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.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,不足之处,欢迎批评指正;








  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值