前言
uni-app是一个开源前端框架,是用vue.js开发的,可以实现跨平台的开发。地址:https://github.com/dcloudio/uni-app
而Native.js是使用uni-app开发时可以用到的一种开发技术,以下介绍摘自《5+ App开发Native.js入门指南》:http://ask.dcloud.net.cn/article/88
本文只是对上面这个文章的一些摘抄和提炼,方便Android开发者参考。
Native.js技术,简称NJS,是一种将手机操作系统的原生对象转义,映射为JS对象,在JS里编写原生代码的技术。
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应用。
再次强调,Native.js不是一个js库,不需要下载引入到页面的script中,也不像nodejs那样有单独的运行环境,Native.js的运行环境是集成在5+runtime里的,使用HBuilder打包的app或流应用都可以直接使用Native.js。
简言之,Native.js可以实现用js语法来调用Android或者ios的功能,以实现一处开发,多处运行的目的。使用HBuilder这个开发工具完成功能开发后,需要把打包数据放入Android项目或者ios项目里,然后就可以编译得到Android或者ios安装包。
HBuilder工具下载地址:https://www.dcloud.io/hbuilderx.html
本文主要介绍Native.js如何配合Android开发。
简单示例
以一个简单的例子说明一下Native.js的使用:
如果Android 项目里有个工具类ToastUtil.java是用来管理Toast的,其中有个静态方法用来显示Toast:
package com.example.demo;
public static void show(Context ctx, CharSequence msg, int duration) {
XXX
}
在Android项目里,如果是这样用的:
ToastUtil.show(MainActivity.this, "提醒一下", Toast.LENGTH_LONG);
对应到了native.js里,写法就是这样:
var ToastUtil = plus.android.importClass("com.example.demo.ToastUtil");
var Toast = plus.android.importClass("android.widget.Toast");
ToastUtil.show(plus.android.runtimeMainActivity(), "提醒一下", Toast.LENGTH_LONG);
其中plus.android.importClass是用来导入类的,然后由于ToastUtil类的show方法是静态方法,Toast类的LENGTH_LONG是静态常量,所以都是可以用类后面跟点号来使用的。plus.android.runtimeMainActivity()是用来获取当前的activity。详细语法后面会讲,这里先大概有个印象。
当然上面的写法如果运行在ios平台上就会出错了,所以在native.js里,得针对不同操作系统做判断:
switch ( plus.os.name ) {
case "Android":
// Android平台: plus.android.*
var ToastUtil = plus.android.importClass("com.example.demo.ToastUtil");
var Toast = plus.android.importClass("android.widget.Toast");
ToastUtil.show(plus.android.runtimeMainActivity(), "提醒一下", Toast.LENGTH_LONG);
break;
case "iOS":
// iOS平台: plus.ios.*
break;
default:
// 其它平台
break;
}
如果还有兴趣继续看下去的话,接下来就是详细讲解了。
用法详解
以一个更全面的例子来讲解,下面是一个测试类:
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;
}
}
这是上面的代码中用到的接口类:
package io.dcloud;
// 定义接口NjsHelloEvent
public interface NjsHelloEvent {
public void onEventInvoked( String name );
}
下面看如何在native.js中使用这个测试类:
· 导入类后获取类的静态常量属性
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 获取类的静态常量属性
var type = NjsHello.CTYPE;
· 导入类后调用类的静态方法
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 调用类的静态方法
NjsHello.testCount();
· 导入类后获取类的静态变量值
// 导入测试类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”
· 导入类后设置类的静态属性值
// 导入测试类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”
· 导入类创建实例对象,调用对象的方法
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 创建NjsHello的实例对象
var hello = new NjsHello();
// 调用对象的方法
hello.updateName( "Tester" );
// ...
· 导入类创建实例对象,获取对象的常量属性
// 导入测试类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”
// ...
· 导入类创建实例对象,获取对象的属性值
// 导入测试类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”
// ...
· 导入类创建实例对象,设置对象的属性值
// 导入测试类NjsHello
var NjsHello = 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”
// ...
· 实现接口,并触发接口中函数的运行
// 导入测试类NjsHello
var NjsHello = plus.android.importClass("io.dcloud.NjsHello");
// 实现接口“NjsHelloEvent”对象
var hevent = plus.android.implements( "io.dcloud.NjsHelloEvent", {
"onEventInvoked":function( name ){
console.log( "Invoked Object’s name: "+name ); // 输出“Invoked Object’s name: Tester”
}
} );
// 创建对象的实例
var hello = new NjsHello();
// 调用updateName方法
hello.updateName( "Tester" );
// 设置监听对象
hello.setEventObserver( hevent );
// 调用test方法,触发代理事件
hello.test(); // 触发上面定义的匿名函数运行
// ...
高级用法
有前述的常用API,已经可以完成各项业务开发。此处补充的高级API,是在熟悉NJS后,为了提升性能而使用的API。高级API无法直接用“.”操作符使用原生对象的方法,在debug时也无法watch原生对象,但高级API性能高于常规API。
虽然导入类对象(plus.android.importClass和plus.ios.importClass)后,可以方便的通过“.”操作符来访问对象的常量、调用对象的方法,但导入类对象也需要消耗较多的系统资源,所以在实际开发时应该尽可能的减少导入类对象,以提高程序效率。
如果我们不导入类对象则无法通过new操作符实例化类对象,这时可通过plus.ios.newObject()、plus.android.newObject()方法来创建实例对象。
注意:由于没有导入类对象,所以通过此方法创建的实例对象无法通过“.”操作符直接调用对象的方法,而必须使用plus.android.invoke方法来调用。
· 不导入类创建实例对象
// 不调用plus.android.importClass("io.dcloud.NjsHello")导入类NjsHello
// 创建对象的实例
var hello = plus.android.newObject( "io.dcloud.NjsHello" );
// ...
· 不导入类对象获取类的静态常量属性
// 不调用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属性值
// 不调用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.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属性值
// 不调用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.importClass("io.dcloud.NjsHello")导入类NjsHello
// 调用类的静态方法
plus.android.invoke( "io.dcloud.NjsHello", "testCount" );
// ...
· 不导入类对象,创建实例对象,并调用其updateNmae方法
在这里插入代码片// 不调用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”
// ...
关于Native.js调用其它Android系统功能,可以看这里:https://ask.dcloud.net.cn/article/114
本文是从这篇讲解里提炼出来的,如果有问题,可以查看原文:
http://ask.dcloud.net.cn/article/88