uni-qnc-toc/native-js使用教程.txt
2025-01-13 19:31:32 +08:00

1659 lines
71 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

概述
Native.js技术简称NJS是一种将手机操作系统的原生对象转义映射为JS对象在JS里编写原生代码的技术。 如果说Node.js把js扩展到服务器世界那么Native.js则把js扩展到手机App的原生世界。 HTML/JS/Css全部语法只有7万多而原生语法有几十万Native.js大幅提升了HTML5的能力。 NJS突破了浏览器的功能限制也不再需要像Hybrid那样由原生语言开发插件才能补足浏览器欠缺的功能。 NJS编写的代码最终需要在HBuilder里打包发行为App安装包或者在支持Native.js技术的浏览器里运行。目前Native.js技术不能在普通手机浏览器里直接运行。
NJS大幅扩展了HTML5的能力范围原本只有原生或Hybrid App的原生插件才能实现的功能如今可以使用JS实现。
NJS大幅提升了App开发效率将iOS、Android、Web的3个工程师组队才能完成的App变为1个web工程师就搞定。
NJS不再需要配置原生开发和编译环境调试、打包均在HBuilder里进行。没有mac和xcode一样可以开发iOS应用。
如果不熟悉原生API也没关系我们汇总了很多NJS的代码示例复制粘贴就可以用。http://ask.dcloud.net.cn/article/114
再次强调Native.js不是一个js库不需要下载引入到页面的script中也不像nodejs那样有单独的运行环境Native.js的运行环境是集成在5+runtime里的使用HBuilder打包的app或流应用都可以直接使用Native.js。
注意事项:
Uni-app不支持Native.js执行UI相关操作的API调用及webview相关API调用。将失效无法正常使用。Uni-app不推荐使用Native.js
技术要求
由于NJS是直接调用Native API需要对Native API有一定了解知道所需要的功能调用了哪些原生API能看懂原生代码并参考原生代码修改为JS代码。 否则只能直接copy别人写好的NJS代码。
开始使用
判断平台
Native API具有平台依赖性所以需要通过以下方式判断当前的运行平台
function judgePlatform(){
switch ( plus.os.name ) {
case "Android":
// Android平台: plus.android.*
break;
case "iOS":
// iOS平台: plus.ios.*
break;
default:
// 其它平台
break;
}
}
复制代码
类型转换
在NJS中调用Native API或从Native API返回数据到NJS时会自动转换数据类型。
类型转换表
类型 Objective-C Java JavaScript
基本数据 byte/short/int/long/float/double/... byte/short/int/long/float/double/... Number
字符 char char String
字符串 NSString/@"" String/"" String
数组 @[1,2,3]/NSArray new XXX[] InstanceObject
类 @interface class ClassObject
对象(实例) * * InstanceObject
空对象 nil null null
其它 Protocol Interface Object(JSON)
其他转换
Android原生应用的主Activity对象 转为plus.android.runtimeMainActivity() Android的主Activity对象是启动应用时自动创建的不是代码创建此时通过plus.android.runtimeMainActivity()方法获取该Activity对象
Objective-C方法冒号剔除 [pos setPositionX:(int)x Y:(int)y;] 转为 pos.setPositionXY(x,y); OC语法中方法的定义格式为: “(返回值类型) 函数名: (参数1类型) 形参1 参数2名称: (参数2类型) 形参2” 方法的完整名称为: “函数名:参数2名称:”。 如:“voidsetPositionX:(int)x Y:(int)y;”方法的完整名称为“setPositionX:Y:”,调用时语法为:“[pos setPositionX:x Y:y];”。 在JS语法中函数名称不能包含“:”字符所以OC对象的方法名映射成NJS对象方法名时将其中的“:”字符自动删除上面方法名映射为“setPositionXY”在NJS调用的语法为“pos.setPositionXY(x,y);”。
文件路径转换 Web开发里使用的image/1.png是该web工程的相对路径而原生API中经常需要使用绝对路径比如/sdcard/apptest/image/1.png此时使用这个扩展方法来完成转换plus.io.convertLocalFileSystemURL("image/1.png")
概念
类对象
由于JavaScript中本身没有类的概念为了使用Native API层的类在NJS中引入了类对象ClassObject的概念用于对Native中的类进行操作如创建类的实例对象、访问类的静态属性、调用类的静态方法等。其原型如下
Interface ClassObject {
function Object plusGetAttribute( String name );
function void plusSetAttribute( String name, Object value );
}
复制代码
获取类对象 在iOS平台我们可以通过plus.ios.importClass(name)方法导入类对象参数name为类的名称在Android平台我们可以通过plus.android.importClass(name)方法导入类对象其参数name为类的名称必须包含完整的命名空间。
示例:
// iOS平台导入NSNotificationCenter类
var NSNotificationCenter = plus.ios.importClass("NSNotificationCenter");
// Android平台导入Intent类
var Intent = plus.android.importClass("android.content.Intent");
复制代码
获取类对象后,可以通过类对象“.”操作符获取类的静态常量属性、调用类的静态方法类的静态非常量属性需通过plusGetAttribute、plusSetAttribute方法操作。
实例对象
在JavaScript中所有对象都是Object为了操作Native层类的实例对象在NJS中引入了实例对象InstanceObject的概念用于对Native中的对象进行操作如操作对象的属性、调用对象的方法等。其原型如下
Interface InstanceObject {
function Object plusGetAttribute( String name );
function void plusSetAttribute( String name, Object value );
}
复制代码
获取实例对象 有两种方式获取类的实例对象一种是调用Native API返回值获取另一种是通过new操作符来创建导入的类对象的实例如下
// iOS平台导入NSDictionary类
var NSDictionary = plus.ios.importClass("NSDictionary");
// 创建NSDictionary的实例对象
var ns = new NSDictionary();
// Android平台导入Intent类
var Intent = plus.android.importClass("android.content.Intent");
// 创建Intent的实例对象
var intent = new Intent();
复制代码
获取实例对象后,可以通过实例对象“.”操作符获取对象的常量属性、调用对象的成员方法实例对象的非常量属性则需通过plusGetAttribute、plusSetAttribute方法操作。
操作对象的属性方法
常量属性 获取对象后就可以通过“.”操作符获取对象的常量属性,如果是类对象则获取的是类的静态常量属性,如果是实例对象则获取的是对象的成员常量属性。
非常量属性 如果Native层对象的属性值在原生环境下被更改此时使用“.”操作符获取到对应NJS对象的属性值就可能不是实时的属性值而是该Native层对象被映射为NJS对象那一刻的属性值。 为获取获取Native层对象的实时属性值需调用NJS对象的plusGetAttribute(name)方法参数name为属性的名称返回值为属性的值。调用NJS对象的plusSetAttribute(name,value)方法设置Native层对象的非常量属性值参数name为属性的名称value为要设置新的属性值。 注意使用plusGetAttribute(name)方法也可以获取Native层对象的常量属性值但不如直接使用“.”操作符来获取性能高。
方法 获取对象后可以通过“.”操作符直接调用Native层方法如果是类对象调用的是Native层类的静态方法如果是实例对象调用的是Native层对象的成员方法。 注意在iOS平台由于JS语法的原因Objective-C方法名称中的“:”字符转成NJS对象的方法名称后将会被忽略因此在NJS中调用的方法名需去掉所有“”字符。
类的继承 Objective-C和Java中类如果存在继承自基类在NJS中对应的对象会根据继承关系递归将所有基类的公有方法一一换成NJS对象的方法所有基类的公有属性也可以通过其plusGetAttribute、plusSetAttribute方法访问。
开始写NJS
使用NJS调用Native API非常简单基本步骤如下
导入要使用到的类;
创建类的实例对象(或者调用类的静态方法创建);
调用实例对象的方法;
以下例子使用NJS调用iOS和Android的原生弹出提示框类似但不同于js的alert
Android
以下代码在Android平台展示调用Native API显示系统提示框。 首先是Android原生 Java代码用于比对参考
import android.app.AlertDialog;
//...
// 创建提示框构造对象Builder是AlertDialog的内部类。参数this指代Android的主Activity对象该对象启动应用时自动生成
AlertDialog.Builder dlg = new AlertDialog.Builder(this);
// 设置提示框标题
dlg.setTitle("自定义标题");
// 设置提示框内容
dlg.setMessage("使用NJS的原生弹出框可自定义弹出框的标题、按钮");
// 设置提示框按钮
dlg.setPositiveButton("确定(或者其他字符)", null);
// 显示提示框
dlg.show();
//...
复制代码
Native.js代码
/**
* 在Android平台通过NJS显示系统提示框
*/
function njsAlertForAndroid(){
// 导入AlertDialog类
var AlertDialog = plus.android.importClass("android.app.AlertDialog");
// 创建提示框构造对象构造函数需要提供程序全局环境对象通过plus.android.runtimeMainActivity()方法获取
var dlg = new AlertDialog.Builder(plus.android.runtimeMainActivity());
// 设置提示框标题
dlg.setTitle("自定义标题");
// 设置提示框内容
dlg.setMessage("使用NJS的原生弹出框可自定义弹出框的标题、按钮");
// 设置提示框按钮
dlg.setPositiveButton("确定(或者其他字符)",null);
// 显示提示框
dlg.show();
}
//...
复制代码
注意NJS代码中创建提示框构造对象要求传入程序全局环境对象可通过plus.android.runtimeMainActivity()方法获取应用的主Activity对象它是HTML5+应用运行期自动创建的程序全局环境对象。
Android设备上运行效果图 Android Native.js示例运行效果图 `注意其实HTML5+规范已经封装过原生提示框消息APIplus.ui.alert( message, alertCB, title, buttonCapture)。此处NJS的示例仅为了开发者方便理解实际使用时调用plus.ui.alert更简单性能也更高。**
iOS
以下代码在iOS平台展示调用Native API显示系统提示对话框。 iOS原生Objective-C代码用于比对参考
#import <UIKit/UIKit.h>
//...
// 创建UIAlertView类的实例对象
UIAlertView *view = [UIAlertView alloc];
// 设置提示对话上的内容
[view initWithTitle:@"自定义标题" // 提示框标题
message:@"使用NJS的原生弹出框可自定义弹出框的标题、按钮" // 提示框上显示的内容
delegate:nil // 点击提示框后的通知代理对象nil类似js的null意为不设置
cancelButtonTitle:@"确定(或者其他字符)" // 提示框上取消按钮的文字
otherButtonTitles:nil]; // 提示框上其它按钮的文字设置为nil表示不显示
// 调用show方法显示提示对话框在OC中使用[]语法调用对象的方法
[view show];
//...
复制代码
Native.js代码
/**
* 在iOS平台通过NJS显示系统提示框
*/
function njsAlertForiOS(){
// 导入UIAlertView类
var UIAlertView = plus.ios.importClass("UIAlertView");
// 创建UIAlertView类的实例对象
var view = new UIAlertView();
// 设置提示对话上的内容
view.initWithTitlemessagedelegatecancelButtonTitleotherButtonTitles("自定义标题" // 提示框标题
, "使用NJS的原生弹出框可自定义弹出框的标题、按钮" // 提示框上显示的内容
, null // 操作提示框后的通知代理对象,暂不设置
, "确定(或者其他字符)" // 提示框上取消按钮的文字
, null ); // 提示框上其它按钮的文字设置为null表示不显示
// 调用show方法显示提示对话框在JS中使用()语法调用对象的方法
view.show();
}
//...
复制代码
注意在OC语法中方法的定义格式为: “(返回值类型) 函数名: (参数1类型) 形参1 参数2名称: (参数2类型) 形参2” 方法的完整名称为: “函数名:参数2名称:”。 如:“voidsetPositionX:(int)x Y:(int)y;”方法的完整名称为“setPositionX:Y:” 调用时语法为:“[pos setPositionX:x Y:y];”。 在JS语法中函数名称不能包含“:”字符所以OC对象的方法名映射成NJS对象方法名时将其中的“:”字符自动删除上面方法名映射为“setPositionXY”在NJS调用的语法为“pos.setPositionXY(x,y);”。 iOS设备上运行效果图 iOS Native.js示例运行效果图 `注意其实HTML5+规范已经封装过原生提示框消息APIplus.ui.alert( message, alertCB, title, buttonCapture)。此处NJS的示例仅为了开发者方便理解实际使用时调用plus.ui.alert更简单、性能也更高。
在HBuilder自带的Hello H5+模板应用中“Native.JS”plus/njs.html页面有完整的源代码可真机运行查看效果。
常用API
API on Android
为了能更好的理解NJS调用Java Native API我们在Android平台用Java实现以下测试类将在会后面API说明中的示例来调用。 文件NjsHello.java代码如下
package io.dcloud;
// 定义类NjsHello
public class NjsHello {
// 静态常量
public static final int CTYPE = 1;
// 静态变量
public static int count;
// 成员常量
public final String BIRTHDAY = "2013-01-13";
// 成员变量
String name; //定义属性name
NjsHelloEvent observer;
public void updateName( String newname ) { //定义方法updateName
name = newname;
}
public void setEventObserver( NjsHelloEvent newobserver ) {
observer = newobserver;
}
public void test() { //定义方法test
System.out.printf( "My name is: %s", name );
observer.onEventInvoked( name );
}
public static void testCount() {
System.out.printf( "Static count is:%d", count );
}
static{ // 初始化类的静态变量
NjsHello.count = 0;
}
}
复制代码
文件NjsHelloEvent.java代码如下
package io.dcloud;
// 定义接口NjsHelloEvent
public interface NjsHelloEvent {
public void onEventInvoked( String name );
}
复制代码
此NjsHello示例仅为了说明原生代码与NJS代码之间的映射关系以下示例代码无法直接在HBuilder里真机运行必须在以后HBuilder开放自定义打包后方可把NjsHello类打入app并被NJS调用。实际使用中这种需要并非必要大多数情况可以通过直接写NJS代码调用操作系统API而无需由原生语言二次封装类供JS调用。
plus.android.importClass
导入Java类对象方法原型如下
ClassObject plus.android.importClass( String classname );
复制代码
导入类对象后,就可以通过“.”操作符直接调用对象(类对象/实例对象)的常量和方法。 classname要导入的Java类名必须是完整的命名空间使用"."分割如果指定的类名不存在则导入类失败返回null。
注意:导入类对象可以方便的使用“.”操作符来调用对象的属性和方法但也会消耗较多的系统资源。因此导入过多的类对象会影响性能此时可以使用“高级API”中提供的方法在不导入类对象的情况下调用Native API。
示例:
导入类对象 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 创建对象的实例
NjsHello hello = new NjsHello();
//...
}
//...
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 创建NjsHello的实例对象
var hello = new NjsHello();
// ...
复制代码
ClassObject
调用plus.android.importClass()方法导入类并返回ClassObject类对象通过该类对象可以创建类的实例对象。在Java中类的静态方法会转换成NJS类对象的方法可通过类对象的“.”操作符调用类的静态常量会转换为NJS类对象的属性可通过类对象的“.”操作符访问类的静态属性则需通过NJS类对象的plusGetAttribute、plusSetAttribute方法操作。 示例:
导入类后获取类的静态常量属性 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 获取类的静态常量属性
int type = NjsHello.CTYPE;
System.out.printf( "NjsHello Final's value: %d", type ); // 输出“NjsHello Final's value: 1”
//...
}
//...
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 获取类的静态常量属性
var type = NjsHello.CTYPE;
console.log( "NjsHello Final's value: "+type ); // 输出“NjsHello Final's value: 1”
// ...
复制代码
导入类后调用类的静态方法 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 调用类的静态方法
NjsHello.testCount();
//...
}
//...
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 调用类的静态方法
NjsHello.testCount();
// ...
复制代码
ClassObject.plusGetAttribute
获取类对象的静态属性值,方法原型如下:
Object classobject.plusGetAttribute( String name );
复制代码
导入类对象后就可以调用其plusGetAttribute方法获取类的静态属性值。
name要获取的静态属性名称如果指定的属性名称不存在则获取属性失败返回null。
注意如果导入的类对象中存在“plusGetAttribute”同名的静态方法则必须通过plus.android.invoke()方法调用。
示例:
导入类后获取类的静态属性值 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 获取类的静态属性
int count = NjsHello.count;
System.out.printf( "NjsHello Static's value: %d", count ); // 输出“NjsHello Static's value: 0”
//...
}
//...
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 获取类的静态属性
var count = NjsHello.plusGetAttribute( "count" );
console.log( "NjsHello Static's value: "+count ); // 输出“NjsHello Static's value: 0”
// ...
复制代码
ClassObject.plusSetAttribute
设置类对象的静态属性值,方法原型如下:
void classobject.plusSetAttribute( String name, Object value );
复制代码
导入类对象后就可以调用其plusSetAttribute方法设置类的静态属性值。
name要设置的静态属性名称如果指定的属性名称不存在则设置属性失败返回null。
value要设置的属性值其类型必须与Native层类对象的静态属性区配否则设置操作不生效将保留以前的值。
注意如果导入的类对象中存在“plusSetAttribute”同名的静态方法则必须通过plus.android.invoke()方法调用。
示例:
导入类后设置类的静态属性值 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 设置类的静态属性值
NjsHello.count = 2;
System.out.printf( "NjsHello Static's value: %d", NjsHello.count ); // 输出“NjsHello Static's value: 2”
//...
}
//...
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 设置类的静态属性值
NjsHello.plusSetAttribute( "count", 2 );
console.log( "NjsHello Static's value: "+NjsHello.plusGetAttribute( "count" ) ); // 输出“NjsHello Static's value: 2”
// ...
复制代码
InstanceObject
NJS中实例对象与Java中的对象对应调用plus.android.importClass()方法导入类后通过new操作符可创建该类的实例对象或直接调用plus.android.newObject方法创建类的实例对象也可通过调用Native API返回实例对象。在Java中对象的方法会转换成NJS实例对象的方法可通过实例对象的“.”操作符调用对象的常量属性会转换NJS实例对象的属性可通过实例对象的“.”操作符访问。对象的非常量属性则必须通过NJS实例对象的plusGetAttribute、plusSetAttribute方法操作。 示例:
导入类创建实例对象,调用对象的方法 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 创建NjsHello的实例对象
NjsHello hello = new NjsHello();
// 调用对象的方法
hello.updateName( "Tester" );
//...
}
//...
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 创建NjsHello的实例对象
var hello = new NjsHello();
// 调用对象的方法
hello.updateName( "Tester" );
// ...
复制代码
导入类创建实例对象,获取对象的常量属性 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 创建NjsHello的实例对象
NjsHello hello = new NjsHello();
// 访问对象的常量属性
String birthday = hello.BIRTHDAY;
System.out.printf( "NjsHello Object Final's value: %s", birthday ); // 输出“NjsHello Object Final's value: 2013-01-13”
//...
}
//...
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 创建NjsHello的实例对象
var hello = new NjsHello();
// 访问对象的常量属性
var birthday = hello.BIRTHDAY;
console.log( "NjsHello Object Final's value: "+birthday ); // 输出“NjsHello Object Final's value: 2013-01-13”
// ...
复制代码
InstanceObject.plusGetAttribute
获取实例对象的属性值,方法原型如下:
Object instancebject.plusGetAttribute( String name );
复制代码
获取实例对象后就可以调用其plusGetAttribute方法获取对象的属性值。 name要获取对象的属性名称如果指定的属性名称不存在则获取属性失败返回null。
注意如果实例对象中存在“plusGetAttribute”同名的方法则必须通过plus.android.invoke()方法调用。
示例:
导入类创建实例对象,获取对象的属性值 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 创建对象的实例
NjsHello hello = new NjsHello();
hello.updateName( "Tester" );
// 获取其name属性值
String name = hello.name;
System.out.printf( "NjsHello Object's name: %s", name ); // 输出“NjsHello Object's name: Tester”
//...
}
//...
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 创建对象的实例
var hello = new NjsHello();
hello.updateName( "Tester" );
// 获取其name属性值
var name = hello.plusGetAttribute( "name" );
console.log( "NjsHello Object's name: "+name ); // 输出“NjsHello Object's name: Tester”
// ...
复制代码
InstanceObject.plusSetAttribute
设置类对象的静态属性值,方法原型如下:
void instanceobject.plusSetAttribute( String name, Object value );
复制代码
导入类对象后就可以调用其plusSetAttribute方法设置类的静态属性值。
name要设置的静态属性名称如果指定的属性名称不存在则设置属性失败返回null。
value要设置的属性值其类型必须与Native层类对象的静态属性区配否则设置操作不生效将保留以前的值。
注意如果导入的类对象中存在“plusSetAttribute”同名的静态方法则必须通过plus.android.invoke()方法调用。
示例:
导入类创建实例对象,设置对象的属性值 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 创建对象的实例
NjsHello hello = new NjsHello();
// 设置其name属性值
hello.name = "Tester";
System.out.printf( "NjsHello Object's name: %s", hello.name ); // 输出“NjsHello Object's name: Tester”
//...
}
//...
}
复制代码
NJS代码
// 导入测试类NjsHello
var Hello = plus.android.importClass("NjsHello");
// 创建对象的实例
var hello = new NjsHello();
// 设置其name属性值
hello.plusSetAttribute( "name", "Tester" );
console.log( "NjsHello Object's name: "+hello.plusGetAttribute("name") ); // 输出“NjsHello Object's name: Tester”
// ...
复制代码
plus.android.implements
在Java中可以通过定义新类并实现Interface的接口并创建出新类对象作为其它接口的参数在NJS中则可快速创建对应的Interface对象方法原型如下 Object plus.android.implements( String name, Object obj );
此方法创建Native层中Java的接口实现对象作为调用其它Native API的参数。
name接口的名称必须是完整的命名空间使用"."分割如果不存在此接口则创建接口实现对象失败返回null。
objJSON对象类型接口实现方法的定义JSON对象中key值为接口方法的名称value值为Function方法参数必须与接口中方法定义的参数区配。
示例:
Test类中实现接口NjsHelloEvent的方法并调用NjsHello对象的test方法触发接口中函数的运行。 Java代码
import io.dcloud.NjsHello;
import io.dcloud.NjsHelloEvent;
//...
// Test类实现NjsHelloEvent接口
public class Test implements NjsHelloEvent {
public static void main( String args[] ) {
// 创建对象的实例
NjsHello hello = new NjsHello();
// 调用updateName方法
hello.updateName( "Tester" );
// 设置监听对象
hello.setEventObserver( this );
// 调用test方法触发接口事件
hello.test(); // 触发onEventInvoked函数运行
//...
}
// 实现接口NjsHelloEvent的onEventInvoked方法
@Override
public void onEventInvoked( String name ) {
System.out.printf( "Invoked Object's name is: %s", name );
}
//...
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 实现接口“NjsHelloEvent”对象
var hevent = plus.android.implements( "io.dcloud.NjsHelloEvent", {
"onEventInvoked":function( name ){
console.log( "Invoked Objects name: "+name ); // 输出“Invoked Objects name: Tester”
}
} );
// 创建对象的实例
var hello = new NjsHello();
// 调用updateName方法
hello.updateName( "Tester" );
// 设置监听对象
hello.setEventObserver( hevent );
// 调用test方法触发代理事件
hello.test(); // 触发上面定义的匿名函数运行
// ...
复制代码
plus.android.runtimeMainActivity
获取运行期环境主Activity实例对象方法原型如下
InstanceObject plus.android.runtimeMainActivity();
复制代码
此方法将获取程序的主Activity的实例对象它是Html5+运行期环境主组件用于处理与用户交互的各种事件也是应用程序全局环境android.app.Activity的实现对象。android.app.Activity是一个特殊的类需要在原生开发环境中注册后才能使用所以使用new操作符创建对象无实际意义。
示例:
调用Activity的startActivity方法来拨打电话 Java代码
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
//...
// 获取主Activity对象的实例
Activity main = context;
// 创建Intent
Uri uri = Uri.parse("tel:10086");
Intent call = new Intent("android.intent.action.CALL",uri);
// 调用startActivity方法拨打电话
main.startActivity(call);
//...
复制代码
NJS代码
// 导入Activity、Intent类
var Intent = plus.android.importClass("android.content.Intent");
var Uri = plus.android.importClass("android.net.Uri");
// 获取主Activity对象的实例
var main = plus.android.runtimeMainActivity();
// 创建Intent
var uri = Uri.parse("tel:10086");
var call = new Intent("android.intent.action.CALL",uri);
// 调用startActivity方法拨打电话
main.startActivity( call );
// ...
复制代码
plus.android.currentWebview
获取当前Webview窗口对象的native层实例对象方法原型如下
InstanceObject plus.android.currentWebview();
复制代码
Android平台完整Java类名为android.webkit.Webview完整API请参考Android开发文档android.webkit.Webview。
示例:
调用Webview的loadUrl方法跳转页面 Java代码
import android.webkit.Webview;
//...
// 获取Webview对象
Webview wv = this;
// 跳转页面
wv.loadUrl("http://www.dcloud.io/");
//...
复制代码
NJS代码
// 导入Webview类
var Webview = plus.android.importClass("android.webkit.Webview");
// 当前Webview对象的实例
var wv = plus.android.currentWebview();
// 跳转页面
wv.loadUrl("http://www.dcloud.io/");
// ...
复制代码
完整API文档参考HTML5+ API - Native.js for Android
API on iOS
为了能更好的理解NJS调用Objective-C Native API我们在iOS平台用Objective-C实现以下测试类将会在后面API说明中的示例来调用。 头文件njshello.h代码如下
// 定义协议
@protocol NjsHelloEvent <NSObject>
@required
-(void) onEventInvoked:(NSString*)name;
@end
// -------------------------------------------------------------
// 定义类NjsHello
@interface NjsHello : NSObject {
NSString *_name;
id<NjsHelloEvent > _delegate;
}
@property (nonatomic,retain) NSString *name;
@property (nonatomic,retain) id delegate;
-(void)updateName:(NSString*)newname;
-(void)setEventObserver:(id<NjsHelloEvent >)delegate;
-(void)test;
+(void)testCount;
@end
复制代码
实现文件njshello.m源代码如下
#import "njshello.h"
// 实现类NjsHello
@implementation NjsHello
@synthesize name=_name;
-(void)updateName:(NSString*)newname{
_name = [newname copy];
}
-(void)setEventObserver:(id<NjsHelloEvent >)delegate{
_delegate = delegate;
}
-(void)test{
NSLog(@"My name is: %@",_name);
[[self delegate]onEventInvoked:name];
}
-(void)dealloc{
[_name release];
[supper dealloc];
}
+(void)testCount{
NSLog( @"Static test count" );
}
@end
复制代码
plus.ios.importClass
导入Objective-C类对象方法原型如下
ClassObject plus.ios.importClass( String classname );
复制代码
导入类对象后,就可以通过“.”操作符直接调用对象(类对象/实例对象)的常量和方法。通过“.”操作符号调用方法时,不需要使用“:”来分割方法名。
classname要导入的Objective-C类名如果指定的类名不存在则导入类失败返回null。
注意:导入类对象可以方便的使用“.”操作符来调用对象的属性和方法但也会消耗较多的系统资源。因此导入过多的类对象会影响性能此时可以使用“高级API”中提供的方法在不导入类对象的情况下调用Native API。 示例:
导入类并创建实例对象 Objective-C代码
#import "njshello.h"
int main( int argc, char *argv[] )
{
// 创建对象的实例
NjsHello* hello = [[NjsHello alloc] init];
// ...
}
// ...
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.ios.importClass("NjsHello");
// 创建对象的实例
var hello = new NjsHello();
// ...
复制代码
ClassObject
调用plus.ios.importClass()方法导入类并返回ClassObject类对象通过该类对象可以创建类的实例对象。在Objective-C中类的静态方法会转换成NJS类对象的方法可通过类对象的“.”操作符调用;
注意由于Objective-C中类没有静态变量而是通过定义全局变量来实现目前NJS中无法访问全局变量的值。对于全局常量在NJS中也无法访问对于原类型常量可在文档中找到其具体的值在JS代码中直接赋值对于非原类型常量目前还无法访问。
示例:
导入类后调用类的静态方法 Objective-C代码
#import "njshello.h"
// ...
int main( int argc, char *argv[] )
{
// 调用类的静态方法
[NjsHello testCount];
// ...
}
// ...
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.ios.importClass("NjsHello");
// 调用类的静态方法
NjsHello.testCount();
// ...
复制代码
InstanceObject
NJS中实例对象与Objective-C中的对象对应调用plus.ios.importClass()方法导入类后通过new操作符可创建该类的实例对象或直接调用plus.ios.newObject方法创建类的实例对象也可通过调用Native API返回实例对象。在Objective-C中对象的方法会转换成NJS实例对象的方法可通过实例对象的“.”操作符调用对象的属性则必须通过NJS实例对象的plusGetAttribute、plusSetAttribute方法操作。
示例:
导入类创建实例对象,调用对象的方法 Objective-C代码
#import "njshello.h"
int main( int argc, char *argv[] )
{
// 创建对象的实例
NjsHello* hello = [[NjsHello alloc] init];
// ...
}
// ...
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.ios.importClass("NjsHello");
// 创建对象的实例
var hello = new NjsHello();
// ...
复制代码
InstanceObject.plusGetAttribute
获取实例对象的属性值,方法原型如下:
Object instancebject.plusGetAttribute( String name );
复制代码
获取实例对象后就可以调用其plusGetAttribute方法获取对象的属性值。
name要获取对象的属性名称如果指定的属性名称不存在则获取属性失败返回null。
注意如果实例对象中存在“plusGetAttribute”同名的方法则只能通过plus.ios.invoke()方法调用。
示例:
导入类创建实例对象,获取对象的属性值 Objective-C代码
#import "njshello.h"
int main( int argc, char *argv[] )
{
// 创建对象的实例
NjsHello* hello = [[NjsHello alloc] init];
[hello updateName:@"Tester"];
// 获取其name属性值
NSString* name = hello.name;
NSLog(@"NjsHello Object's name: %@",name); // 输出“NjsHello Object's name: Tester”
// ...
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.ios.importClass("NjsHello");
// 创建对象的实例
var hello = new NjsHello();
hello.updateName( "Tester" );
// 获取其name属性值
var name = hello.plusGetAttribute( "name" );
console.log( "NjsHello Objects name: "+name ); // 输出“NjsHello Objects name: Tester”
// ...
复制代码
InstanceObject.plusSetAttribute
设置类对象的静态属性值,方法原型如下:
void instanceobject.plusSetAttribute( String name, Object value );
复制代码
导入类对象后就可以调用其plusSetAttribute方法设置类的静态属性值。
name要设置的静态属性名称如果指定的属性名称不存在则设置属性失败返回null。
value要设置的属性值其类型必须与Native层类对象的静态属性区配否则设置操作不生效将保留以前的值。
注意如果导入的类对象中存在“plusSetAttribute”同名的静态方法则只能通过plus.android.invoke()方法调用。
示例:
导入类创建实例对象,设置对象的属性值 Java代码
#import "njshello.h"
int main( int argc, char *argv[] )
{
// 创建对象的实例
NjsHello* hello = [[NjsHello alloc] init];
// 设置其name属性值
hello.name = @"Tester";
NSLog(@"NjsHello Object's name: %@",hello.name); // 输出“NjsHello Object's name: Tester”
// ...
}
//...
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.ios.importClass("NjsHello");
// 创建对象的实例
var hello = new NjsHello();
// 设置其name属性值
hello.plusSetAttribute( "name", "Tester" );
console.log( "NjsHello Objects name: "+hello.plusGetAttribute("name") ); // 输出“NjsHello Objects name: Tester”
// ...
复制代码
plus.ios.implements
在Objective-C中可以通过定义新类并实现Protocol的协议并创建出新类对象作为代理对象在NJS中则可实现协议快速创建代理对象方法原型如下
Object plus.ios.implements( String name, Object obj );
复制代码
此方法返回一个NJS实例对象映射到Native层中的代理对象其父类为“NSObject”并且实现obj中指定的协议方法。通常作为调用其它Native API的参数。
name协议的名称也可以是自定的字符串名称用于定义一个代理。
objJSON对象类型代理实现方法的定义JSON对象中key值为协议中定义的方法名称必须保留方法名称中的“”字符value值为Function方法参数必须与协议中定义方法的参数区配。
示例:
实现一个代理并调用test方法触发调用代理的方法 Objective-C代码
#import "njshello.h"
// 定义代理类NjsDelegate
@interface NjsDelegate: NSObject<NjsHelloEvent> {
-(void) onEventInvoked:(NSString*)name;
}
@end
// -------------------------------------------------------------
// 实现代理类NjsDelegate
@implementation NjsDelegate
-(void) onEventInvoked:(NSString*)name{
NSLog(@"Invoked Object's name:%@",name); // 输出“Invoked Objects name: Tester”
}
@end
// -------------------------------------------------------------
// 主函数
int main( int argc, char *argv[] )
{
// 创建对象的实例
NjsHello* hello = [[NjsHello alloc] init];
// 调用updateName方法
[hello updateName:@"Tester"];
// 创建代理对象
NjsDelegate* delegate = [[NjsDelegate alloc] init];
// 设置监听对象
[hello setEventObserver:delegate];
// 调用test方法触发代理事件
[hello test]; // 触发上面代理对象定义的onEventInvoked运行
// ...
}
复制代码
在NJS中不需要创建新的类对象调用plus.ios.implements实现协议接口即可创建出代理对象代码如下
// 导入测试类NjsHello
var NjsHello = plus.ios.importClass("NjsHello");
// 实现协议“NjsHelloEvent”的代理
var hevent = plus.ios.implements( "NjsHelloEvent", {
"onEventInvoked:":function( name ){
console.log( "Invoked Objects name: "+name ); // 输出“Invoked Objects name: Tester”
}
} );
// 调用updateName方法
hello.updateName( "Tester" );
// 设置监听对象
hello.setEventObserver( hevent );
// 调用test方法触发代理事件
hello.test(); // 触发上面代理对象定义的匿名函数运行
// ...
复制代码
plus.ios.deleteObject
释放NJS中实例对象中映射的Native对象方法原型如下
void plus.ios.deleteObject( Object obj );
复制代码
NJS中所有的实例对象InstanceObject都可以通过此方法释放会将Native层的对象使用的资源进行释放。
obj要释放的实例对象如果obj对象不是有效的实例对象则不执行对象的是否资源操作。
注意:此方法是可选的,如果不调用此方法释放实例对象,则在页面关闭时会自动释放所有对象;若对象占用较多的系统资源,则在业务逻辑处理完成时应该主动调用此方法释放资源,以提到程序的运行效率。
示例:
创建实例对象使用完成后,显式操作销毁对象 Objective-C代码
#import "njshello.h"
int main( int argc, char *argv[] )
{
// 创建对象的实例
NjsHello* hello = [[NjsHello alloc] init];
// 调用updateName方法
[hello updateName:@"Tester"];
// ...
// 使用完后销毁对象的实例
[hello release];
}
复制代码
NJS代码
// 导入测试类NjsHello
var NjsHello = plus.ios.importClass("NjsHello");
// 创建对象的实例
var hello = new NjsHello();
// 调用updateName方法
hello.updateName( "Tester" );
// ...
// 使用完后销毁对象的实例
plus.ios.deleteObject( hello );
复制代码
plus.ios.currentWebview
获取当前Webview窗口对象的native层UIWebview实例对象方法原型如下
InstanceObject plus.ios.currentWebview();
复制代码
UIWebview对象的API请参考Apple开发文档UIWebview
示例:
创建实例对象使用完成后,显式操作销毁对象 Objective-C代码
// 获取当前Webview对象的实例
UIWebview* wv=self;
// 创建请求对象
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.dcloud.io/"]];
// 跳转页面
[web loadRequest:req];
// 释放对象
// 系统自动回收
// ...
复制代码
NJS代码
// 导入UIWebview、NSURLRequest、NSURL类
var Webview = plus.ios.importClass("UIWebview");
var NSURLRequest = plus.ios.import('NSURLRequest');
var NSURL = plus.ios.import('NSURL');
// 获取当前Webview对象的实例
var wv = plus.ios.currentWebview();
// 创建请求对象
var req = NSURLRequest.requestWithURL(NSURL.URLWithString('http://www.dcloud.io/'));
// 跳转页面
plus.ios.invoke(wv,"loadRequest:",req);
// 释放对象(可选)
plus.ios.deleteObject(req);
plus.ios.deleteObject(wv);
// ...
复制代码
完整API文档参考HTML5+ API - Native.js for iOS
完整业务演示
Android
在Android手机桌面上创建快捷方式图标这是原本只有原生程序才能实现的功能。即使使用Hybrid方案也需要原生工程师来配合写插件。 下面我们演示如何直接使用js在Android手机桌面创建快捷方式在HelloH5+应用中Native.JS页面中“Shortcut (Android)”可以查看运行效果。 这段代码是使用原生Java实现的创建快捷方式的代码用于参考比对
import android.app.Activity;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap;
// 创建桌面快捷方式
void createShortcut(){
// 获取主Activity
Activity main = this;
// 创建快捷方式意图
Intent shortcut = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
// 设置快捷方式的名称
shortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, "HelloH5+");
// 设置不可重复创建
shortcut.putExtra("duplicate",false);
// 设置快捷方式图标
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/icon.png");
shortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
// 设置快捷方式启动执行动作
Intent action = new Intent(Intent.ACTION_MAIN);
action.setComponent( main.getComponentName() );
shortcut.putExtra( Intent.EXTRA_SHORTCUT_INTENT, action );
// 广播创建快捷方式
main.sendBroadcast(shortcut);
}
复制代码
使用NJS实现时首先导入需要使用到的android.content.Intent、android.graphics.BitmapFactory类按照Java代码中的方法对应转换成JavaScript代码。 其中快捷方式图标是通过解析本地png文件进行设置在JavaScript中需要使用plus.io.* API转换成本地路径传递给Native API完整代码如下
var Intent=null,BitmapFactory=null;
var main=null;
document.addEventListener( "plusready", function() {//"plusready"事件触发时执行plus对象的方法
// ...
if ( plus.os.name == "Android" ) {
// 导入要用到的类对象
Intent = plus.android.importClass("android.content.Intent");
BitmapFactory = plus.android.importClass("android.graphics.BitmapFactory");
// 获取主Activity
main = plus.android.runtimeMainActivity();
}
}, false);
/**
* 创建桌面快捷方式
*/
function createShortcut(){
// 创建快捷方式意图
var shortcut = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
// 设置快捷方式的名称
shortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, "测试快捷方式");
// 设置不可重复创建
shortcut.putExtra("duplicate",false);
// 设置快捷方式图标
var iconPath = plus.io.convertLocalFileSystemURL("/icon.png"); // 将相对路径资源转换成系统绝对路径
var bitmap = BitmapFactory.decodeFile(iconPath);
shortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON,bitmap);
// 设置快捷方式启动执行动作
var action = new Intent(Intent.ACTION_MAIN);
action.setClassName(main.getPackageName(), 'io.dcloud.PandoraEntry');
shortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT,action);
// 广播创建快捷方式
main.sendBroadcast(shortcut);
console.log( "桌面快捷方式已创建完成!" );
}
复制代码
注意提交到云平台打包时需要添加Android权限才能在桌面创建快捷方式在HBuilder工程中双击应用的“manifest.json”文件切换到“代码视图”中在plus->distribute->google->permissions节点下添加权限数据
"google": {
// ...
"permissions": [
"<uses-permission android:name=\"com.android.launcher.permission.INSTALL_SHORTCUT\"/>"
]
}
复制代码
如下图所示:
manifest.json中Android权限 permissions
iOS
在iOS手机上登录game center一个游戏中心服务这是原本只有原生程序才能实现的功能。即使使用Hybrid方案也需要原生工程师来配合写插件。 下面我们演示如何直接使用js在iOS手机上登录game center在HelloH5+应用中Native.JS页面中的“Game Center (iOS)”可以查看运行效果。 注意手机未开通game center则无法登陆请先点击iOS自带的game center进行配置。 这段代码是使用原生Objective-C实现的登录game center的代码用于参考比对。原生Objective-C代码的头文件Test.h中代码如下
@interface Test: NSObject
// 游戏玩家登录状态监听函数
- (void)authenticationChanged:(NSNotification*)notification;
// 获取游戏玩家状态信息
- (void)playerInformation:(GKPlayer *)player;
// 登录到游戏中心
- (void)loginGamecenter;
// 停止监听登录游戏状态变化
- (void)logoutGamecenter;
@end
实现文件Test.m中代码如下
@implementation Test
// 游戏玩家登录状态监听函数
- (void)authenticationChanged:(NSNotification*)notification
{
// 获取游戏玩家共享实例对象
GKLocalPlayer *player = notification.object;
if ( player.isAuthenticated ) {
// 玩家已登录认证,获取玩家信息
[self playerInformation:player];
} else {
// 玩家未登录认证,提示用户登录
NSLog(@"请登录!");
}
// 释放使用的对象
[player release];
}
// 获取游戏玩家状态信息
- (void)playerInformation:(GKPlayer *)player
{
// 获取游戏玩家的名称
NSLog(@"Name: %@",player.displayName);
}
// 登录到游戏中心
- (void)loginGamecenter
{
// 监听用户登录状态变更事件
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:@selector(authenticationChanged)
name:@"GKPlayerAuthenticationDidChangeNotificationName"
object:nil];
// 获取游戏玩家共享实例对象
GKLocalPlayer *localplayer = [GKLocalPlayer localPlayer];
// 判断游戏玩家是否已经登录认证
if ( localplayer.isAuthenticated ) {
// 玩家已登录认证,获取玩家信息
[self playerInformation:localplayer];
} else {
// 玩家未登录认证,发起认证请求
[localplayer authenticateWithCompletionHandler:nil];
NSLog(@"登录中...");
}
// 释放使用的对象
[localplayer release];
[nc release];
}
// 停止监听登录游戏状态变化
- (void)logoutGamecenter
{
// 取消监听用户登录状态变化
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self
name:@"GKPlayerAuthenticationDidChangeNotificationName"
object:nil];
// 释放使用的对象
[nc release];
}
@end
复制代码
使用NJS实现时可以按照Objective-C代码中的方法对应转换成JavaScript代码最关键的代码是loginGamecenter方法中对用户登录状态的监听需调用NSNotificationCenter对象的“addObserver:selector:name:object”方法
addObserver:后要求传入一个实例对象用于查找selector参数中指定的方法在Objective-C中通常将对象自身self传入但在NJS中没有此概念因此需使用plus.ios.implements方法来创建一个新的对象 var delegate = plus.ios.implements("NSObject",{"authenticationChanged:":authenticationChanged}); 第一个参数“NSObject”表示对象的类型第二个参数中的JSON对象表明对象拥有的方法“authenticationChanged”方法是delegate对象的方法。
selector:后要传入一个类函数指针在Objective-C中通过“@selector”指令可选择函数指针在NJS中则需使用plus.ios.newObject方法来创建一个函数对象 plus.ios.newObject("@selector","authenticationChanged:") 第一个参数需固定值为“@selector”表示创建的是类函数指针对象第二个参数。 在"plusready"事件中导入GKLocalPlayer和NSNotificationCenter类并调用登录方法longinGamecenter()。
完整JavaScript代码如下
// 处理"plusready"事件
var bLogin=false;
document.addEventListener( "plusready", function() {
// ...
if ( plus.os.name == "iOS" ) {
GKLocalPlayer = plus.ios.importClass("GKLocalPlayer");
NSNotificationCenter = plus.ios.importClass("NSNotificationCenter");
longinGamecenter();
} else {
alert("欢迎您");
bLogin = true;
setTimeout( function(){
plus.ui.toast( "此平台不支持Game Center功能" );
}, 500 );
}
}, false);
var GKLocalPlayer=null,NSNotificationCenter=null;
var delegate=null;
// 游戏玩家登录状态监听函数
function authenticationChanged( notification ){
// 获取游戏玩家共享实例对象
var player = notification.plusGetAttribute("object");
if ( player.plusGetAttribute("isAuthenticated") ) {
// 玩家已登录认证,获取玩家信息
playerInformation(player);
bLogin = true;
} else {
// 玩家未登录认证,提示用户登录
alert("请登录");
bLogin = false;
}
// 释放使用的对象
plus.ios.deleteObject(player);
}
// 获取游戏玩家状态信息
function playerInformation( player ){
var name = player.plusGetAttribute("displayName");
alert( name+" 已登录!" );
}
// 登录到游戏中心
function longinGamecenter(){
if ( bLogin ){
return;
}
// 监听用户登录状态变更事件
var nc = NSNotificationCenter.defaultCenter();
delegate = plus.ios.implements("NSObject",{"authenticationChanged:":authenticationChanged});
nc.addObserverselectornameobject(delegate,
plus.ios.newObject("@selector","authenticationChanged:"),
"GKPlayerAuthenticationDidChangeNotificationName",
null);
// 获取游戏玩家共享实例对象
var localplayer = GKLocalPlayer.localPlayer();
// 判断游戏玩家是否已经登录认证
if ( localplayer.isAuthenticated() ) { // localplayer.plusGetAttribute("isAuthenticated")
// 玩家已登录认证,获取玩家信息
playerInformation( localplayer );
bLogin = true;
} else {
// 玩家未登录认证,发起认证请求
localplayer.authenticateWithCompletionHandler(null);
alert( "登录中..." );
}
// 释放使用的对象
plus.ios.deleteObject(localplayer);
plus.ios.deleteObject(nc);
}
// 停止监听登录游戏状态变化
function stopGamecenterObserver()
{
// 取消监听用户登录状态变化
var nc = NSNotificationCenter.defaultCenter();
nc.removeObservernameobject(delegate,"GKPlayerAuthenticationDidChangeNotificationName",null);
plus.ios.deleteObject(nc);
plus.ios.deleteObject(delegate);
delegate = null;
}
复制代码
注意
提交到云平台打包时需要添加Game Center API的系统库framework才能正确调用在HBuilder工程中双击应用的“manifest.json”文件切换到“代码视图”中在plus->distribute->apple->frameworks节点下添加要引用的系统Framework
"apple": {
"devices": "universal",
"frameworks": [
"GameKit.framework"
]
}
复制代码
,如下图所示: HBuilder frameworks 2. 正式发布提交到AppStore时在配置苹果开发者网站上配置App ID需要选中“Game Center”服务 Game Center
##开发注意和建议用途 Native.js的运行性能仍然不比纯原生应用JS与Native之间的数据交换效率并不如在js内部的数据交换效率基于如上原因有几点开发建议
以标准web 代码为主当遇到web能力不足的时候调用Native.js。
以标准web 代码为主当遇到web性能不足的时候需要分析 if ((原生进行运算的效率-js与原生通讯的损耗)>纯web的效率){ 使用Native.js }else{ 还应该使用纯js }
应避免把程序设计为在短时间内并发触发Native.js代码
##调试 使用safari和chrome的控制台调试HBuilder的5+App时一样可以调试NJS对象即可以在浏览器控制台中查看各种原生对象的属性和方法如下图所示57行设了断点watch了Intent对象并在右边展开了该对象的所有属性方法 Chrome Debug 关于如何在浏览器控制台调试HBuilder的5+App请参考HBuilder的5+App开发入门教程。
##开发资源 iOS 官方在线文档https://developer.apple.com/library/ios/navigation/ Android 官方在线文档https://developer.android.com/reference/packages.html 演讲视频http://v.youku.com/v_show/id_XNzYzNTcwNDI4.html
##高级API 有前述的常用API已经可以完成各项业务开发。此处补充的高级API是在熟悉NJS后为了提升性能而使用的API。高级API无法直接用“.”操作符使用原生对象的方法在debug时也无法watch原生对象但高级API性能高于常规API。 虽然导入类对象plus.android.importClass和plus.ios.importClass可以方便的通过“.”操作符来访问对象的常量、调用对象的方法,但导入类对象也需要消耗较多的系统资源,所以在实际开发时应该尽可能的减少导入类对象,以提高程序效率。可以参考以下依据进行判断:
如导入的类特别复杂,继承自很多基类,方法和属性特别多则考虑不导入类;
对导入类是否需要频繁操作若导入类仅是为了实例化并作为调用其它API的参数则不应该导入类
在同一页面中是否导入了很多类?如果导入太多则需要考虑减少导入类的数目。
如果我们不导入类对象则无法通过new操作符实例化类对象这时可通过plus.ios.newObject()、plus.android.newObject()方法来创建实例对象,如下:
// iOS平台创建NSDictionary的实例对象
var ns = plus.ios.newObject( "NSDictionary" );
// Android平台创建Intent的实例对象
var intent = plus.android.newObject( "android.content.Intent" );
复制代码
API on Android
plus.android.newObject
不导入类对象直接创建类的实例对象,方法原型如下:
InstanceObject plus.android.newObject( String classname, Object...args );
复制代码
此方法对Native层中对类进行实例化操作创建一个类的实体并返回NJS层的实例对象。相比导入类对象后使用new操作符创建对象效率要高。
classname要创建实例对象的类名类名必须是完整的命名空间使用“.”分隔符如“android.app.AlertDialog”如果需要创建内部类对象需要使用“$”分割符如“android.app.AlertDialog$Builder”。如果指定的类名不存在则创建对象失败返回null。
args调用类构造函数的参数其类型和数目必须与Native层Java类构造函数区配否则无法创建类对象将返回null。
注意:由于没有导入类对象,所以通过此方法创建的实例对象无法通过“.”操作符直接调用对象的方法而必须使用plus.android.invoke方法来调用。
示例:
不导入类创建实例对象 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 创建对象的实例
NjsHello hello = new NjsHello();
//...
}
//...
}
复制代码
NJS代码
// 不调用plus.android.importClass("io.dcloud.NjsHello")导入类NjsHello
// 创建对象的实例
var hello = plus.android.newObject( "io.dcloud.NjsHello" );
// ...
复制代码
plus.android.getAttribute
不导入类对象,则无法通过类对象并访问类的静态属性,需调用以下方法获取类的静态属性值,方法原型如下:
Object plus.android.getAttribute( String|Object obj, String name );
复制代码
此方法也可以获取类对象或实例对象的属性值,如果是类对象获取的则是类的静态属性,如果是实例对象则获取的是对象的非静态属性。
obj若是String类型表示要获取静态属性值的类名类名必须是完整的命名空间使用"."分割若是ClassObject类型表示要获取静态属性的类对象若是InstanceObject类型表示要获取属性值的实例对象。
name要获取的属性名称如果指定的属性名称不存在则获取属性失败返回null。
注意同样导入类对象后也可以调用此方法obj参数类型为ClassObject时其作用与ClassObject.plusSetAttribute方法一致。obj参数类型为InstanceObject时其作用与InstanceObject.plusSetAttribute方法一致。
示例:
不导入类对象获取类的静态常量属性 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 获取类的静态常量属性
int type = NjsHello.CTYPE;
System.out.printf( "NjsHello Final's value: %d", type ); // 输出“NjsHello Final's value: 1”
// 获取类的静态属性
int count = NjsHello.count;
System.out.printf( "NjsHello Static's value: %d", count ); // 输出“NjsHello Static's value: 0”
//...
}
//...
}
复制代码
NJS代码
// 不调用plus.android.importClass("io.dcloud.NjsHello")导入类NjsHello
// 访问类的静态常量属性
var type = plus.android.getAttribute( "io.dcloud.NjsHello", "CTYPE" );
console.log( "NjsHello Final's value: "+type ); // 输出“NjsHello Final's value: 1”
// ...
复制代码
不导入类对象创建实例对象并获取其name属性值 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 创建对象的实例
NjsHello hello = new NjsHello();
// 获取其name属性值
String name = hello.name;
System.out.printf( "NjsHello Object's name: %s", name ); // 输出“NjsHello Object's name: Tester”
//...
}
//...
}
复制代码
NJS代码
// 不调用plus.android.importClass("io.dcloud.NjsHello")导入类NjsHello
// 创建对象的实例
var hello = plus.android.newObject( "io.dcloud.NjsHello" );
// 获取其name属性值
var name = plus.android.getAttribute( hello, "name" );
console.log( "NjsHello Object's name: "+name ); // 输出“NjsHello Object's name: Tester”
// ...
复制代码
plus.android.setAttribute
若没有导入类对象,则无法通过类对象设置类的静态属性值,需调用以下方法设置类的静态属性值,方法原型如下:
void plus.android.setAttribute( String|Object obj, String name, Object value );
复制代码
此方法也可以设置类对象或实例对象的属性值,如果是类对象设置的则是类的静态属性,如果是实例对象则设置的是对象的非静态属性。
obj若是String类型表示要设置静态属性值的类名类名必须是完整的命名空间使用"."分割若是ClassObject类型表示要设置静态属性的类对象若是InstanceObject类型表示要设置属性值的实例对象。
name要设置的属性名称如果指定的属性名称不存在则设置属性失败返回null。
value要设置的属性值其类型必须与Native层obj对象的属性区配否则设置操作不生效将保留以前的值。
注意同样导入类对象后也可以调用此方法obj参数类型为ClassObject时其作用与ClassObject.plusSetAttribute方法一致。obj参数类型为InstanceObject时其作用与InstanceObject.plusSetAttribute方法一致。
示例:
不导入类对象设置类的静态属性值 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 设置类的静态属性值
NjsHello.count = 2;
System.out.printf( "NjsHello Static's value: %d", NjsHello.count ); // 输出“NjsHello Static's value: 2”
//...
}
//...
}
复制代码
NJS代码
// 不调用plus.android.importClass("io.dcloud.NjsHello")导入类NjsHello
// 设置类的静态属性值
plus.android.setAttribute( "io.dcloud.NjsHello", "count", 2 );
console.log( "NjsHello Static's value: "+plus.android.getAttribute("io.dcloud.NjsHello","count") ); // 输出“NjsHello Static's value: 2”
// ...
复制代码
导入类对象创建实例对象并设置其name属性值 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 创建对象的实例
NjsHello hello = new NjsHello();
// 设置其name属性值
hello.name = "Tester";
System.out.printf( "NjsHello Object's name: %s", hello.name ); // 输出“NjsHello Object's name: Tester”
//...
}
//...
}
复制代码
NJS代码
// 不调用plus.android.importClass("io.dcloud.NjsHello")导入类NjsHello
// 创建对象的实例
var hello = plus.android.newObject( "io.dcloud.NjsHello" );
// 设置其name属性值
plus.android.setAttribute( hello, "name", "Tester" );
console.log( "NjsHello Object's name: "+hello.plusGetAttribute("name") ); // 输出“NjsHello Object's name: Tester”
// ...
复制代码
plus.android.invoke
若没有导入类对象,则无法通过实例对象的“.”操作符调用其成员方法,需通过以下方法调用实例对象的成员方法,方法原型如下:
Object plus.android.invoke( String|Object obj, String name, Object... args );
复制代码
此方法也可以调用类对象或实例对象的方法如果是类对象则调用的是类的静态方法如果是实例对象则调用的是对象的普通成员方法。函数返回值是调用Native层方法运行后的返回值Native对象的方法无返回值则返回undefined。
obj若是String类型表示要调用静态方法的类名类名必须包含完整的包名若是ClassObject类型表示要调用静态方法的类对象若是InstanceObject类型表示要调用成员方法的实例对象。
name要调用的方法名称如果指定的方法不存在则调用方法失败返回值为null。
args调用方法的参数其类型和数目必须与Native层对象方法的函数区配否则无法调用对象的方法将返回null。
注意:同样导入类对象后也可以调用此方法,其作用与通过类对象或实例对象的“.”操作符调用方法作用一致。
示例: 1不导入类对象调用类的静态方法 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 调用类的静态方法
NjsHello.testCount();
//...
}
//...
}
复制代码
NJS代码
// 不调用plus.android.importClass("io.dcloud.NjsHello")导入类NjsHello
// 调用类的静态方法
plus.android.invoke( "io.dcloud.NjsHello", "testCount" );
// ...
复制代码
不导入类对象创建实例对象并调用其updateNmae方法 Java代码
import io.dcloud.NjsHello;
//...
public class Test {
public static void main( String args[] ) {
// 创建对象的实例
NjsHello hello = new NjsHello();
// 调用updateName方法
hello.updateName( "Tester" );
System.out.printf( "NjsHello Object's name: %s", name ); // 输出“NjsHello Object's name: Tester”
//...
}
//...
}
复制代码
NJS代码
// 不调用plus.android.importClass("io.dcloud.NjsHello")导入类NjsHello
// 创建对象的实例
var hello = plus.android.newObject( "io.dcloud.NjsHello" );
// 调用updateName方法
plus.android.invoke( hello, "updateName", "Tester" );
console.log( "NjsHello Object's name: "+hello.getAttribute("name") ); // 输出“NjsHello Object's name: Tester”
// ...
复制代码
完整API文档参考HTML5+ API - Native.js for Android
API on iOS
plus.ios.newObject
不导入类对象直接创建类的实例对象,方法原型如下:
InstanceObject plus.ios.newObject( String classname, Object..args );
复制代码
此方法会在Native层中对类进行实例化操作创建一个类的实体并返回NJS层的类实例对象。相比导入类对象后使用new操作符创建对象效率要高。
classname要创建实例对象的类名如果指定的类名不存在则创建对象失败返回null。
args调用类构造函数的参数其类型和数目必须与Native层对象构造函数区配否则无法创建类对象将返回null。
注意:由于没有导入类对象,所以通过此方法创建的实例对象无法通过“.”操作符直接调用对象的方法而必须使用plus.ios.invoke方法来调用。classname参数值为“@selector”表示需要创建一个函数指针对象与Objective-C中的@selector指令功能相似args参数为函数的名称此时函数的名称需要包含“”字符。
示例:
不导入类创建实例对象 Objective-C代码
#import "njshello.h"
int main( int argc, char *argv[] )
{
// 创建对象的实例
NjsHello* hello = [[NjsHello alloc] init];
// ...
}
复制代码
NJS代码
// 未导入“NjsHello”类
// 创建对象的实例
var hello = plus.ios.newObject( "NjsHello" );
// ...
复制代码
plus.ios.invoke
若没有导入类对象,则无法通过实例对象的“.”操作符调用其成员方法,需通过以下方法调用实例对象的成员方法,方法原型如下:
Object plus.ios.invoke( String|Object obj, String name, Object... args );
复制代码
此方法也可以调用类对象或实例对象的方法如果是类对象则调用的是类的静态方法如果是实例对象则调用的是对象的普通成员方法。函数返回值是调用Native层方法运行后的返回值Native对象的方法无返回值则返回undefined。
obj若是String类型表示要调用静态方法的类名类名必须包含完整的包名若是ClassObject类型表示要调用静态方法的类对象若是InstanceObject类型表示要调用成员方法的实例对象。
name要调用的方法名称必须保留方法名称中的“”字符如果指定的方法不存在则调用方法失败返回值为null。
args调用方法的参数其类型和数目必须与Native层对象方法的函数区配否则无法调用对象的方法将返回null。
注意:同样导入类对象后也可以调用此方法,其作用与通过类对象或实例对象的“.”操作符调用方法作用一致。
示例:
不导入类创建实例对象并调用updateName方法 Objective-C代码
#import "njshello.h"
int main( int argc, char *argv[] )
{
// 创建对象的实例
NjsHello* hello = [[NjsHello alloc] init];
// 调用updateName方法
[hello updateName:@"Tester"];
NSLog(@"NjsHello Object's name: %@",hello.name); // 输出“NjsHello Object's name: Tester”
// ...
}
复制代码
NJS代码
// 未导入“NjsHello”类
// 创建对象的实例
var hello = plus.ios.newObject( "NjsHello" );
// 调用updateName方法
plus.ios.invoke( hello, "updateName", "Tester" );
console.log( "NjsHello Object's name: "+hello.getAttribute("name") ); // 输出“NjsHello Object's name: Tester”
// ...
复制代码
完整API文档参考HTML5+ API - Native.js for iOS
性能优化
调整代码结构优化
前面章节中我们介绍如何通过NJS调用Native API来显示系统提示框在真机运行时会发现第一次调用时会有0.5s左右的延时再次调用则不会延时。这是因为NJS中导入类对象操作会花费较长的时间再次调用时由于类对象已经导入过会能很快执行完毕。因此可以调整代码结构进行优化在页面打开后触发的“plusready”事件中进行类对象的导入操作从而避免第一次调用的延时。
Android平台调整NJS代码结构如下
// 保存Android导入对象和全局环境对象
var AlertDialog=null,mainActivity=null;
// H5+事件处理
document.addEventListener("plusready",function(){
switch ( plus.os.name ) {
case "Android":
// 程序全局环境对象内部自动导入Activity类
mainActivity = plus.android.runtimeMainActivity();
// 导入AlertDialog类
AlertDialog = plus.android.importClass("android.app.AlertDialog");
break;
default:
break;
}
},false);
//...
/**
* 在Android平台通过NJS显示系统提示框
*/
function njsAlertForAndroid(){
// 创建提示框构造对象构造函数需要提供程序全局环境对象通过plus.android.runtimeMainActivity()方法获取
var dlg = new AlertDialog.Builder(mainActivity);
// 设置提示框标题
dlg.setTitle("自定义标题");
// 设置提示框内容
dlg.setMessage("使用NJS的原生弹出框可自定义弹出框的标题、按钮");
// 设置提示框按钮
dlg.setPositiveButton("确定(或者其他字符)",null);
// 显示提示框
dlg.show();
}
//...
复制代码
iOS平台调整NJS代码结构如下
// 保存iOS平台导入的类对象
var UIAlertView=null;
// H5+事件处理
document.addEventListener("plusready",function(){
switch ( plus.os.name ) {
case "iOS":
// 导入UIAlertView类
UIAlertView = plus.ios.importClass("UIAlertView");
break;
default:
break;
}
},false);
//...
/**
* 在iOS平台通过NJS显示系统提示框
*/
function njsAlertForiOS(){
// 创建UIAlertView类的实例对象
var view = new UIAlertView();
// 设置提示对话上的内容
view.initWithTitlemessagedelegatecancelButtonTitleotherButtonTitles("自定义标题" // 提示框标题
, "使用NJS的原生弹出框可自定义弹出框的标题、按钮" // 提示框上显示的内容
, null // 操作提示框后的通知代理对象,暂不设置
, "确定(或者其他字符)" // 提示框上取消按钮的文字
, null ); // 提示框上其它按钮的文字设置为null表示不显示
// 调用show方法显示提示对话框
view.show();
}
//...
复制代码
使用高级API优化
前面章节中我们提到导入类对象会消耗较多的系统资源导入过多的类对象会影响性能。在高级API中提供一组接口可以在不导入类对象的情况下调用Native API从而提升代码运行性能。
Android平台使用高级API优化代码如下
// 保存Android导入对象和全局环境对象
var mainActivity=null;
// H5+事件处理
document.addEventListener("plusready",function(){
switch ( plus.os.name ) {
case "Android":
// 程序全局环境对象内部自动导入Activity类
mainActivity = plus.android.runtimeMainActivity();
break;
default:
break;
}
},false);
//...
/**
* 在Android平台通过NJS显示系统提示框
*/
function njsAlertForAndroid(){
// 由于Builder类是android.app.AlertDialog类的内部类这里需要使用$符号分割
var dlg = plus.android.newObject("android.app.AlertDialog$Builder",mainActivity);
// 设置提示框标题
plus.android.invoke(dlg,"setTitle","自定义标题");
// 设置提示框内容
plus.android.invoke(dlg,"setMessage","使用NJS的原生弹出框可自定义弹出框的标题、按钮");
// 设置提示框按钮
plus.android.invoke(dlg,"setPositiveButton","确定(或者其他字符)",null);
// 显示提示框
plus.android.invoke(dlg,"show");
}
//...
复制代码
iOS平台使用高级API优化代码如下
/**
* 在iOS平台通过NJS显示系统提示框
*/
function njsAlertForiOS(){
// 创建UIAlertView类的实例对象
var view = plus.ios.newObject("UIAlertView");
// 设置提示对话上的内容,这里的方法名称中必须包含':'字符
plus.ios.invoke(view,"initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:"
,"自定义标题" // 提示框标题
, "使用NJS的原生弹出框可自定义弹出框的标题、按钮" // 提示框上显示的内容
, null // 操作提示框后的通知代理对象,暂不设置
, "确定(或者其他字符)" // 提示框上取消按钮的文字
, null ); // 提示框上其它按钮的文字设置为null表示不显示
// 调用show方法显示提示对话框在JS中使用()语法调用对象的方法
plus.ios.invoke(view,"show");
}
//...