cordova 自定義外掛之完整流程
一.前期開發環境
1.android studio和xcode開發環境
2.安裝node.js
3.安裝plugman
4.命令工具環境(可以安裝git也可以使用系統自帶的工具,window的dos,ios的終端)
5.subline text3 主要用於編輯外掛的的檔案(當然也可以用notepad 看個人喜好 也可以用一些其它編輯工具)
二.建立工程
1.安裝cordova和plugman
使用npm命令:npm install -g cordova
npm install -g plugman
如果是mac上有可能安裝失敗,這是因為讀寫許可權問題,在命令前面加上sudo就好。
cordova安裝的是最新版本。
2.建立android或ios的cordova專案
雖然這一步沒必要寫 ,網上也有很多教程 ,但是為了整個流程的完整性 ,還是寫出來
命令步驟如下:
在這之前有一點細碎的事,個人習慣一定要把工程放在合適的位置
例如在window 的DOS 環境下,cd到相應的磁碟目錄在使用下面的命令(ios則直接在Desktop目錄下就可以了 也就是桌面上)
2.1 建立Hello工程
cordova create hello com.moke.hello Hello
第一個hello是建立的工程資料夾名 中間的com.moke.hello就不用多說了,Hello,工程名
2.2 新增開發環境平臺
首先得切換命令目錄到工程目錄,例如本例子就需要 cd hello到工程目錄中,然後執行 以下命令:
android環境:cordova platform add android ,ios環境:cordova platform add ios
會生出如下目錄(ios為例):
2.3 新增外掛
這一步可做可不做 ,但是命令還是要寫出來。 cordova plugin add ********* ,星號部分為外掛的地址 或者 自定義外掛的目錄地址
可以新增也可以刪除 cordova plugin rm ******** ,星號為外掛名 如果不知道外掛名 可以用命令檢視當前工程的外掛列表 cordova plugin list
2.4 最後就是編譯
cordova build ios或者android
三 自定義外掛
有時候github或者npm上的外掛不能滿足專案需求時 就需要自己自定義外掛
3.1建立外掛基本結構
先cmd到桌面或者任意磁碟目錄執行以下命令:
輸入 plugman create --name com.moke.TestPlugin --plugin_id com.moke.testPlugin --plugin_version 0.0.1
生成一個名字為com.moke.TestPlugin的外掛資料夾以及目錄為下:
3.2 外掛目錄配置
plugin.xml 是配置相關android ios wp等平臺的資訊,這是一個非常重要的配置檔案,在js中能否呼叫到外掛中的本地方法就需要看這個檔案中是否配置正確。
src資料夾:裡面放置的是各個平臺的類檔案以及一些lib庫,但是需要注意在src目錄下 要新建例如 命名為ios的資料夾 這個資料夾就放置的ios的.h 和.m的檔案以及ios環境下外掛所需要的第三方庫等,同等,放置android的java檔案需要建立命名為android的資料夾。
www資料夾:這個資料夾裡面有一個js檔案,是在3.1中建立外掛檔案時自動生成的。這個js的主要作用就是連結原生代碼的介面 通過訪問該js介面來呼叫src資料夾中不同平臺的本地方法
3.3 外掛配置詳細
3.3.1 以一個簡單demo為例子來表示相應配置資訊 在這建立了相應android平臺的hello.java 和ios平臺的HVPhello.h HVPhello.m檔案 主要實現了字串的顯示
hello.java檔案:
package com.moke.testPlugin;
import org.apache.cordova.*;
import org.json.JSONArray;
import org.json.JSONException;
public class Hello extends CordovaPlugin {
@Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
if (action.equals("greet")) {
String name = data.getString(0);
String message = "Hello, " + name;
callbackContext.success(message);
return true;
} else {
return false;
}
}
}
HVPhello.h HVPhello.m檔案
#import <Cordova/CDV.h>
@interface HWPHello : CDVPlugin
- (void) greet:(CDVInvokedUrlCommand*)command;
@end
#import "HWPHello.h"
@implementation HWPHello
- (void)greet:(CDVInvokedUrlCommand*)command
{
NSString* name = [[command arguments] objectAtIndex:0];
NSString* msg = [NSString stringWithFormat: @"Hello, %@", name];
CDVPluginResult* result = [CDVPluginResult
resultWithStatus:CDVCommandStatus_OK
messageAsString:msg];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
@end
備註:在本地外掛檔案中
java callbackContext 和 ios中的 sendPluginResult:result 都代表了將相應結果回撥到你的html中的js回撥方法中。
3.3.2 plugin.xml配置
<?xml version='1.0' encoding='utf-8'?>
<plugin id="com.moke.testPlugin" version="0.0.1" xmlns="http://apache.org/cordova/ns/plugins/1.0">
<name>TestPlugin</name>
<description>Cordova hello Plugin</description>
<license>Apache 2.0</license>
<keywords>cordova,hello</keywords>
<!--www資料夾下js的配置 主要作用是用於能夠找到該js檔案 其中clobbers中的target是用於你的h5應用呼叫js中的方法的變數 可以自定義該tag-->
<js-module name="com.moke.TestPlugin" src="www/com.moke.TestPlugin.js">
<clobbers target="TestPlugin" />
</js-module>
<!--android平臺的配置-->
<platform name="android">
<!--config-file 是把你android平臺的java檔案配置進去 feature中的name可以自定義-->
<config-file target="res/xml/config.xml" parent="/*">
<feature name="TestPlugin" >
<param name="android-package" value="com.moke.testPlugin.Hello"/>
<param name="onload" value="true" />
</feature>
</config-file>
<!--source-file 其中 src中的目錄是你外掛java檔案的目錄 target-dir是把你外掛的類檔案在cordova工程中的目錄,記住com/moke/testPlugin一定要是你自己的檔案的包名-->
<source-file src="src/android/Hello.java" target-dir="src/com/moke/testPlugin" />
</platform>
<!--ios平臺的配置-->
<platform name="ios">
<config-file target="config.xml" parent="/*">
<feature name="TestPlugin">
<param name="ios-package" value="HWPHello"/>
<param name="onload" value="true" />
</feature>
</config-file>
<!-- Plugin source code -->
<header-file src="src/ios/HWPHello.h" />
<source-file src="src/ios/HWPHello.m" />
</platform>
</plugin>
備註:在執行plugman命令生成的plugin檔案 在最開始是隻有<js-module> 和 <name>標籤的
所以平臺相關配置還是需要自己配置,具體配置的註解在程式碼中我已經標明。
3.3.3 www資料夾下的js配置:
var exec = require('cordova/exec');
<!-- msg 是傳遞的資料 success error 是回撥方法 其中 TestPlugin是plugin中配置的js中clobbers標籤中的target-->
<!--greet 是java檔案中excute中的action值,和.h中定義的greet方法, 記住 要保持一致。-->
exports.greet = function(msg, success, error) {
exec(success, error, "TestPlugin", "greet", [msg]);
};
備註:js是執行plugman自動生成的,但是其中的exports 和exec中的相應引數需要做一些改變,程式碼中做了註釋
4.外掛原生代碼的建立
外掛原生代碼邏輯和方法的編碼 也就是java檔案 和 .h .m 檔案的建立,可以在android studio 或者 xcode 中 載入相應平臺的cordova工程專案 ,在專案工程中做外掛原生代碼的編碼,然後把寫好的檔案再copy到外掛檔案中的src中相應資料夾下即可。
5.新增外掛。
先cmd到相應cordova目錄 然後執行 cordova plugin add xx/xx/xx/com.moke.TestPlugin 。
這時就可以看到在cordova工程中的外掛目錄中新增好的 com.moke.TestPlugin外掛
6.外掛呼叫
在你的cordova工程中的 html頁面用呼叫js方法 並且在js的function中寫入
var success = function(e){
alert(e);
}
var error = function(e){
alert(e);
}
TestPlugin.greet("Geek",success,error);
四最後一點外掛相應的配置
如果我們寫的外掛需要使用第三方庫那麼 第三方庫的配置怎麼辦?
我們以微信支付為例子 : 只做個簡單的例子配置展現。
plugin.xml配置
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="moke-plugin-wepay"
version="1.3.0">
<name>WeChatPay</name>
<description>Cordova wepay Plugin</description>
<license>Apache 2.0</license>
<keywords>cordova,pay,wechat</keywords>
<preference name="WECHATAPPID" />
<engines>
<engine name="cordova-android" version=">=4.0.0" />
</engines>
<platform name="ios">
<config-file target="config.xml" parent="/*">
<feature name="WeChatPay">
<param name="ios-package" value="CDVWeChatPayPlugin"/>
<param name="onload" value="true" />
</feature>
<preference name="WECHATAPPID" value="$WECHATAPPID"/>
</config-file>
<config-file target="*-Info.plist" parent="LSApplicationQueriesSchemes">
<array>
<string>weixin</string>
<string>wechat</string>
</array>
</config-file>
<config-file target="*-Info.plist" parent="NSAppTransportSecurity">
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
</config-file>
<config-file target="*-Info.plist" parent="CFBundleURLTypes">
<array>
<dict>
<key>CFBundleURLName</key>
<string>weixin</string>
<key>CFBundleURLSchemes</key>
<array>
<string>$WECHATAPPID</string>
</array>
</dict>
</array>
</config-file>
<js-module src="www/Wechatpay.js" name="WeChatPay">
<clobbers target="WeChatPay" />
</js-module>
<!-- Plugin source code -->
<header-file src="src/ios/CDVWeChatPayPlugin.h" />
<source-file src="src/ios/CDVWeChatPayPlugin.m" />
<!-- Wechat Official -->
<header-file src="src/ios/libs/OpenSDK1.7.4/WXApi.h" />
<header-file src="src/ios/libs/OpenSDK1.7.4/WXApiObject.h" />
<source-file src="src/ios/libs/OpenSDK1.7.4/libWeChatSDK.a" framework="true" />
<!-- Other required frameworks -->
<framework src="libz.tbd" />
<framework src="libsqlite3.0.tbd" />
<framework src="CoreTelephony.framework" />
<framework src="SystemConfiguration.framework" />
<framework src="Security.framework" />
<framework src="CFNetwork.framework" />
<framework src="libstdc++.6.tbd" />
</platform>
<platform name="android">
<js-module src="www/Wechatpay.js" name="WeChatPay">
<clobbers target="WeChatPay" />
</js-module>
<hook type="after_plugin_add" src="scripts/android-install.js" />
<hook type="after_plugin_install" src="scripts/android-install.js" />
<hook type="before_plugin_rm" src="scripts/android-install.js" />
<hook type="before_plugin_uninstall" src="scripts/android-install.js" />
<config-file target="res/xml/config.xml" parent="/*">
<feature name="WeChatPay" >
<param name="android-package" value="org.apache.cordova.pay.WeChatPayPlugin"/>
<param name="onload" value="true" />
</feature>
</config-file>
<source-file src="src/android/WeChatPayPlugin.java" target-dir="src/org/apache/cordova/pay" />
<source-file src="src/android/Utils.java" target-dir="src/org/apache/cordova/pay" />
<source-file src="src/android/libammsdk.jar" target-dir="libs" />
<info>
This plugin is only applicable for versions of cordova-android greater than 4.0. If you have a previous platform version, you do *not* need this plugin since the whitelist will be built in.
</info>
<config-file target="AndroidManifest.xml" parent="/*">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</config-file>
<config-file target="AndroidManifest.xml" parent="/manifest/application">
<activity
android:name=".wxapi.WXPayEntryActivity"
android:label="@string/launcher_name"
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</config-file>
</platform>
</plugin>
android-install.js
module.exports = function (context) {
var path = context.requireCordovaModule('path'),
fs = context.requireCordovaModule('fs'),
shell = context.requireCordovaModule('shelljs'),
projectRoot = context.opts.projectRoot,
plugins = context.opts.plugins || [];
// The plugins array will be empty during platform add
if (plugins.length > 0 && plugins.indexOf('cordova-plugin-wechat') === -1) {
return ;
}
var ConfigParser = null;
try {
ConfigParser = context.requireCordovaModule('cordova-common').ConfigParser;
} catch(e) {
// fallback
ConfigParser = context.requireCordovaModule('cordova-lib/src/configparser/ConfigParser');
}
var config = new ConfigParser(path.join(context.opts.projectRoot, "config.xml")),
packageName = config.android_packageName() || config.packageName();
// replace dash (-) with underscore (_)
packageName = packageName.replace(/-/g , "_");
console.info("Running android-install.Hook: " + context.hook + ", Package: " + packageName + ", Path: " + projectRoot + ".");
if (!packageName) {
console.error("Package name could not be found!");
return ;
}
// android platform available?
if (context.opts.cordova.platforms.indexOf("android") === -1) {
console.info("Android platform has not been added.");
return ;
}
var targetDir = path.join(projectRoot, "platforms", "android", "src", packageName.replace(/\./g, path.sep), "wxapi");
targetFiles = ["WXPayEntryActivity.java"];
if (['after_plugin_add', 'after_plugin_install'].indexOf(context.hook) === -1) {
// remove it?
targetFiles.forEach(function (f) {
try {
fs.unlinkSync(path.join(targetDir, f));
} catch (err) {}
});
} else {
// create directory
shell.mkdir('-p', targetDir);
// sync the content
targetFiles.forEach(function (f) {
fs.readFile(path.join(context.opts.plugin.dir, 'src', 'android', f), {encoding: 'utf-8'}, function (err, data) {
if (err) {
throw err;
}
data = data.replace(/^package __PACKAGE_NAME__;/m, 'package ' + packageName + '.wxapi;');
fs.writeFileSync(path.join(targetDir, f), data);
});
});
}
};
微信目錄結構:
最後 該微信支付例子是從github上的一個開源專案做了相應的改動,由此感謝github上貢獻的各位同行。
由於是第一次寫部落格,如果文章中不足和錯誤,希望大家能夠指正,不勝感激。