本篇文章讲述的是如何制作自己的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.html
3.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,不足之处,欢迎批评指正;