Learn what Felgo offers to help your business succeed. Start your free evaluation today! Felgo for Your Business

Native App Integration: Integrate Felgo and Qt with Existing Android and iOS Applications

With Felgo you can create powerful standalone apps and games for multiple platforms. It is however also possible to integrate Felgo content into existing apps. You can load complete QML files with all Felgo features in Android and iOS apps. This guide explains the necessary steps to integrate QML with existing applications.

Use Cases

Integrating Felgo and QML in existing native apps has many beneficial use cases:

  • Implement parts of your app or game in QML. You can load content created with QML as one or many single screens in your app. This way you can implement your logic with the power of QML while still using the native look-and-feel and navigation concepts of your platform.
  • Show QML content as sub-views inside other screens. You can leverage the simplicity of QML for smaller parts of your app or game's UI.
  • Load a complete Felgo-powered app or game from the platform's IDE. You can skip installing the Qt Creator IDE and just implement a Felgo application using Android Studio or Xcode.

Example Applications

You can find examples of integrating Felgo and QML with existing apps on our Github pages:

Android

Project Setup

First set up your project to enable loading QML content from a native Android application.

Felgo Dependency

Add the felgo-android dependency in your build.gradle file:

 dependencies {
   implementation 'com.felgo:felgo-android:3.+'
 }

Also add the Felgo Maven repository at the repositories block:

 repositories {
   maven { url 'https://github.com/FelgoSDK/FelgoAndroid/raw/master/maven/' }
 }

Activity Base Class

It's easiest to integrate QML content in your Android application by using an Activity base class. Extend an Activity where you would like to show QML content from FelgoAndroidActivity:

 import com.felgo.ui.FelgoAndroidActivity;

 public class MyQmlActivity extends FelgoAndroidActivity {

   @Override
   public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     // more Activity setup
   }
 }

Use a regular Activity or any other base type for Activities that do not show QML content.

Note: FelgoAndroidActivity simplifies QML integration but is not required. To use other Activity base types, e.g. AppCompatActivity, forward its lifecycle methods to FelgoAndroid.

Add QML Files to Your Project

You can load QML files from anywhere. All you need is the text content of the QML file. This lets you even load QML files from the web at runtime.

The most common use case is loading QML files from your project assets. To do so, place your .qml files under your projects assets directory (usually <project-dir>/src/main/assets). You can also use subfolders inside assets and reference files relatively from within QML.

Note: Use App or GameWindow as the root type for showing QML content.

Load QML Content

You can load any QML content using the class FelgoAndroidView or FelgoAndroidFragment. You can add an instance in code or in a layout XML file.

Using a Layout XML File

You can add FelgoAndroidView to any layout .xml file:

 <com.felgo.ui.FelgoAndroidView
     android:id="@+id/felgo_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     app:qml_source="qml/Main.qml"/>

This loads the file qml/Main.qml from your project assets.

Programmatically

You can also add a FelgoAndroidView to an Activity at runtime:

 void loadQml() {
   ViewGroup container = this.findViewById(R.id.felgo_container);
   try {
     container.addView(new FelgoAndroidView(this)
             .setQmlSource(getApplicationContext(), "qml/Main.qml")
     );
   } catch (IOException ex) {
     // QML file not found
     Log.w("MainActivity", "Could not load QML file", ex);
   }
 }

Here R.id.felgo_container is the ID of an existing ViewGroup to place the new View into. This loads the file qml/Main.qml from your project assets. You can also load content from other places.

Use the method setQmlSource(Context context, var source) to load QML from a local file. The source parameter can be any file:// URI. In this case, relative resource lookup within QML starts at the source file's directory. To load a file from your app's assets, use a String with the asset file path. For example, a call like setQmlSource(context, "qml/Main.qml").

Use the method setQmlContent(String qmlContent, String qmlBaseUrl) to load QML content directly from a source string. The parameter qmlBaseUrl is an optional virtual URL for relative resource lookup within QML. For example, you can use file:///android_asset/qml/Main.qml as base URL. This lets you use lookup e.g. "../images/image.png" from within QML. Which would result in the image being loaded from your app's assets/images folder.

Note: It is also possible to show QML content in an Android Fragment. Use the FelgoAndroidFragment for this use-case.

Interact with QML

You can interact with the QML application directly from native code. FelgoAndroidView provides methods for this. You can read and write properties on the QML root item with setQmlProperty() and getQmlProperty(). You can call a JavaScript function on the root item with callQmlMethod(). You can react to QML signals with addSignalHandler().

Note: On Android, the QML application runs on a thread separate from the Android UI thread. Thus setting QML properties and calling QML methods happens asynchronously. Also, signal handlers are not invoked on the UI thread. To interact with native UI from signal handlers, you can use Activity.runOnUiThread().

You can use these methods after loading a QML file with either setQmlSource() or setQmlContent(). The QML scene is loaded asynchronously. You can react to the QML file being loaded completely from your native app. Either override FelgoAndroidActivity::onQmlInitialized() or use FelgoAndroidFragment::setQmlInitializedListener(). The callbacks are invoked on the Android UI thread.

Example

The following example shows how to set up interaction between Java and QML:

assets/qml/Main.qml

 import Felgo
 import QtQuick

 App {
     property string qmlText: ""

     signal btnPressed

     Column {
         AppText {
             text: qmlText
         }

         AppButton {
             text: "Click me!"
             onClicked: btnPressed()
         }
     }
 }

MainActivity.java

 package com.felgo.nativeintegrationexample;

 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.v7.widget.Toolbar;
 import android.util.Log;

 import com.felgo.ui.FelgoAndroidActivity;
 import com.felgo.ui.FelgoAndroidView;

 import org.qtproject.qt5.android.bindings.QtFragment;

 import java.io.IOException;

 public class MainActivity extends FelgoAndroidActivity {

   private FelgoAndroidView m_felgo;

   @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);

     m_felgo = new FelgoAndroidView(this);

     // show QML fragment and load assets/qml/Main.qml:
     try {
       m_felgo.setQmlSource(getApplicationContext(), "qml/Main.qml");
     } catch (IOException ex) {
       // qml file not found
       Log.w("MainActivity", "Could not load QML file", ex);
     }

     ViewGroup container = this.findViewById(R.id.felgo_container);
     container.addView(m_felgo);
   }

   @Override
   public void onQmlInitialized() {
     m_felgo.setQmlProperty("qmlText", "Hello QML from Java!");

     m_felgo.addSignalHandler("btnPressed", new QtFragment.QmlSignalHandler() {
       @Override
       public void onSignalEmitted(Object[] signalParameters) {
         Log.d("MainActivity", "QML button pressed!");
       }
     });
   }
 }

You can find more examples on how to integrate Felgo with native Android implementations here: https://github.com/FelgoSDK/Felgo-Add-To-App-Examples

iOS

Project Setup

First set up your project to enable loading QML content from a native iOS application.

Initialize CocoaPods

You can add the Felgo dependency to an existing Xcode project using CocoaPods. If you have not yet used CocoaPods, you can install it with RubyGems from terminal:

 $ sudo gem install cocoapods

If your project does not yet use CocoaPods, you can add it via terminal. Execute the following command in your Xcode project root:

 $ pod init

This creates a file named Podfile in the same directory.

Felgo Dependency

Add the FelgoIOS dependency in your Podfile:

 target 'MyIOSApp' do
   # more dependencies

   pod 'FelgoIOS', :git => 'https://github.com/FelgoSDK/FelgoIOS.git'
 end

Afterwards, update CocoaPods dependencies:

 $ pod install

This generates a file called <project-name>.xcworkspace. To use CocoaPods, open this file in Xcode instead of the <project-name>.xcodeproj.

Initialize the Felgo Runtime

[FelgoIOS sharedInstance] contains the Felgo iOS runtime. Start it before using any QML content. For this, call [FelgoIOS start]. You can do this, for example, in your AppDelegate's didFinishLaunchingWithOptions method. When your app terminates, you can quit the Felgo Runtime again with [FelgoIOS quit].

 #import "FelgoIOS.h"

 @implementation AppDelegate

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

   // other code ...

   [[FelgoIOS sharedInstance] start];

   return YES;
 }

 - (void)applicationWillTerminate:(UIApplication *)application {

   // other code ...

   [[FelgoIOS sharedInstance] quit];
 }

 @end

Add QML Files to Your Project

You can load QML files from anywhere. All you need a URI to the QML file. This lets you even load QML files from the web at runtime.

The most common use case is loading QML files from your project resources. To do so, add your .qml files to your project resources in Xcode. You can also use subfolders inside resources and reference files relatively from within QML.

Add Felgo View

You can display QML content using the class FelgoIOSView. You can add an instance of the view in code or in an interface builder file.

Using Interface Builder

You can add FelgoIOSView using the Xcode Interface Builder. Add an empty View to your interface and set the custom class to FelgoIOSView:

To access the view from source code, add an IBOutlet property to your ViewController implementation:

 #import "FelgoIOSView.h"

 @interface ViewController

 @property (weak, nonatomic) IBOutlet FelgoIOSView *felgoView;

 @end

You can then add a referencing outlet by right-clicking the view in Interface Builder:

Programmatically

You can also add FelgoIOSView to another view in code. Example from within a ViewController implementation:

 #import "FelgoIOSView.h"

 @interface ViewController()

 @property (strong, nonatomic) FelgoIOSView *felgoView;

 @end

 @implementation ViewController

 // more methods...

 - (void)addQMLView {
   self.felgoView = [FelgoIOSView new];
   self.felgoView.frame = self.view.bounds;
   [self.view addSubview:self.felgoView];
 }

 @end

Load QML Content

To load QML content, assign a URI to the property FelgoIOSView::qmlSource. You can use any URI, for example to a web resource, a local file or a project resource.

This example loads Main.qml from your project resources:

 - (void)loadQML {
   self.felgoView.qmlSource = [[NSBundle mainBundle] URLForResource:@"Main" withExtension:@"qml"];
 }

You can also load QML directly from an NSData or NSString object. For this, assign to the property FelgoIOSView::qmlContent:

 - (void)loadQML {
   // obtain QML content from anywhere...
   NSString *content = @"import Felgo; App { AppText { text: 'Direct QML content' } }";

   self.felgoView.qmlContent = [content dataUsingEncoding:NSUTF8StringEncoding];
 }

Note: Using FelgoIOSView::qmlSource allows for relative resource lookup within QML. In the above example, relative resource lookup within QML starts at the FelgoIOSView::qmlSource file's directory. This is not possible when using QML content directly with FelgoIOSView::qmlContent.

Interact with QML

You can interact with the QML application directly from native code. FelgoIOSView provides methods for this. You can read and write properties on the QML root item with [FelgoIOSView setQmlProperty:value:] and [FelgoIOSView getQmlProperty:. You can call a JavaScript function on the root item with [FelgoIOSView callQmlMethod:value:]. You can react to QML signals with [FelgoIOSView addSignalHandler:handler:].

Note: On iOS, the QML application runs on the main iOS UI thread. Thus setting QML properties and calling QML methods happens synchronously.

You can use these methods after loading a QML file with either FelgoIOSView::qmlSource or FelgoIOSView::qmlContent. The QML scene is loaded asynchronously. You can react to the QML file being loaded completely with the property FelgoIOSView::qmlInitBlock.

Example

The following example shows how to set up interaction between Objective C and QML:

assets/qml/Main.qml

 import Felgo
 import QtQuick

 App {
     property string qmlText: ""

     signal btnPressed

     Column {
         AppText {
             text: qmlText
         }

         AppButton {
             text: "Click me!"
             onClicked: btnPressed()
         }
     }
 }

ViewController.mm

 #import "ViewController.h"

 #import "FelgoIOSView.h"

 @interface ViewController ()

 @property (strong, nonatomic) FelgoIOSView *felgoView;

 @end

 @implementation ViewController

 - (void)viewDidLoad {
   [super viewDidLoad];

   self.felgoView = [FelgoIOSView new];
   self.felgoView.frame = self.view.bounds;
   [self.view addSubview:self.felgoView];

   QMLSignalHandler btnHandler = ^(NSArray * _Nonnull signalParameters) {
     NSLog(@"QML button pressed!");
   };

   self.felgoView.qmlInitBlock = ^{
     [self.felgoView setQmlProperty:@"qmlText" value:@"Hello QML from Objective C!"];

     [self.felgoView addSignalHandler:@"btnPressed" handler:btnHandler];
   };

   // Load QML file from project resources:
   self.felgoView.qmlSource = [[NSBundle mainBundle] URLForResource:@"Main" withExtension:@"qml" subdirectory:@"qml"];
 }

 @end

You can find more examples on how to integrate Felgo with native iOS implementations here: https://github.com/FelgoSDK/Felgo-Add-To-App-Examples

Available Native Types

These types allow you to load QML content from a native application. They are available from Java/Kotlin on Android and from Objective C/Swift on iOS.

FelgoAndroid

Initializes the Felgo runtime from a native Android application

FelgoAndroidActivity

Integrates Felgo in a native Android application

FelgoAndroidFragment

Shows Felgo QML content in a native Android application

FelgoAndroidView

Shows Felgo QML content in a native Android application

FelgoIOS

Initializes the Felgo runtime from a native iOS application

FelgoIOSView

Shows Felgo QML content inside a native iOS application

Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded