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.
Integrating Felgo and QML in existing native apps has many beneficial use cases:
You can find examples of integrating Felgo and QML with existing apps on our Github pages:
First set up your project to enable loading QML content from a native Android application.
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/' }
}
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.
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.
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.
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.
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.
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.
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
First set up your project to enable loading QML content from a native iOS application.
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.
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
.
[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
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.
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.
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:
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
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.
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.
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
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.
Initializes the Felgo runtime from a native Android application |
|
Integrates Felgo in a native Android application |
|
Shows Felgo QML content in a native Android application |
|
Shows Felgo QML content in a native Android application |
|
Initializes the Felgo runtime from a native iOS application |
|
Shows Felgo QML content inside a native iOS application |