DeviceAPI is a solution that allows developers to apply device-specific features to Nexacro Platform applications. Developers can expand features of mobile platforms (eg. iOS and Android) through DeviceAPI.
DeviceAPI is largely devided into two segments: one is native modules developed in mobile platforms and the other is JavaScript interfaces designed to apply native modules to Nexacro Platform projects.
This chapter will explain how to develop and apply DeviceAPI through simple examples where text strings are entered and displayed.
Native Module
Developing iOS native module
This section will explain how to develop an iOS native module by using Xcode. The provided DeviceAPI class file will be inherited for the development.
The below test environments were used when the example was developed.
OS: OSX 10.9.3 Xcode: Version 5.1.1 Device: iPad Mini (iOS 7.1)
Creating a project
Launch Xcode and create a project by accessing the below menu.
File > New > Project
Select 'Cocoa Touch static Library' as a basic template.
Fill in necessary options including Product Name (HelloPlugin) to finish creating a project.
Project settings
After the creation, select the 'HelloPlugin' project, go to Build Phases, and add the below three frameworks.
nexacro14.framework UIKit.framework Foundation.framework
Modifying the source file
Make modifications as below on the HelloPlugin.h header file and HelloPlugin.m source file, which were automatically generated.
// HelloPlugin.h #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> #import <nexacro14/DeviceAPI.h> @interface HelloPlugin : DeviceAPI { NSInteger nID; NSString *helloMsg; } @property (nonatomic) NSInteger nID; @property (nonatomic, retain) NSString * helloMsg; - (void)hello:(NSString*)lid withDict:(NSMutableDictionary*)options; @end
A format specifer alert, as shown in the Line 19 in the above script, can occur if the application building is conducted under the 64-bit environment. Therefore, change self.nID to (int)self.nID, as described the below source, under the the 64-bit environment.
// HelloPlugin.m #import "HelloPlugin.h" @implementation HelloPlugin @synthesize nID, helloMsg; //hello Method - (void)hello:(NSString*)lid withDict:(NSMutableDictionary*)options { self.helloMsg = [options objectForKey:@"helloMsg"]; self.nID = [lid integerValue]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:self.helloMsg delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [alert show]; //Event NSString *callbackResult = [NSString stringWithFormat:@"runCallback(\"%d\",\"_onhello\",{'eventid':\"onhello\",'msg':\"%@\"});", self.nID, self.helloMsg]; //64bit build /* NSString *callbackResult = [NSString stringWithFormat:@"runCallback(\"%ld\",\"_onhello\",{'eventid':\"onhello\",'msg':\"%@\"});", (int)self.nID, self.helloMsg]; */ [self writeJavascript:callbackResult]; } @end
Build
After the build in Xcode, you can see the libHelloPlugin.a file generated in the Products folder. You can find the same file in Finder.
Adding libHelloPlugin.a to an application project
Add the libHelloPlugin.a file to an application project while also adding existing frameworks. The below picture shows the result of adding the libHelloPlugin.a file to the application project named "NX14."
Please refer to the chapter "App Development and Execution (iOS)" in Nexacro Platform 14/Administrator Guide for the details on the development of an iOS project.
When you use a simulator for testing, there is no need for authentication. However, an additional setting is required to connect to an actual device.
Set the Code Signing Identity property in Code Signing with an appropriate profile.
[Administrator Guide > App Development and Execution (iOS) > Code Singing]
Developing Android native module
This section will explain how to develop an Android native module by using Eclipse. The NexacroPlugin class will be inherited for the development.
The below test environments were used when the example was developed.
JDK(Java SE Development Kit) Eclipse Android SDK ADT plugin Device: Optimus G (Android 4.4.2)
Creating a project
Launch Eclipse and create a project by accessing the below menu.
File > New > Android Application Project
Enter 'HelloPlugin' as a name for the new project and finish the creation.
For Android 4.4 (Kitkat) or later SDK the appcompat_v7 project is automatically created for downward compatibility if the Minimum Required SDK is set below 3.2 (Honeycomb). Refer to
http://developer.android.com/tools/support-library/features.html.
However, this setting does not have any effect when you create Nexacro Platform applications. Therefore, it is not recommended to create the project. To deal with this situation, you can set the Minimum required SDK to 4.0(IceCreamSandwich) and create a project. You can then designate a downward version as you want when setting AndroidManifest.xml.
Create the HelloPlugin.java file and you can see the structure illustrated in the below picture.
Modifying the source file
Modify the generated HelloPlugin.java file as seen in the below script. Create the HelloPlugin module and input messages into params. Then, those messages will be displayed in the form of an Android toast.
package com.example.helloplugin; import org.json.JSONException; import org.json.JSONObject; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.widget.Toast; import com.nexacro.Native; import com.nexacro.plugin.NexacroPlugin; import com.nexacro.plugin.NexacroPluginManager; import com.nexacro.util.Log; public class HelloPlugin extends NexacroPlugin { private static String LOG_TAG = "HelloPlugin"; private static HelloPlugin helloplugin = null; public HelloPlugin(String objectId) { super(objectId); // TODO Auto-generated constructor stub } @Override public void init(JSONObject paramObject) { // TODO Auto-generated method stub } @Override public void release(JSONObject paramObject) { // TODO Auto-generated method stub } @Override //To save the text string of 'helloMsg' if there is the hello method public void execute(String method, JSONObject paramObject) { // TODO Auto-generated method stub Log.w(LOG_TAG, "execute paramObject:" + paramObject.toString()); if (method.equals("hello")) { String msg = ""; try { JSONObject params = paramObject.getJSONObject("params"); msg = params.getString("helloMsg"); // repeatcount } catch (JSONException e) { e.printStackTrace(); } show(msg); } } //To show the variable of the excute() method in the form of an Android toast public void show(String message) { final String msg = message; new Thread(new Runnable() { @Override public void run() { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { Toast.makeText( NexacroPluginManager.getInstance() .getActivity(), msg, Toast.LENGTH_LONG) .show(); } }); } }).start(); Native.SendDeviceEvent(getObjectId(), "_onhello", "{}"); } }
Creating a JAR file
Create a JAR file that will be used as a plug-in
Right-click the HelloPlugin project and select Export from the pop-up menu.
Access [Java > JAR file] in the Export window.
Check only the 'src' folder of the HelloPlugin project in the JAR Export window while leaving other folders unselected.
Adding the JAR file to an application project
Create the Plugin.xml file in the 'xml' folder of the application project. Designate a name and class in order to use the Android native module developed earlier.
<?xml version="1.0" encoding="utf-8"?> <plugin-config> <plugin name="HelloPlugin" class="com.example.helloplugin.HelloPlugin"/> </plugin-config>
Drag the libhelloplugin.jar file and drop on the 'libs' folder.
Please refer to the chapter "App Development and Execution (Android)" in Nexacro Platform 14/Administrator Guide for the details on the development of an Android project.
JavaScript Interface Development
Write the script of the Hello.js file, a JavaScript interface designed to call the nexacro.Hello user component to Nexacro Studio. The _pHello.hello function in this example is a code that actually executes the user-defined device API.
The JavaScript interface is composed of the following three sections.
A function to be called when an object is constructed
A function to be called when an object is destroyed
A function to execute a user-defined device API
//Hello.js if (!nexacro.Hello) { nexacro.Hello = function(name, obj) { this._id = nexacro.Device.makeID(); nexacro.Device._userCreatedObj[this._id] = this; this.name = name || ""; this.enableevent = true; this._event_list = { "onhello": 1 }; var params = '""'; var jsonstr = '{"id":' + this._id + ', "div":"HelloPlugin","method":"constructor", "params":' + params + '}'; nexacro.Device.exec(jsonstr); }; var _pHello = nexacro.Hello.prototype = nexacro._createPrototype(nexacro.EventSinkObject, nexacro.Hello); _pHello._type_name = "Hello"; _pHello.destroy = function () { var params = '""'; var jsonstr; delete nexacro.Device._userCreatedObj[this._id]; jsonstr = '{"id":' + this._id + ', "div":"HelloPlugin", "method":"destroy", "params":' + params + '}'; nexacro.Device.exec(jsonstr); return true; }; _pHello.on_created = function () { }; //=============================================================== // nexacro.Hello : Methods //=============================================================== _pHello.hello = function(strHelloMsg) { var msg = strHelloMsg; var params = '{"helloMsg":"' + msg + '"}'; var jsonstr = '{"id":' + this._id + ', "div":"HelloPlugin", "method":"hello", "params":' + params + '}'; nexacro.Device.exec(jsonstr); }; //=============================================================== // nexacro.Hello : Event //=============================================================== _pHello._onhello = function(objData) { var e = new nexacro.HelloEventInfo(objData.eventid, objData.msg); this._fire_onhello(this, e); }; _pHello._fire_onhello = function(objHello, eHelloEventInfo) { if (this.onhello && this.onhello._has_handlers) { return this.onhello._fireEvent(this, eHelloEventInfo); } return true; }; //=============================================================== //nexacro.HelloEventInfo //=============================================================== nexacro.HelloEventInfo = function(strEventId, strMsg) { this.eventid = strEventId; this.msg = strMsg; }; var _pHelloEvnetInfo = nexacro._createPrototype(nexacro.Event, nexacro.HelloEventInfo); nexacro.HelloEventInfo.prototype = _pHelloEvnetInfo; _pHelloEvnetInfo._type_name = "HelloEventInfo"; delete _pHelloEvnetInfo; delete _pHello; }
Basically, the constructor and destroy methods are used to construct and destroy an object to execute a device API (Such an object is written in Java or Objective-C).
At this moment, however, those two methods cannot convey their parameters due to the difference in device APIs between Android and iOS. Therefore, you should define user methods.
Application of User Component to Nexacro Platform Project
Develop a user component and apply it to a Nexacro Platform project in order to apply the JavaScript interface developed earlier. This section touches upon the brief explanation about how to develop a user component and how to use it in a Nexacro Platform project.
User component
Developing a user component
The files used in this example were written not to develop a certain feature but to help your understanding. The below four files were utilized.
Module file (*.json)
ExtDeviceAPI.json
Object information file (*.info)
Hello.info
HelloEnum.info
Component script file (*.js)
Hello.js
The module and script files must be situated under the 'component' folder on the Base Lib Path designated in Nexacro Studio.
The default Base Lib Path is the nexacro14lib folder, which is placed on the installation path of Nexacro Platform. You can change the base path by accessing the below menu in Nexacro Studio.
Options > Environment > Base Lib Path
Refer to User Components for the details on user components
Registering a module
Write the ExtDeviceAPI.json file as below. The paths and files specified in the 'scripts' and 'objInfo' elements must belong to the 'component' folder under the designated Base Lib Path.
{ "name": "ComComp", "version": "14.0.0.0", "description": "nexacro platform Common Component Library", "license": "", "scripts": [ "ExtDeviceAPI/Hello.js" ], "objInfo": [ "ExtDeviceAPI/Hello.info", "ExtDeviceAPI/HelloEnum.info" ] } //@ sourceURL=ExtDeviceAPI.json
Create the 'ExtDeviceAPI' folder, which was specified in the 'scripts' and 'objInfo' elements in the ExtDeviceAPI.json file, and create the following three files under the new folder.
Register ExtDeviceAPI.json as a module in Nexacro Studio. Right-click TypeDefinition in the Project Explorer and select Edit from the pop-up menu. Then, click the Add button in the Edit TypeDefinition window to register the ExtDeviceAPI.json file as a module.
Object information
Hello.info and HelloEnum.info were the two object information files specified for the nexacro.Hello user component. Hello.info contains necessary information for the component while HelloEnum.info contains information on the ENUM property.
Hello.info
This file contains necessary information for the nexacro.Hello user component.
<?xml version='1.0' encoding='utf-8'?> <MetaInfo version="1.0"> <Object id="nexacro.Hello"> <!-- define extend component based nexacro.Object --> <ObjectInfo typename="nexacro.Hello" csstypename="Hello,HelloABC[userprop='abc']" csscontrolname="HelloControl,HelloControlABC[userprop='abc']" group="Object" csspseudo="true" container="false" composite="true" tabstop="true" cssstyle="true" contents="true" formats="false" contentseditor="auto" defaultwidth="300" defaultheight="200" requirement="Runtime,HTML5" description=""/> <PseudoInfo> <Pseudo name="pushed" control="true" deprecated="false" unused="false" /> <Pseudo name="focused" control="true" deprecated="false" unused="true" /> </PseudoInfo> <ControlInfo> </ControlInfo> <PropertyInfo> <!-- define new property --> <Property name="userprop" group="Misc" type="Enum" defaultvalue="abc" readonly="false" initonly="false" hidden="false" control="false" style="false" expr="false" deprecated="false" unused="false" objectinfo="" enuminfo="enum_ext_test" unitinfo="" requirement="Runtime,HTML5" description="this is desc" /> <!-- re-define super's property --> <Property name="tooltiptext" group="Misc" type="String" defaultvalue="1111111" readonly="false" initonly="false" hidden="false" control="false" style="false" expr="false" deprecated="false" unused="false" objectinfo="" enuminfo="" unitinfo="" requirement="Runtime,HTML5" description="this is desc" /> <!-- define new style property --> <Property name="itemopacity" group="Style" type="Opacity" defaultvalue="" readonly="false" initonly="false" hidden="false" control="false" style="true" expr="false" deprecated="false" unused="false" objectinfo="nexacro.Style_opacity" enuminfo="" unitinfo="" requirement="Runtime,HTML5" description="this is desc" /> </PropertyInfo> <MethodInfo> <Method name="hello" group="" async="false" deprecated="false" unused="false" requirement="Runtime,HTML5" description="this is test method" > <Syntax text = "hello(a [, b])" > <Return/> <Arguments> <Argument name="a" type="String" in="true" out="false" option="false" variable="false" description="any string" /> <Argument name="b" type="String" in="true" out="false" option="true" variable="false" description="any string" /> </Arguments> </Syntax> </Method> </MethodInfo> <EventHandlerInfo> <!-- define event --> <EventHandler name="onhello" group="Event" deprecated="false" unused="false" requirement="Runtime,HTML5" description="this is test event" > <Syntax text="onhello(obj:Object, e:nexacro.EventInfo)" > <Return/> <Arguments> <Argument name="obj" type="Object" in="true" out="false" option="false" variable="false" description="Event Source Object" /> <Argument name="e" type="nexacro.EventInfo" in="true" out="false" option="false" variable="false" description="Event Information Object" /> </Arguments> </Syntax> </EventHandler> </EventHandlerInfo> </Object> </MetaInfo>
HelloEnum.info
This file contains information on the ENUM property.
<?xml version='1.0' encoding='utf-8'?> <MetaInfo version="1.0"> <!-- define enum information --> <EnumInfo id="enum_ext_test" composite="false" delimiter="" description="abc, 123" > <Enum name="abc" description="abc" /> <Enum name="123" description="123" /> </EnumInfo> </MetaInfo>
Registering the user component
Open the Edit TypeDefinition window, go to the Objects tab and click Add button to register the user component (nexacro.Hello).
Check that the Hello object icon has been created on the component toolbar.
Developing Test Form
Developing HelloTest.xfdl
Create a form (HelloTest.xfdl) to test the nexacro.Hello user component in Nexacro Studio.
If you apply the Hello object to the created form, you can see the object appear in the Invisible Object box and settings defined in Hello.info appear in the Properties window. After checking the Hello object was properly applied, add a button component on the top the form screen.
Add the
onclick
event to the button component by writing code. Enter 'this.Hello00.
" and you will see thehello
method, which was defined in Hello.js and Hello.info, appear as a hint.
this.Button00_onclick = function(obj:Button, e:nexacro.ClickEventInfo) { this.Hello00.hello("Hello World"); }
onhello
event
In the Properties window, you can find the onhello
event defined in Hello.info.
Input the text string "Hello World" to the hello
method, followed by the invocation of onhello
event. Then, set the TextArea00 object outputting the text string "onhello Event call."
//hello Method this.Button00_onclick = function(obj:Button, e:nexacro.ClickEventInfo) { this.Hello00.hello("Hello World"); } //onhello Event this.Hello00_onhello = function(obj:Hello, e:nexacro.EventInfo) { this.TextArea00.set_value("onhello Event call"); }
Modify the iOS and Android native module sources so that clicking the 'HelloTest' button will call the _onhello
event.
HelloPlugin.m (iOS native module)
As described in the below script, add the code of the
_onhello
event through theruncallback
method and build libHelloPlugin.a again
... //hello Method - (void)hello:(NSString*)lid withDict:(NSMutableDictionary*)options { self.helloMsg = [options objectForKey:@"helloMsg"]; self.nID = [lid integerValue]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:self.helloMsg delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [alert show]; //To call the _onhello event through the runcallback method when clicking the 'HelloTest' button NSString *callbackResult = [NSString stringWithFormat:@"runCallback(\"%d\",\"_onhello\",{'eventid':\"onhello\",'msg':\"%@\"});", self.nID, self.helloMsg]; [self writeJavascript:callbackResult]; } @end
HelloPlguin.java (Android native module)
Add the code to call
_onhello
event as described in the below script and build the libhelloplugin.jar file again.
... public void show(String message) { final String msg = message; new Thread(new Runnable() { @Override public void run() { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { Toast.makeText( NexacroPluginManager.getInstance() .getActivity(), msg, Toast.LENGTH_LONG) .show(); } }); } }).start(); // To call the _onhello event when clicking the 'HelloTest' button Native.SendDeviceEvent(getObjectId(), "_onhello", "{}"); } }
Test Execution
When you click the "HelloTest" button on the form created in Nexacro Studio, the hello
method will be called displaying the specified message in the form of an alert. Afterward, the hello
function will be called triggering the onhello
event and displaying the text string "hello_onhello call" on the TextArea component.
iOS device test
Android device test