天天看點

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