天天看点

ionic自定义插件

ionic是一个运行在webview上的应用,但是很多功能js搞不定,免不了本地代码的支持。

ionic在native支持这块直接用的cordova,cordova有一套webview里js代码与native代码交互的方案,这个就是cordova plugin。

    • 什么是cordova plugin
    • 如何写一个自己的插件
        • 初始化插件结构
        • 编写插件的 js api
        • 编写native代码
        • native代码如何在项目工程里生效
        • 如何找到native入口类
      • 如何在项目工程里调用插件的js方法
        • 如何在接口中使用Promise
        • 如何方便的编写插件native代码

什么是cordova plugin

一个cordova plugin基本就长这样:

ionic自定义插件

他是一个完整的功能模块,并且在js层向外提供服务。

它包含 javascript代码,也包含native代码。javascript代码向程序提供调用,方法调用时,调用信息会通过 cordova 的jssdk传入到native代码。

所以说,它的核心是js,native之间的调用,其实就是webview的jssdk。

当将插件加入工程时,插件中的js代码,native代码都会被copy到工程的相应目录下,这样程序运行时,你的程序就可以成功调用到这个插件的功能。

目前,cordova已经有大量的插件,如sqlite,camera , video , 二维码 等等,可以在下面几个地方找。

ionic native api list

cordova plugin center

如何写一个自己的插件

初始化插件结构

需要使用一个工具plugman

npm install -g plugman

创建一个空插件

plugman create –name [dir] –plugin_id [id] –plugin_version 1.0.0

这样,一个空的插件结构就创建好了。

ionic自定义插件
ionic自定义插件

编写插件的 js api

插件的目的就是在js层向外提供服务,所以我们先写这个文件。

可以看到www目录结构下的那个js文件,在里面编写调用方法。

var exec = require('cordova/exec');

exports.callNative = function(arg0, success, error) {
    exec(success, error, "plugin-name", "callNative", [arg0]);
};
           

这里导出了一个叫做 callNative的方法,你可以在程序的ts代码中调用它。它接受参数,包括回调。你可以根据自己的需要定义自己的接口。

这个方法调用了cordova的exec方法,就是这个方法将你的调用信息传递给native代码。

我们仔细看一看这个方法:

exec(success, error, plugin-name, method-name, [arg0]);
  • success:成功后的回调
  • error:失败回调
  • plugin-name: 这里替换成你的插件名。cordova 运行时维护了一个插件列表,就是根据这个值来路由到你的插件。在plugin.xml中配置。
//plugin.xml
<platform name="android">
    <config-file parent="/*" target="res/xml/config.xml">
        <feature name="bpdriver”> 
            <param name="android-package" value="blueprint/plugin/driver/driver" />
        </feature>
    </config-file>
</platform>
           

这里的bpdriver就是你的插件名,cordova.exec方法使用。

这个插件名时配置在android下的,ios下也有一个,建议配成一样的。而且最好和 plugin—>name 配置成一样的。

  • method-name:方法名,这个参数会传递给native方法。
  • [arg0]:这里是一个数组类型的参数,传递给native方法。

编写native代码。

首先要增加平台

plugman platform add –platform_name android

plugman platform add –platform_name ios

调用

plugman platform add

时,plugman帮大家生成了native入口类示例.

我只说一下android的。即图上的那个Driver.java(具体名称跟这个不一样,具体要看你的插件工程名)

public class Driver extends CordovaPlugin {
    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        if (action.equals("callNative")) {
            Log.d("TAG" , "callNative");
            return true;
        }
        return false;
    }
}
           

这个类我叫他native入口类,因为之前写的 js接口类中的cordova.exec调用,最后会调用到这个类的 execute方法。

这个类一定要继承了CordovaPlugin。

我们来看一看参数对应关系

corodva.exec(success, error, plugin-name, method-name, [arg0]);

public boolean execute(String action, JSONArray args, CallbackContext callbackContext)

ionic自定义插件

- cordova.exec参数plugin-name,用于定位到你写的插件,

- method-name 传入到 execute 中的 action。

- [arg0]数组,传入到 execute 中的 args。

- callbackContext中有一系列

success(xxx)

,

error(xxx)

方法,调用这些方法,最后回调用到corodva.exec 传入的 success , error 回调。

到现在为止, 插件里的 js方法调用 —> native 方法 —> js回调接口被调用 这一个流程就已经通了。

这一段流程其实就是一个cordova的jssdk。

cordova jssdk的原理?

android的是通过向webview.addJavascriptInterface的方式.

SystemExposedJsApi exposedJsApi = new SystemExposedJsApi(bridge);
webView.addJavascriptInterface(exposedJsApi, "_cordovaNative");
           

ios的我不懂,谁知道请不吝回复。

到现在为止,整个流程还少两步:

1. 插件native代码如何在项目中生效?

2. 如何在项目工程里调用插件的js代码?

native代码如何在项目工程里生效?

其实plugin之所以能生效,是因为cordova帮你把代码都copy到工程里了,包括js和native代码。

这里有两个问题:

1. 如何将native代码copy到相应的工程目录下?

2. 如何找到native入口类?

cordova的脚本已经帮我们做了所有的事情,添加插件或添加平台时,会自动将插件的native代码,copy到相应工程里。但是,我们需要在 plugin.xml中配置好。

这里以android来讲,ios也是相同的思路。

//plugin.xml中的一段
<platform name="android">
    <source-file src="src/android/Driver.java" target-dir="src/blueprint/plugin/driver" />
</platform>
           

source-file标签配置了将native代码copy到相应的工程目录。

src 填写在native代码在插件中的位置,可以是文件,也可以是文件夹。

target-dir 是指 复制到工程里的目录。

类似的标签还有 header-file , resource-file。

这个copy有两个时机起作用

1. 将插件添加到平台时,将文件从插件copy到相应平台的工程。

2. 将插件从平台移除时,将文件从相应平台删除。

如何找到native入口类?

//plugin.xml中的一段
<platform name="android">
   <feature name=“bpdriver">
        <param name="android-package" value=“blueprint.plugin.driver.Driver" />
    </feature>
</platform>
           

这一段,配置了android的native入口类的类名。

ios的配置类似。

如何在项目工程里调用插件的js方法?

首先,要知道你这个插件js调用对像在哪里?

//plugin.xml
<js-module name="bpdriver" src="www/driver.js">
    <clobbers target="cordova.plugins.bpdriver" />
</js-module>
           

clobbers配置了这个对象运行时的位置。

如果你的工程是js写的,那么,你在工程里可以这么调用

window.cordova.plugins.bpdriver.callNative("hello world!",(success)=>{

},(err)=>{

});
           

如果你的工程是ts写的,怎么调用?

方案一: 将window声明为any类型,使编译器忽略类型检查

let w = window as any;

w.cordova.plugins.bpdriver.call(“hello world!”,(success)=>{

},(err)=>{

});

方案二:给插件写声明文件

在插件根目录下,增加一个ts声明文件。

declare interface DriverPlugin {
    callNative(data : any , success : (data : any) => void ,err : (data : any) => void);
}

           

然后在工程里引用这个声明文件

可以在 project/src/declareations.d.ts 中

/// <reference path="../plugins/pluginname/DriverPlugin.d.ts" />
           

在调用处

let w = window as any;
let driver: DriverPlugin = w.cordova.plugins.bpdriver;
driver.call("hello world!",(success)=>{
    },(err)=>{
    });
}
           

如何在接口中使用Promise?

大家调用ionic插件,都知道ionic插件的异步调用都是Promise的,很方便,那么咱们的自定义插件可不可以也使用Promise?

方案一?

如下:

var exec = require(‘cordova/exec’);

exports.call = function(arg0) {

return new Promise((resolve , reject) =>{

exec(resolve, reject, “bpdriver”, “callPromise”, [arg0]);

});

};

很遗憾,不可以!因为Ionic工程的ts编译选项可以看一下,target=es5,而Promise是es6的标准。

在ts主工程里可以使用Promise是因为ts编译器会吧Promise转换为callback调用方式。

方案二?

插件接口文件直接用ts写行不行?

很遗憾,不可以!因为cordova框架并没有对插件ts做支持。都到手机里了还是ts代码,明显用不了。

那为什么ionic的插件都是Promise的?

ionic 之所以能用Promise调用,是因为ionic-native工程里针对每一个插件都写一个*.ts类,这个类将callback方式转换为Promise方式。大家也可以在自己的工程里写一个ts的包装类,将调用都转换为Promise的方式。

如何方便的编写插件native代码?

说实在的,大家也不可能直接就在vscode上这么啪啪啪,实在伤不起呀。

当然得是 用 android stuido 在 platforms/android 下开发。用xcode在platforms/ios下开发。

开发过程中切记不要运行

ionic build

ionic run

,他会把plugins/xxx下的代码copy到platform/下,冲掉你刚写的代码,你会哭的。

开发完记得将代码copy到插件目录,不然等于白干。

手动copy太麻烦,容易出问题,还是写个脚本。

修改插件js,plugin.xml 时,需要更新插件,没有直接的命令,只好删除再添加插件。

cordova plugin remove blueprint-plugin-driver && cordova plugin add ../cordovaplugin/driver