Using Extensions or Cordova Plugins in your RhoMobile Application Darryn Campbell @darryncampbell Application Architect
Agenda Creating a Rho Native Extension on Android Converting a Cordova Plugin to a Rho Native Extension Questions
Creating a Rho Native Extension on Android
Creating a Native Extension - Overview What a Native Extension IS: Exposes native code through either JavaScript or Ruby What a Native Extension is NOT: Easier to create than a native app Ask high level questions: Why are you creating a native extension? Would it make more sense to create a native application rather than use Rho? What platforms does your native extension need to work on? The fewer platforms you need to support, the less your need for a cross platform framework. Treat native extension development like any other software project: Gather requirements Design your API Implement Debug / Test These steps can be quite painful with the current version(s) of Rho and we would like to improve in the future
Creating a Native Extension Pre-Requisites: RhoMobile Suite installed (I m using RMS 5.1) Android SDK installed (I m using API level 22 to avoid the compatibility issue with level 23 and RMS 5.1) Android NDK (I m using r9d) Rhobuild.yml configured appropriately Worked Example: A native extension to expose the Android Light Sensor to a Rho application API will consist of two methods to start or stop listening for updates from the sensor API will expose a property of how frequently to request updates from the sensor API will pre-define constants for FAST and NORMAL update speed Doing it Native: What does the Native code look like? Great example we can just copy / paste at https://developer.android.com/guide/topics/sensors/sensors_overview.html See next slide
Creating a Native App Light Sensor public class SensorActivity extends Activity implements SensorEventListener { private SensorManager msensormanager; private Sensor mlight; } @Override public final void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); } msensormanager = (SensorManager) getsystemservice(context.sensor_service); mlight = msensormanager.getdefaultsensor(sensor.type_light); @Override public final void onaccuracychanged(sensor sensor, int accuracy) { // Do something here if sensor accuracy changes. } @Override public final void onsensorchanged(sensorevent event) { // The light sensor returns a single value. // Many sensors return 3 values, one for each axis. float lux = event.values[0]; // Do something with this sensor value. } @Override protected void onresume() { super.onresume(); msensormanager.registerlistener(this, mlight, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onpause() { super.onpause(); msensormanager.unregisterlistener(this); }
Creating a Native App Light Sensor DEMO Light Sensor Native Application
Creating a Native Extension Light Sensor Step 1: Create a Rho application into which your native extension will be placed >rhoelements app appforum-example Cd into your application >cd appforum-example Create the extension >Rhodes extension lightsensor Design the API: Open generated /extensions/lightsensor/ext/lightsensor.xml Modify your xml API definition Add the methods, constants and properties we previously described More detail available in the help docs at http://docs.rhomobile.com/en/5.1.1/guide/native_extensions#overview-of-the-apidescriptor-xml-file
Creating a Native Extension Light Sensor CD to the directory that contains your XML >cd extensions/lightsensor/ext Regenerate the code based on your updated XML >rhogen api Lightsensor.xml Add your new extension to your build.xml Extensions: - lightsensor Open the native API implementation & observe the structure >(your favourite editor) /platform/android/src/com/rho/lightsensor Since we have specified DEFAULT_INSTANCE in our API template we have a factory and singleton classes created for us. We don t need to modify the LightsensorFactory.java or LightsensorSingleton.java as we re only concerned with a single Light Sensor. This is best practice with hardware APIs like scanners where the device can have multiple scanners
Creating a Native Extension Light Sensor Modify Lightsensor.java to @Override the methods you defined in your XML as well as property accessors. Make any additional updates as required, i.e. in this case we need to implement SensorEventListener
Creating a Native Extension Light Sensor Test it You MUST perform a clean build prior to testing the public interface: >rake clean:android >rake device:android:production Takes ~ 10 minutes
Creating a Native Extension Light Sensor Test it with a bit more pizzaz
Creating a Native Extension Light Sensor Test it with a bit more pizzaz
Creating a Native Extension Light Sensor DEMO A Light Sensor Native Extension
Creating a Native Extension Light Sensor But wait what if it doesn t work first time?? It is not possible to load your native extension in eclipse and build from there as Rhodes build scripts are rake based rather than ant or gradle The only way to debug what is going on is to use logcat and logging Import android.util.log Log.d( Light Sensor, Why isn t this darn thing working? ); Try a clean build: >rake clean:android We are continually looking at ways to improve our developer experience
Converting a Cordova Plugin to a Rho Native Extension
Converting a Cordova Plugin What are we doing here? There are currently hundreds if not thousands of Cordova plugins available for Phonegap / Ionic / Cordova projects. Wouldn t it be great if you could use them in your Rho application with minimal fuss and bother? Good news! You can, sort of whilst technically possible this is an advanced topic so be warned.
Converting a Cordova Plugin - Walkthrough For this example we have the official Zxing scanner for cordova: https://github.com/phonegap/phonegapplugin-barcodescanner Not associated with Zebra technologies I m showing this example on Android since that is the main Zebra platform Clone the Repo (phonegap-plugin-barcodescanner) >git clone https://github.com/phonegap/phonegap-plugin-barcodescanner.git Familiarize yourself with the plugin and github repo: The npm page with duplicate documentation: https://www.npmjs.com/package/phonegap-plugin-barcodescanner The JavaScript interface exposed by the plugin: /www/barcodescanner.js Source code: src/android/com/phonegap/plugins/barcodescanner Jar file: src/android/com.google.zxing.client.android.captureactivity.jar Android resources associated with plugin e.g. view: src/android/libraryproject/res The Cordova plugin configuration file: /plugin.xml
Cordova Plugin XML - Walkthrough
Cordova Plugin XML
Cordova Plugin XML
Cordova Plugin XML
Cordova Plugin XML
Cordova Plugin XML
Cordova Plugin XML
Cordova Plugin XML
Prepare your Rho Native Extension Design an API for your native Extension We ll call ours cordovabarcode You will not be able to map the API 1:1 with the Cordova plugin as Rho does not support multiple callbacks in the same method: E.g. Where the Cordova plugin uses: BarcodeScanner.prototype.scan = function (successcallback, errorcallback, config) { } We will use: Rho.CordovaScanner.scan(propertyMap, callback); Example call: Rho.CordovaScanner.scan({}, function(scanneddata) {alert(scanneddata);});
Prepare your Rho Native Extension Create the native extension for cordova barcode and define the XML as previously explained: >rhodes extension cordovabarcode (Create the XML for the Cordova Barcode interface) Re-Generate the files that depend on the XML structure >cd extensions/lightsensor/ext >rhogen api Cordovabarcode.xml Add your new extension to your build.xml extensions: - lightsensor - cordovabarcode Perform a clean build to ensure all changes are picked up >rake clean:android >rake device:android:production
A Closer look at our defined interface Methods: Enumerate Scan From the generator, keep this here for best Rho practise with hardware APIs Just to keep things simple we ll only expose the Scan API and ignore Encode Takes a property map, a JSON object or Ruby hash defining the scanner configuration Takes a single callback. For simplicity s sake we will assume the scan is always successful and returns some scanned data as a String <METHODS> <METHOD name="enumerate" access="static" hascallback="optional"> </METHOD> <METHOD name="scan" hascallback="mandatory"> <DESC>Start listening for Light sensor changes</desc> <PARAMS><PARAM name="propertymap" type="hash"> <DESC>Some description</desc> </PARAM> </PARAMS> <CALLBACK type="hash"> <DESC>The light sensor value</desc> <PARAMS><PARAM name="data" type="float"> <DESC>The scanned barcode data</desc> </PARAM> </PARAMS> </CALLBACK> </METHOD></METHODS>
Update your Rho Native Extension with the Cordova Plugin logic Update build.yml: Add your extension Ensure no existing extensions interfere with your new plugin, i.e. Rho already has an implementation of the Zxing extension and Android will not like it if you try and include it twice. Comment out app_type: rhoelelements to ensure the Barcode API is not included
Update your Rho Native Extension with the Cordova Plugin logic Add new Java files to the list of required java files at /extensions/cordovascan ner/ext/platform/androi d/ext_java.files In this case there is only one, BarcodeScanner.java
Update your Rho Native Extension with the Cordova Plugin logic Copy the resources from the Cordova Plugin into the Rhodes Native Extension: copy phonegap-plugin-barcodescanner/src/android/libraryproject/res/* to extensions/cordovascanner/ext/platform/android/additional_files/res/* You will need to create the additional_files directory
Update your Rho Native Extension with the Cordova Plugin logic Work around any resource conflicts: The build process will not like two resource files with the same name. Rename /extensions/lightsensor/ext/platform/android/additional_files/res/values/strings.xml to strings2.xml The build process will not like two resources with the same name. Comment our the app_name string from strings2.xml. We already have an app_name generated automatically from the name you specify in your build.yml file.
Update your Rho Native Extension with the Cordova Plugin logic Copy the lib files from the Cordova Plugin into the Rhodes Native Extension: copy phonegap-plugin-barcodescanner/src/android/com.google.zxing.client.android.captureactivity.jar to extensions/cordovascanner/ext/platform/android/libs/com.google.zxing.client.android.captureactivity.jar You will need to create the libs directory
Update your Rho Native Extension with the Cordova Plugin logic Tell the Rhodes extension which changes are required to the Android Manifest Create an empty manifest file named AndroidManifest.xml under /extensions/cordovascanner/ext/platform/android/androidmanifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.rhomobile.rhodes" android:installlocation="auto" android:versioncode="29" android:versionname="2.3.3"> </manifest> Between the <manifest></manifest> tags add the sections from the Cordova Plugin s plugin.xml that relate to the Android Manifest (see next slide)
Update your Rho Native Extension with the Cordova Plugin logic
Update your Rho Native Extension with the Cordova Plugin logic
Update your Rho Native Extension with the Cordova Plugin logic Update your extension s rake file to ensure the.jar file is included in the build:
Update your Rho Native Extension with the Cordova Plugin logic Update your extension s rake file to ensure the.jar file is included in the build:
Update your Rho Native Extension with the Cordova Plugin logic Update your extension s rake file to ensure the.jar file is included in the build:
Update your Rho Native Extension with the Cordova Plugin logic Update your extension s ext.yml: \extensions\cordovascanner\ext.yml Add definition of the changes we require to the Android Manifest: Manifest_changes: ext/platform/android/androidmanifest.xml Tell Rhodes we are adding additional resources associated with our Extension Adds: ext/platform/android/additional_files Tell Rhodes to listen for incoming intents to the CordovaScannerFactory class Rhodes_listener: com.rho.cordovabarcode.cordovabarcodefactory
Update your Rho Native Extension with the Cordova Plugin logic Modify the Cordova plugin code to work within the Rho framework We only have one non-template Java file, BarcodeScanner.java We will be modifying one of the template files to act as a receiver for the scan intent, CordovabarcodeFactory.java We will be modifying the template Cordovabarcode.java to pass the activity result back to the BarcodeScanner class
Update your Rho Native Extension with the Cordova Plugin logic Changes to CordovabarcodeFactory.java Implement IRhoListener interface Stub all methods required by IRhoListener interface: oncreateapplication, oncreate, onstart, onresume, onpause, onstop, ondestroy, onnewintent, oncreatedialog, onconfigurationchanged, onkey, onsaveinstancestate, oneblicensevisible, oneblicensehidden, oneblicensedestroyed Implement onactivityresult, inherited from IRhoListener. This receives the scan data from the Zxing activity Our implementation sends the result back to the BarcodeScanner.java class
Changes to CordovaBarcodeFactory
Update your Rho Native Extension with the Cordova Plugin logic Changes to Cordovabarcode.java Create BarcodeScanner object for each scan (arguments are not processed for brevity) Add onactivityresult method that passes the activity result back to BarcodeScanner.java
Update your Rho Native Extension with the Cordova Plugin logic Changes to BarcodeScanner.java No longer extends CordovaPlugin Need to use Rhodes IMethodResult to return data to the user rather than Cordova s this.callbackcontext.success / failure No longer need the Cordova execute() method which is called in response to the Cordova JavaScript API Transition from this.cordova.getactivity() to RhodesActivity.getInstance() onactivityresult is no longer @Override since we do that in CordovabarcodeFactory
Modifications to BarcodeScanner.java
Modifications to BarcodeScanner.java
Modifications to BarcodeScanner.java
Modifications to BarcodeScanner.java
Modifications to BarcodeScanner.java
Modifications to BarcodeScanner.java
Update your Rho Native Extension with the Cordova Plugin logic DEMO Cordova Barcode in a Rho App
Resources
Resources Templates / Examples Existing open source plugins show a variety of techniques you may wish to use when transitioning your plugin: https://github.com/rhomobile/rhodes/tree/master/lib/commonapi Android Service: Used by ConnectionChecking extension: https://github.com/rhomobile/rhodes/tree/master/lib/commonapi/connectio nchecking/ext/platform/android Using hardware permissions: AudioCapture extension showcases an alternative way of modifying the Android Manifest: https://github.com/rhomobile/rhodes/tree/master/lib/commonapi/audiocaptu re/ext/platform/android
Resources Apps used in this Presentation Native Android application to demonstrate the Light sensor: https://github.com/darryncampbell/lightsensor-native Rho application with just the Light Sensor extension https://github.com/darryncampbell/appforum-rho-lightsensoronly Official Zxing scanner for Cordova: https://github.com/phonegap/phonegap-plugin-barcodescanner Rho application with both the light sensor and Cordova Barcode extensions: https://github.com/darryncampbell/appforum-rho-full
PLEASE TAKE THE SURVEY DO NOT USE APPFORUM EVENT SURVEY SESSION SURVEY
Questions?
THANK YOU