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閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容