ionic插件

ionic是一个运行在webview上的应用,但是很多功能js搞不定,免不了本地代码的支持。
ionic在native支持这块直接用的cordova,cordova有一套webview里js代码与native代码交互的方案,这个就是cordova plugin。

什么是cordova plugin

一个cordova plugin基本就长这样:


20170311140259975.png

他是一个完整的功能模块,并且在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

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

20170311144154121.png

20170311150457981.png

编写插件的 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)

20170311163631765.png
  • 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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容