您现在的位置是:网站首页> 小程序设计

Native.js入门指南

摘要

uniapp快速回顾

在线文档

先入例子

Android使用

IOS调用

uniapp另一种调用原生


当使用uni-app开发基于HBuilderX的混合应用时,你可以使用plus.ios.importClass方法

来在uni-app中调用iOS的类对象函数。下面是一个具体的例子:

首先,在你的uni-app项目中,打开manifest.json文件,确保已经开启了plus模块,例如:


"plus": {

  "modules": {

    "ios": {

      "description": "iOS特有API",

      "native": true

    }

  }

}

在你的uni-app页面中,通过plus.ios.importClass方法来导入iOS的类对象。例如,在index.vue文件中:

vue

复制

<template>

  <view class="content">

    <button @click="callNativeFunction">调用iOS类对象函数</button>

  </view>

</template>


<script>

export default {

  methods: {

    callNativeFunction() {

      const YourClass = plus.ios.importClass('YourClass')

      const instance = YourClass.new()

      instance.yourFunction()

      

      plus.ios.deleteObject(instance)

    }

  }

}

</script>

在上面的代码中,我们通过plus.ios.importClass方法导入了名为YourClass的iOS类对象。然后,我们使用YourClass.new()创建了一个类对象实例,并调用了yourFunction函数。


请注意,plus.ios.deleteObject方法用于释放创建的iOS对象实例。


在iOS原生代码中,确保你的YourClass类存在,并实现了yourFunction函数。例如,在Objective-C中:

objective

复制

// YourClass.h


#import <Foundation/Foundation.h>


@interface YourClass : NSObject


- (void)yourFunction;


@end


// YourClass.m


#import "YourClass.h"


@implementation YourClass


- (void)yourFunction {

    NSLog(@"iOS类对象函数被调用");

}


@end

在上述示例中,我们假设你已经在iOS原生代码中实现了名为YourClass的类,并添加了yourFunction函数。

通过以上步骤,你可以在uni-app中使用plus.ios.importClass方法来导入iOS的类对象,并调用其中的函数。请确保在导入类对象后,使用正确的类名和函数名来调用对应的函数。


Android调用系统通讯录控件,native.js实现监听startActivityForResult后返回结果

var REQUESTCODE = 1000;  

main = plus.android.runtimeMainActivity();  

var Intent = plus.android.importClass('android.content.Intent');  

var ContactsContract = plus.android.importClass('android.provider.ContactsContract');  

var intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);  

main.onActivityResult = function(requestCode, resultCode, data) {   

  if (REQUESTCODE == requestCode) {  

    var phoneNumber = null;  

    var resultString = "";  

    var context = main;  

    plus.android.importClass(data);  

    var contactData = data.getData();  

    var resolver = context.getContentResolver();  

    plus.android.importClass(resolver);  

    var cursor = resolver.query(contactData, null, null, null, null);  

    plus.android.importClass(cursor);  

    cursor.moveToFirst();  

    var s_ret;  

    var givenName = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));  

    s_ret = givenName;  

    var contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));  

    var pCursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,  

     null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId,  

     null, null);  

    while (pCursor.moveToNext()) {  

     phoneNumber =   pCursor.getString( pCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));  

     s_ret += '\n' + phoneNumber;  

    }  

    alert(s_ret);  

    cursor.close();  

    pCursor.close();  

  }  

};  

main.startActivityForResult(intent, REQUESTCODE);


navtive.js发送消息

sendMessage1() {

 if (plus.os.name == "Android") {

//获取当前MainActivity

var main = plus.android.runtimeMainActivity();

//获取SystemService

var sManager = main.getSystemService("telephony_subscription_service");

console.log(sManager);

//获取所有卡列表

var subscriptionInfoList = plus.android.invoke(sManager,"getActiveSubscriptionInfoList");

//获取卡信息   

var sInfo = plus.android.invoke(subscriptionInfoList,"get",0);

//获取卡id

var id = plus.android.invoke(sInfo,"getSubscriptionId");

console.log(id);

//获取卡id获取SMSManagers对象

var managers = plus.android.invoke("android.telephony.SmsManager","getSmsManagerForSubscriptionId",id);

var eMessage = "哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈--------------";

//分割短信内容 短信规定不能大于70字,大于70会被分割,分开发送

var list = plus.android.invoke(managers,"divideMessage",eMessage);

//发送短信

var returns = plus.android.invoke(managers,"sendMultipartTextMessage","18829221189",null,list,null,null);

以监听手机飞行模式开关为例说明如何使用Native.js进行BroadcastReceiver广播

var receiver;  

main = plus.android.runtimeMainActivity(); //获取activity  

receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {  

    onReceive: function(context, intent) { //实现onReceiver回调函数  

        plus.android.importClass(intent);  

        console.log(intent.getAction());  

        result.textContent += '\nAction :' + intent.getAction();  

        main.unregisterReceiver(receiver);  

    }  

});  

var IntentFilter = plus.android.importClass('android.content.IntentFilter');  

var Intent = plus.android.importClass('android.content.Intent');  

var filter = new IntentFilter();  

filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); //监听飞行模式  

main.registerReceiver(receiver, filter); //注册监听 

在H5+ API 不能满足要求的情况下调用Native API

Native API具有平台依赖性,所以需要通过以下方式判断当前的运行平台

function judgePlatform(){  

    switch ( plus.os.name ) {  

        case "Android":  

        // Android平台: plus.android.*  

        break;  

        case "iOS":  

        // iOS平台: plus.ios.*  

        break;  

        default:  

        // 其它平台  

        break;  

    }  

}

类型转换表

类型转换表

类型Objective-CJavaJavaScript
基本数据byte/short/int/long/float/double/...byte/short/int/long/float/double/...Number
字符charcharString
字符串NSString/@""String/""String
数组@[1,2,3]/NSArraynew XXX[]InstanceObject
@interfaceclassClassObject
对象(实例)**InstanceObject
空对象nilnullnull
其它ProtocolInterfaceObject(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名称:”。

如:“(void)setPositionX:(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非常简单,基本步骤如下:

1.导入要使用到的类;

2.创建类的实例对象(或者调用类的静态方法创建);

3.调用实例对象的方法;

以下例子使用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+应用运行期自动创建的程序全局环境对象。



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名称:”。 如:“(void)setPositionX:(int)x Y:(int)y;”,方法的完整名称为“setPositionX:Y:” 调用时语法为:“[pos setPositionX:x Y:y];”。 在JS语法中函数名称不能包含“:”字符,所以OC对象的方法名映射成NJS对象方法名时将其中的“:”字符自动删除,上面方法名映射为“setPositionXY”,在NJS调用的语法为:“pos.setPositionXY(x,y);”。

常用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 );  

}

导入类对象

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();  

// ...


导入类后获取类的静态常量属性

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();  

// ...

导入类后获取类的静态属性值

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”  

// ...

导入类后设置类的静态属性值

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”  

// ...

plus.android.implements

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 Object’s name: "+name ); // 输出“Invoked Object’s name: Tester”  

}  

} );  

// 创建对象的实例  

var hello = new NjsHello();  

// 调用updateName方法  

hello.updateName( "Tester" );  

// 设置监听对象  

hello.setEventObserver( hevent );  

// 调用test方法,触发代理事件  

hello.test(); // 触发上面定义的匿名函数运行  

// ...

plus.android.runtimeMainActivity

调用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的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/");  

// ...

完整业务演示

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

    ]  

}


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"  

]  

}

开发注意和建议用途

Native.js的运行性能仍然不比纯原生应用;JS与Native之间的数据交换效率并不如在js内部的数据交换效率;基于如上原因,有几点开发建议:


以标准web 代码为主,当遇到web能力不足的时候,调用Native.js。

以标准web 代码为主,当遇到web性能不足的时候,需要分析,

if ((原生进行运算的效率-js与原生通讯的损耗)>纯web的效率){

使用Native.js

}else{

还应该使用纯js

}

应避免把程序设计为在短时间内并发触发Native.js代码

高级API

不导入类创建实例对象

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" );  

// ...


不导入类对象获取类的静态常量属性

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”  

// ...


不导入类对象设置类的静态属性值

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

不导入类对象,调用类的静态方法

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”  

// ...



在uni-app中,NJS(Native JavaScript)调用是指在前端页面中通过JavaScript代码调用原生(Native)功能和接口。NJS调用提供了一种在uni-app应用中与原生能力进行交互的方式,使得开发者可以利用JavaScript来调用设备的底层功能和特定接口。

下面是一个具体的uni-app NJS调用的例子:

在uni-app的前端页面中,你可以通过uni对象的invokeNativeMethod方法来进行NJS调用。例如,在index.vue文件中:

<template>

  <view class="content">

    <button @click="callNativeMethod">调用原生方法</button>

  </view>

</template>


<script>

export default {

  methods: {

    callNativeMethod() {

      uni.invokeNativeMethod('yourNativeMethod', { param1: 'Hello', param2: 123 }, (res) => {

        console.log('NJS调用结果:', res)

      })

    }

  }

}

</script>

在上述代码中,我们通过uni.invokeNativeMethod方法调用名为yourNativeMethod的原生方法,并传递了一个包含两个参数的对象。第三个参数是一个回调函数,用于接收原生方法的返回结果。

在原生代码中,你需要注册名为yourNativeMethod的方法,以便在NJS调用时被调用。例如,在iOS原生代码中:


// AppDelegate.m


#import "AppDelegate.h"

#import <UniPluginProtocol.h>


@interface AppDelegate () <UniPluginProtocol>


@end


@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // 注册插件

    [[UniPluginManager sharedInstance] registerPlugin:self];

    

    return YES;

}


#pragma mark - UniPluginProtocol


- (BOOL)invokeNativeMethod:(NSString *)method arguments:(id)arguments completion:(UniPluginCompletionBlock)completion {

    if ([method isEqualToString:@"yourNativeMethod"]) {

        // 处理yourNativeMethod方法的调用

        NSString *param1 = arguments[@"param1"];

        NSInteger param2 = [arguments[@"param2"] integerValue];

        

        NSLog(@"NJS调用参数: param1 = %@, param2 = %ld", param1, param2);

        

        // 执行你的原生逻辑,并返回结果给前端

        NSDictionary *result = @{@"message": @"Native方法调用成功"};

        completion(result, nil);

        

        return YES;

    }

    

    return NO;

}


@end

在上述代码中,我们实现了UniPluginProtocol协议,并注册了插件。在invokeNativeMethod:arguments:completion:方法中,我们判断调用的方法名是否为yourNativeMethod,并获取传递的参数进行处理。然后,我们执行原生逻辑,并将结果通过completion回调返回给前端。

通过以上步骤,你可以在uni-app中通过NJS调用的方式,调用原生方法并实现前端与原生功能的交互。请注意,具体的原生代码实现会根据不同平台(如iOS、Android)而有所区别,你需要根据目标平台进行相应的实现。


上一篇:uniapp快速回顾

下一篇:Flex布局快速总结

Top