Cordova外掛開發(2)-Android外掛安裝包製作詳解
本篇文章講述的是如何製作自己的Cordova外掛安裝包(Android),具體內容包括以下三個方面:
1,安裝和使用plugman;
2,開發自己的Cordova外掛安裝包;
3,外掛安裝包的安裝與解除安裝;
本篇文章以自定義加密壓縮檔案外掛的實踐過程為例,本人不會IOS,倒是擼過兩年Android,所以這裡只講述Android平臺的實現過程。
一,準備工作
需已搭建好Codova環境;
二,具體實現
1,安裝plugman
plugman是Cordova官方推薦使用的建立外掛工具,執行以下命令即可安裝:
npm install -g plugman
2,使用plugman建立外掛模板
2.1 建立外掛
plugman建立外掛方式如下:
plugman create --name 外掛名 --plugin_id 外掛id --plugin_version 外掛版本號
執行以下命令,即可建立一個外掛名為fileUtil,外掛id為fxp-plugin-fileUtil,版本號為1.0.0的外掛:plugman create --name fileUtil --plugin_id fxp-plugin-fileUtil --plugin_version 1.0.0
2.2 給外掛新增Android平臺
到了這一步,外掛模板就建立完成了,新建立的外掛模板目錄結構如下:cd fileUtil plugman platform add --platform_name android
以上目錄中,一共有plugin.xml、fileUtil.java、fileUtil.js三個檔案。接下來我們就可以在此外掛模板基礎上開發自己的外掛安裝包了。當然,也可以不安裝使用plugman,直接手動建立以上檔案目錄。
3,開發自己的Cordova外掛安裝包
其實外掛安裝包檔案目錄結構完全不用拘泥於以上,只要在plugin.xml檔案中配置得當,目錄結構可以隨意。但出於規範,我們還是參照以上結構比較好。下面是我寫的加密壓縮檔案外掛目錄結構:
以上目錄中,plugin.xml是核心配置檔案,src->android->code目錄下是安卓程式碼,src->android->libs目錄下是安卓用到的jar包,www 目錄下的是js介面檔案。下面開始講解具體實現。
3.0 編輯package.json檔案
package.json檔案用於安裝和釋出,在以前的cordova版本中,沒有此檔案也可以正常本地安裝自己的外掛,但最近不行了,必須得有。直接上程式碼:
{
"name": "fxp-plugin-fileUtil",
"version": "1.0.0",
"description": "create and zip file, used to export data to zip",
"cordova": {
"id": "fxp-plugin-fileUtil",
"platforms": [
"android"
]
},
"repository": {
"type": "",
"url": ""
},
"keywords": [
"cordova",
"zip",
"file",
"phonegap",
"ecosystem:cordova",
"cordova-android"
],
"author": "",
"license": "Apache 2.0",
"bugs": {
"url": ""
},
"homepage": ""
}
3.1 編輯plugin.xml檔案
plugin.xml是核心配置檔案,不廢話,直接上程式碼,程式碼已詳細註釋配置說明及需要注意的問題:
<?xml version='1.0' encoding='utf-8'?>
<plugin xmlns:android="http://schemas.android.com/apk/res/android" id="fxp-plugin-fileUtil"
version="1.0.0" xmlns="http://apache.org/cordova/ns/plugins/1.0">
<name>fileUtil</name>
<!-- 一個plugin可以有多個module,類似於Android Studio中project和module的概念-->
<!-- js-module name可隨意命名,src值為此module對應js檔案的相對路徑 -->
<!-- 【外掛id.js-module的name值】對應安裝後zipUtil.js中cordova.define方法第一個引數,以及其在cordova_plugin.js中的id值 -->
<js-module name="zipUtil" src="www/fileUtil.js">
<!-- target值即為js呼叫外掛方法時所用的物件名,可隨意命名;對應安裝後cordova_plugin.js中clobbers值 -->
<clobbers target="fxp.plugins.zipUtil" />
</js-module>
<!-- 可新增多個平臺,name值為平臺名-->
<platform name="android">
<config-file parent="/*" target="res/xml/config.xml">
<!-- 註冊外掛module,feature的name值為需要註冊的js-module的name值 -->
<feature name="zipUtil">
<!-- name值隨意,value值為【將外掛id中"-"替換為"."後的字串】.【feature的name值】-->
<param name="android-package" value="fxp.plugin.fileUtil.zipUtil" />
</feature>
</config-file>
<config-file parent="/*" target="AndroidManifest.xml">
<!-- 此處新增所需許可權 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</config-file>
<!-- 將外掛檔案放到指定目錄:src為在外掛安裝包中的相對路徑,target-dir為在外掛安裝後的相對路徑 -->
<!-- 將java類檔案放到【src/包名】目錄,注意:此處所寫包名須與java類中包名一致 -->
<source-file src="src/android/code/zipUtil.java" target-dir="src/fxp.plugin.fileUtil" />
<source-file src="src/android/code/CompressUtil.java" target-dir="src/fxp.plugin.fileUtil" />
<source-file src="src/android/code/DateUtils.java" target-dir="src/fxp.plugin.fileUtil" />
<source-file src="src/android/code/FileService.java" target-dir="src/fxp.plugin.fileUtil" />
<source-file src="src/android/code/FileUtils.java" target-dir="src/fxp.plugin.fileUtil" />
<source-file src="src/android/code/StringUtil.java" target-dir="src/fxp.plugin.fileUtil" />
<!-- Cordova官方提供了以下兩種庫依賴方式 -->
<!-- 1,首選framework標籤。此方法引入的庫可被多個外掛使用而不產生衝突;但此方法引入非官方jar包會失敗,故此demo不用此方式 -->
<!--<framework src="com.android.support:support-v4:24.1.1+" />-->
<!-- 2,其次lib-file標籤。但如果有其他外掛也添加了此依賴,則可能產生衝突;此demo依賴的是非官方庫,只有用此標籤了 -->
<lib-file src="src/android/libs/zip4j_1.3.1.jar" />
<lib-file src="src/android/libs/commons-lang3-3.1.jar" />
<lib-file src="src/android/libs/commons-codec-1.7.jar" />
<!-- 經驗證,使用source-file標籤將依賴包放到libs目錄,然後新增依賴關係也是可行的。如下: -->
<!-- 將依賴包檔案放到【libs】目錄 -->
<!-- 外掛安裝後執行cordova run 命令或在Android Studio中Sync操作即可自動新增依賴關係;如果沒有自動新增,可以手動新增 -->
<!--<source-file src="src/android/libs/commons-codec-1.7.jar" target-dir="libs" />-->
<!--<source-file src="src/android/libs/commons-lang3-3.1.jar" target-dir="libs" />-->
<!--<source-file src="src/android/libs/zip4j_1.3.1.jar" target-dir="libs" />-->
</platform>
</plugin>
plugin.xml中配置項其實是很多的,由於此demo中只需要以上配置,所以就沒有體現其他配置項了。想要了解更多的話,可以留言討論,我會盡快回復。當然,也可以直接看官方文件(純英文):http://cordova.apache.org/docs/en/latest/plugin_ref/spec.html3.2 編輯fileUtil.js(js介面實現)
依舊直接上程式碼,程式碼已詳細註釋:
/**
* cordova.define 的第一個引數為【外掛id.js-module的name值】,對應安裝後cordova_plugins.js裡面定義的id
* exec方法,引數說明:
* 引數1:成功回撥function
* 引數2:失敗回撥function
* 引數3:feature name,與config.xml中註冊的一致
* 引數4:呼叫java類時的action
* 引數5:要傳遞的引數,json陣列格式
* 下面提供三種實現方式
*/
//cordova.define("fxp-plugin-fileUtil.zipUtil", function(require, exports, module) {
var exec = require('cordova/exec');
exports.exportDatasToEncryptedZip=function(content, successCallback, errorCallback){
exec(successCallback,errorCallback,"zipUtil","exportDatasToEncryptedZip",[content]);
};
exports.writeFileToDir=function (content, successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, "zipUtil", "writeFileToDir", [content]);
};
exports.zipEncryptedFolders= function (content, successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, "zipUtil", "zipEncryptedFolders", [content]);
}
/* module.exports = {
exportDatasToEncryptedZip: function(content, successCallback, errorCallback){
cordova.exec(successCallback,errorCallback,"zipUtil","exportDatasToEncryptedZip",[content]);
}
,
writeFileToDir: function (content, successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, "zipUtil", "writeFileToDir", [content]);
},
zipEncryptedFolders: function (content, successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, "zipUtil", "zipEncryptedFolders", [content]);
}
}*/
/* var exec = require('cordova/exec');
var FXP = function(){};
FXP.prototype.exportDatasToEncryptedZip=function(content,success, error) {
cordova.exec(success,error,"zipUtil","exportDatasToEncryptedZip",[content]);
};
FXP.prototype.writeFileToDir=function(content,success, error) {
cordova.exec(success, error, "zipUtil", "writeFileToDir", [content]);
};
FXP.prototype.zipEncryptedFolders=function(content,success, error) {
cordova.exec(success, error, "zipUtil", "zipEncryptedFolders", [content]);
};
var fxp = new FXP();
module.exports = fxp;*/
//});
3.3 編輯zipUtil.java(安卓原生介面實現)
package fxp.plugin.fileUtil;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import android.widget.Toast;
/**
* This class echoes a string called from JavaScript.
*/
public class zipUtil extends CordovaPlugin {
/**
* @param action The action to execute.
* @param args The exec() arguments, wrapped with some Cordova helpers.
* @param callbackContext The callback context used when calling back into JavaScript.
* @return
* @throws JSONException
*/
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (action.equals("exportDatasToEncryptedZip")) {
exportDatas(args,callbackContext);
return true;
} else if (action.equals("writeFileToDir")) {
String message = args.getString(0);
//TODO
return true;
} else if (action.equals("zipEncryptedFolders")) {
String message = args.getString(0);
//TODO
return true;
}else {
//TODO
}
return super.execute(action, args, callbackContext);
}
private void exportDatas(JSONArray args,CallbackContext callbackContext) throws JSONException{
JSONObject jsonArgs = new JSONObject(args.getString(0));
String fileContent = (String) jsonArgs.get("fileContent");
String fileName = (String) jsonArgs.get("fileName");
String zipPath = (String) jsonArgs.get("zipPath");
String zipName = (String) jsonArgs.get("zipName");
Boolean isCreateDir = (Boolean) jsonArgs.get("isCreateDir");
String zipPwd = (String) jsonArgs.get("zipPwd");
String exportPath = FileService.getInstance(cordova.getActivity()).exportDatasToEncryptedZip(fileContent, fileName, zipPath, zipName, isCreateDir, zipPwd);
if (exportPath != null && exportPath != "") {
Log.e("本地匯出成功-exportPath", exportPath);
callbackContext.success(exportPath);
} else {
Log.e("本地匯出失敗-exportPath", exportPath);
callbackContext.error(exportPath);
}
}
}
關於此類中execute方法執行緒和args取值問題,我在另一篇博文中有詳細講述,請參看:Cordova外掛開發(1)-Android外掛開發詳解。
主要就是以上三個檔案了,業務程式碼可根據實際需求新增。檔案加密壓縮外掛呼叫方式如下:
var args = {
fileContent:"鵬超帥才不是單身狗鵬超帥才不是單身狗鵬超帥才不是單身狗",
fileName:"fxp_export.json",
zipPath:"/storage/emulated/0/FXP/export/",
zipName:"EncryptedZip.zip",
isCreateDir:true,
zipPwd:"123456"
}
fxp.plugins.zipUtil.exportDatasToEncryptedZip(args,function(success){
alert("本地匯出成功-exportPath:" + success);
},function (error){
alert("本地匯出失敗-exportPath:" + error);
});
下面也貼一點功能實現程式碼吧。這種業務需求,一般習慣寫個服務類統一代理,然後單例模式呼叫。如下:
package fxp.plugin.fileUtil;
import android.content.Context;
import java.util.ArrayList;
import java.util.List;
/**
* File
* $desc:檔案操作服務類
*
* @author fxp
* Created at 2017/4/17.
*/
public class FileService {
private final String TAG = "FileService";
private static FileService instance;
private Context context;
public static FileService getInstance(Context context) {
if (null == instance) {
instance = new FileService(context);
}
return instance;
}
private FileService(Context context) {
this.context = context;
}
/**
* create by fxp 2017-4-18 將字串匯出到加密壓縮包
*
* @param fileContent:文字內容
* @param fileName:檔名
* @param exportPath:壓縮包存放的位置,為Null則存放在第一個帶壓縮檔案/資料夾所在路徑
* @param zipName:壓縮包名稱
* @param isCreateDir:是否需要建立子資料夾
* @param zipPwd:加密密碼
* @return 壓縮檔案的路徑,失敗則為NULL。返回值示例: /storage/emulated/0/FXP/export/20170418115248_done.zip
*/
public String exportDatasToEncryptedZip(String fileContent, String fileName, String exportPath, String zipName, boolean isCreateDir, String zipPwd) {
String filePath = "";
//臨時資料夾路徑。tempPath示例: /storage/emulated/0/FXP/temp/
String tempPath = FileUtils.getTmpPath();
String exportTime = DateUtils.formatDate("yyyyMMddHHmmss", DateUtils.getNow());
//臨時檔案路徑
String dirPath = tempPath + exportTime + "/data/";
//將資料寫入檔案
boolean isWriteSuccess = writeFileToDir(dirPath, fileName, fileContent);
if (isWriteSuccess) {
List<String> folders = new ArrayList<String>();
//將需要匯出的資料夾路徑新增到連結串列
folders.add(tempPath + exportTime);
//加密壓縮資料夾
filePath = zipEncryptedFolders(folders, exportPath, zipName, isCreateDir, zipPwd);
}
//刪除臨時資料夾及檔案
FileUtils.deleteDirOrFile(tempPath);
return filePath;
}
/**
* create by fxp 2017-4-17 將文字內容寫入到指定目錄下檔案
*
* @param dirPath:檔案目錄
* @param fileName:檔名稱
* @param fileContent:文字內容
* @return 文字寫入操作是否成功
*/
public boolean writeFileToDir(String dirPath, String fileName, String fileContent) {
return FileUtils.writeFileToDir(dirPath, fileName, fileContent);
}
/**
* create by fxp 2017-4-17 將1~N個檔案或資料夾加密壓縮到特定目錄下
*
* @param folders:1~N個檔案或資料夾的連結串列
* @param exportPath:壓縮包存放的位置,為Null則存放在第一個帶壓縮檔案/資料夾所在路徑
* @param zipName:壓縮包名稱
* @param isCreateDir:是否需要建立子資料夾
* @param pwd:加密密碼
* @return 壓縮檔案的路徑,失敗則為NULL。返回值示例: /storage/emulated/0/FXP/export/20170418115248_done.zip
*/
public String zipEncryptedFolders(List<String> folders, String exportPath, String zipName, boolean isCreateDir, String pwd) {
return CompressUtil.zipEncryptedFolders(folders, exportPath, zipName, isCreateDir, pwd);
}
}
該下班了,其他的就懶得貼了。迴歸正題,外掛安裝包開發完成。
4,安裝自己的外掛
本篇文章的重點是講述外掛安裝包製作過程,所以這裡先只講本地安裝,後面我會專門整理出一篇文章講述npm、git等安裝方式。
進入cordova工程目錄執行以下命令:
cordova plugin add 外掛安裝包相對路徑
例如,
sudo cordova plugin add ../fileUtil
Installing "fxp-plugin-fileUtil" for android
ANDROID_HOME=/Users/fxp/Library/Android/sdk
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home
Subproject Path: CordovaLib
Incremental java compilation is an incubating feature.
:clean
:CordovaLib:clean
BUILD SUCCESSFUL
Total time: 7.386 secs
Installing "fxp-plugin-fileUtil" for ios
注意:本地安裝是根據相對路徑,不是外掛id。我這裡是把fileUtil資料夾(外掛安裝包)放在cordova工程同一目錄。
5,解除安裝外掛
解除安裝方式並無不同,在cordova工程目錄下執行以下命令:
cordova plugin remove 外掛id
例如,sudo cordova plugin remove fxp-plugin-fileUtil
Password:
Uninstalling fxp-plugin-fileUtil from android
Uninstalling fxp-plugin-fileUtil from ios
Removing "fxp-plugin-fileUtil"
三,寫在後面
1,本篇文章意在講述外掛安裝包製作過程,歡迎交流討論;
2,本篇文章只講解了製作本地安裝包以及本地安裝,後面有空會再整理一篇文章講述基於npm、git方式;
3,此demo為需求驗證所寫,並非實際專案最終所用,不存在侵權問題;
4,已手擼外掛實現了檔案加密、檔案解密、檔案壓縮、檔案解壓、檔案MD5值校驗和其他常見檔案操作,但只擼了Android,IOS不會,期待IOS大神實現IOS版,願交換完整程式碼;
5,不足之處,歡迎批評指正;