DeviceAPI development

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

  1. Launch Xcode and create a project by accessing the below menu.

File > New > Project

프로젝트생성

  1. Select 'Cocoa Touch static Library' as a basic template.

템플릿선택

  1. 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

// 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

HelloPlugin.m

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."

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.

/admin_guide_nexacro_14_en

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

  1. Launch Eclipse and create a project by accessing the below menu.

File > New > Android Application Project

New_Project

  1. Enter 'HelloPlugin' as a name for the new project and finish the creation.

New_Android_Application

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.

  1. Create the HelloPlugin.java file and you can see the structure illustrated in the below picture.

New_HelloPlugin.java

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.

Toasts

http://developer.android.com/guide/topics/ui/notifiers/toasts.html

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

  1. Right-click the HelloPlugin project and select Export from the pop-up menu.

Export1

  1. Access [Java > JAR file] in the Export window.

Export2

  1. Check only the 'src' folder of the HelloPlugin project in the JAR Export window while leaving other folders unselected.

Export3

Adding the JAR file to an application project

  1. 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.

Nexacro_plugins.xml

<?xml version="1.0" encoding="utf-8"?>
<plugin-config>
	<plugin name="HelloPlugin" class="com.example.helloplugin.HelloPlugin"/>
</plugin-config>
  1. Drag the libhelloplugin.jar file and drop on the 'libs' folder.

Insert_libhelloplugin.jar

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.

/admin_guide_nexacro_14_en

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.

//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.

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

  1. 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

  1. 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.

  1. 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.

<?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>
<?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

  1. Create a form (HelloTest.xfdl) to test the nexacro.Hello user component in Nexacro Studio.

  1. 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.

  1. Add the onclick event to the button component by writing code. Enter 'this.Hello00." and you will see the hello 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.

...
//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
...
	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.

Result_iOS

결과화면