NativeObject represents a platform-native object. More...
Import Statement: | import Felgo 4.0 |
Since: | Felgo 3.3.0 |
Inherited By: |
This QML type allows you to interact with native objects on mobile platforms. NativeObject is currently supported on Android and iOS.
A NativeObject wraps an instance of a platform-native object. On Android, this is an instance of Object. On iOS, this is any Objective C id.
You can call methods of the underlying native object with callMethod(). You can also access fields/properties of the object with getProperty() and setProperty().
You can interact with native classes using the derived type NativeClass. It can call static methods and create new object instances. You can obtain a reference to the object's class with getClass(). Similarly, you can access any class by name with NativeObjectUtils::getClass().
NativeObject is intended for advanced usage. Most apps do not need to interact with native objects directly. The most common applications are available in NativeUtils.
This type allows you to directly call any native APIs. These APIs are platform-specific. So make sure to only call them on the correct platform. You can use the Qt global object to find out the currently running platform at runtime:
if(Qt.platform.os === "android") { // android specific code } else if(Qt.platform.os === "ios") { // iOS specific code }
You can also safely call native APIs from within your NativeView platform binding implementations. Use the NativeView::androidBinding property for Android specific code and the NativeView::iosBinding for iOS specific code.
NativeObject is useful to add any native functionality to your apps or games that is not directly supported by Felgo. The following example shows how to get the current battery level on Android and iOS.
A public method handles the platform detection: It uses Qt.platform.os to find out the current platform. It then calls a platform-dependent private method.
The platform-dependent methods can use NativeObjectUtils::getClass() to access native classes. They can create new instances of these classes with NativeClass::newInstance(). They can then call methods of an object instance with callMethod(). Also they can access Java fields and Objective C properties with getProperty() and setProperty().
import Felgo import QtQuick App { AppButton { anchors.centerIn: parent text: qsTr("Check Battery") onClicked: { var batteryPercent = Math.round(getBatteryLevel() * 100) text = "Battery: "+ batteryPercent + "%" } } // returns battery level between 0 and 1 on mobile platforms function getBatteryLevel() { // call platform-dependent implementation: if(Qt.platform.os === "android") { return _.getAndroidBatteryLevel() } else if(Qt.platform.os === "ios") { return _.getIosBatteryLevel() } else { return 0 } } // private methods Item { id: _ function getAndroidBatteryLevel() { // imports and constants: var Intent = NativeObjectUtils.getClass("android/content/Intent") var IntentFilter = NativeObjectUtils.getClass("android/content/IntentFilter") var BatteryManager = NativeObjectUtils.getClass("android/os/BatteryManager") var context = NativeObjectUtils.getContext() // Corresponding Java code (from https://developer.android.com/training/monitoring-device-state/battery-monitoring#CurrentLevel): // IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); // Intent batteryStatus = context.registerReceiver(null, ifilter); // int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); // int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); // return level / (float)scale; var filter = IntentFilter.newInstance(Intent.getStaticProperty("ACTION_BATTERY_CHANGED")) var batteryStatus = context.callMethod("registerReceiver", [null, filter]) var level = batteryStatus.callMethod("getIntExtra", [BatteryManager.getStaticProperty("EXTRA_LEVEL"), -1]) var scale = batteryStatus.callMethod("getIntExtra", [BatteryManager.getStaticProperty("EXTRA_SCALE"), -1]) return level / scale } function getIosBatteryLevel() { // imports: var UIDevice = NativeObjectUtils.getClass("UIDevice") // Corresponding Objective C code: // UIDevice *device = UIDevice.currentDevice; // device.batteryMonitoringEnabled = YES; // return device.batteryLevel; var device = UIDevice.getStaticProperty("currentDevice") device.setProperty("batteryMonitoringEnabled", true) return device.getProperty("batteryLevel") } } }
The methods in NativeObject perform conversion between QML/JavaScript and native object types. They convert parameters, property values and return values automatically.
This table describes which type conversions they perform:
JavaScript / QML | Android | iOS |
---|---|---|
Bool | boolean |
BOOL |
Number | Any primitive number type,java.lang.Number |
Any primitive number type,NSNumber |
String | java.lang.String ,java.lang.CharSequence |
NSString ,SEL |
Array | java.util.List ,T[] |
NSArray |
Object | java.util.Map |
NSDictionary |
function ,map of functions |
any interface type |
any @protocol type |
NativeObject |
java.lang.Object |
NSObject ,id |
null ,undefined |
null |
null ,NSNull |
When you pass an object from QML to a native method/property, you can use it for any of the listed types. For example, a JavaScript array can be used to call a Java method with a java.util.List
parameter. However
it can also be used for a method that accepts a regular Java array.
When you retrieve an object from a native method/property, it is converted to the corresponding JavaScript type. Any object that is not directly supported by a QML type as listed in the table is returned as a new NativeObject instance.
When you interact with native objects, it is often necessary to create objects conforming to Java interfaces
and Objective C protocols
.
On Android for example, to get a click event from a android.widget.Button
, you need an OnClickListener
implementation. The implementation needs to implement the onClick(View view)
method.
You can do this by supplying a JavaScript function. For example, you can use this code to set the Button.onClickListener
:
view.callMethod("setOnClickListener", function(v) { // call QML signal: parent.clicked() })
Note: NativeObject does currently not support returning values from a JavaScript function to a Java interface
method. Any Java interface method will return null,
regardless of what you return from your JavaScript function. It does however support returning a value from JavaScript to an Objective C protocol
method.
You can also create a JavaScript object with keys mapping to functions in place of a Java interface
. This is useful if you need to implement multiple interface methods. Each key in the supplied object corresponds
to a method with that name in the interface. Example:
view.callMethod("setOnClickListener", { "onClick": function(v) { // call QML signal: parent.clicked() } // could add additional interface methods here })
On iOS, you can use the same method to create objects conforming to Objective C protocols. You can use this to create delegate objects and to add target actions.
Native objects in Objective C use manual reference counting to manage their lifetime. Delegate properties usually only store a weak reference without incrementing the reference count.
Thus when obtaining a wrapper for a native protocol, you can store a strong reference manually. Use the NativeObjectUtils::wrap() method for this. It returns a reference that is managed by the QML engine's garbage collector. You can store it in a property for as long as you use it as a delegate for another object.
Example adding a UIScrollViewDelegate
:
Item { property NativeObject scrollView // UIScrollView instance // create wrapper for UIScrollViewDelegate and store strong reference: property NativeObject scrollViewDelegate: NativeObjectUtils.wrap({ "scrollViewWillBeginDragging:": function(scrollView) { console.log("begin dragging") }, // ...other delegate methods here }) function initScrollView() { // ...obtain scrollView instance scrollView.setProperty("delegate", scrollViewDelegate) } }
In Objective C, protocol methods have defined method signatures. When you add a method in such a protocol implementation, you
can specify the method signature before the method name. You can omit the method signature if all parameters and the return value are of object type (id
or pointer to NSObject
types).
Example adding a UIScrollViewDelegate
with methods that use non-object parameters:
Item { property NativeObject scrollView // UIScrollView instance // create wrapper for UIScrollViewDelegate and store strong reference: property NativeObject scrollViewDelegate: NativeObjectUtils.wrap({ // method signature can be omitted - only object parameters and return type "scrollViewWillBeginDragging:": function(scrollView) { console.log("begin dragging") }, // manual method signature required because of non-object parameter bool decelerate "v@:@B scrollViewDidEndDragging:willDecelerate:": function(scrollView, decelerate) { console.log("end dragging", decelerate) }, "scrollViewDidEndDecelerating:": function(scrollView) { console.log("end decelerating") } }) function initScrollView() { // ...obtain scrollView instance scrollView.setProperty("delegate", scrollViewDelegate) } }
Represents a platform-native class |
|
Represents a platform-native object |
|
Allows you to interact with objects native to the mobile platform |
|
Allows to instantiate and display platform-specific views and widgets |
|
Defines the platform specifics for NativeView |
var callMethod(string methodName, var parameters, enumeration threadType, function resultHandler) |
Calls the method methodName
on the native object represented by this item.
On Android, it considers all overloads of this method. It converts the supplied parameters according to Data Type Conversions between QML and Native Code. If any overload fits the converted parameters, it calls that overload.
On iOS, the methodName
is the full selector of the method you want to call, including the colons. Example: "addTarget:action:forControlEvents:"
for UIButton
actions.
You can supply parameters to the method call with the optional parameter parameters
. It can be either a single parameter object or a JavaScript array of parameters.
You can specify which thread to call the method on with the optional parameter threadType
. Use one of these enumeration values with it:
NativeObject.CurrentThread
- Calls the method directly on the QML thread.NativeObject.UiThread
- Calls the method in the platform's native UI thread.
Note: When calling methods of View objects, this thread type should usually be preferred.
Note: On iOS, QML applications run directly on the UI thread. This means, CurrentThread
and UiThread
will result in the same behavior.
NativeObject.BackgroundThread
- Calls the method asynchronously in a background thread.You can use the optional parameter resultHandler
to obtain the method return value asynchronously.
You can supply a JavaScript function for resultHandler
. callMethod()
then immediately returns an undefined value. It then calls the resultHandler
function after the method call has
finished. It supplies the method return value as first parameter to the function.
You can also omit resultHandler
. In this case, callMethod()
returns the method return value directly. If the call is executed on another thread, this means the QML thread will be blocked during
that time.
See also NativeClass::callStaticMethod().
NativeClass getClass() |
Returns a NativeClass object representing this object's class.
This is equivalent to calling object.getClass()
on Android and [object class]
on iOS.
See also NativeObjectUtils::getClass().
Get the property propertyName
from the native object represented by this item.
On Android, this reads a field in the native object's class. If no field with this name exists or the field is not public, it logs a warning message and returns an undefined value.
On iOS, this reads an Objective C property in the native object's class. If no property with this name exists, it logs a warning message and returns an undefined value.
See also setProperty and NativeClass::setStaticProperty().
Set the property propertyName
from the native object represented by this item to value
.
On Android, this sets a field in the native object's class. If no field with this name exists or the field is not public, it logs a warning message and does nothing.
On iOS, this sets an Objective C property in the native object's class. If no property with this name exists, it logs a warning message and does nothing.
See also getProperty and NativeClass::getStaticProperty().