博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android插件自定义之多渠道打包插件(支持微信资源混淆andResGuard)
阅读量:5873 次
发布时间:2019-06-19

本文共 6708 字,大约阅读时间需要 22 分钟。

前言

  自定义android studio插件?想想就觉得是一件令人兴奋的事。最近闲来无事决定完善之前的一些代码操作,然后就想到了之前的apk多渠道打包工具,觉得还是太麻烦,何不用插件的形式引入工程自动打包呢。说做就做...

资料整理

  1.插件入门:   2.插件进阶:,库的插件源码   3.渠道包原理:将渠道打入assets里的文件中,我之前的文章有介绍过此原理的打包工具

简单流程图

ejApkRelease task

  1.初始化task

创建EjApkTask继承gradle api的DefaultTask来创建自己的task

public class EjApkTask extends DefaultTask{    def android    def buildConfigs = []    EjApkTask(){        description = 'Assemble ej APK'        group = 'andChannelApk'        outputs.upToDateWhen { false }        android = project.extensions.android        ...    }    @TaskAction    run(){        ...    }}复制代码

其中: group表示在android studio 右侧的gradle任务列表为此task创建一个自己的目录:

会自动将大写转为小写,写法参照AndResGuard原码写的

run方法表示此task运行的方法

创建,并初始化ejApkRelease task

project.afterEvaluate {            System.out.println("ejApkRelease is start")            def taskName = "resguardRelease"            def ejTask = "ejApkRelease"            def task = project.task(ejTask, type: EjApkTask)            //判断是否存在resguardRelease task            if(project.tasks.findByPath(taskName) != null){                System.out.println("ejApkRelease is exit")                task.dependsOn "resguardRelease"            } else {                task.dependsOn "assembleRelease"            }        }复制代码

其中project.afterEvaluate闭包的调用位置实在 项目的settings.gradle构建之后,build.gradle构建之前。 task.dependsOn 表示将此任务task的调用位置放在resguardRelease或者assembleRelease task的后面

  2.task逻辑处理

通过api 获取app-release.apk文件位置,获取gradle配置的签名文件,获取渠道文件的路径配置:

//渠道文件配置位置        String channel = project.properties.get("channelFile")        buildConfigs.each{ config ->            if (config.file == null || !config.file.exists()) {                System.out.println("ejApkRelease EjApkTask apk file not exit 1")                return            }            //签名文件            def signConfig = config.signConfig            //app-release.apk位置            String path = config.file.getAbsolutePath()            System.out.println("path:"+path)            InputParam.Builder builder = new InputParam.Builder()                    .setChannel(channel)                    .setInputFolder(useFolder(config.file))                    .setApkPath(path)                    .setSignFile(signConfig.storeFile)                    .setKeypass(signConfig.keyPassword)                    .setStorealias(signConfig.keyAlias)                    .setStorepass(signConfig.storePassword)            InputParam inputParam = builder.build()            Main.gradleRun(inputParam)        }复制代码

其中: project.properties.get() 表示获取运行项目(app)目录下的gradle.properties文件里面的配置

解压,修改渠道文件,打包签名

  1.解压:

解压方式很简单,通过java自带api实现解压:

@SuppressWarnings("rawtypes")    public static HashMap
unZipAPk(String fileName, String filePath) throws IOException { checkDirectory(filePath); ZipFile zipFile = new ZipFile(fileName); Enumeration emu = zipFile.entries(); HashMap
compress = new HashMap<>(); while (emu.hasMoreElements()) { ZipEntry entry = (ZipEntry) emu.nextElement(); if (entry.isDirectory()) { new File(filePath, entry.getName()).mkdirs(); continue; } BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry)); File file = new File(filePath + File.separator + entry.getName()); File parent = file.getParentFile(); if (parent != null && (!parent.exists())) { parent.mkdirs(); } //要用linux的斜杠 String compatibaleresult = entry.getName(); if (compatibaleresult.contains("\\")) { compatibaleresult = compatibaleresult.replace("\\", "/"); } compress.put(compatibaleresult, entry.getMethod()); FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER); byte[] buf = new byte[BUFFER]; int len; while ((len = bis.read(buf, 0, BUFFER)) != -1) { fos.write(buf, 0, len); } bos.flush(); bos.close(); bis.close(); } zipFile.close(); return compress; }复制代码
  1.修改渠道文件:

先删除解压包存在的签名文件,再寻找assets文件夹是否存在,存在直接修改渠道文件,不存在则添加assets文件夹并添加渠道文件,通过渠道文件获取要打的渠道,循环修改,并打包,签名:

public void buildApk() throws Exception {        //删除签名文件        File sinFile = new File(tempFile,"META-INF");        if(sinFile.exists()){            FileZipUtils.deleteDir(sinFile);            System.out.println("删除原签名文件");        }        //存放签名包位置        File fileassets = new File(tempFile,"assets");        if(!fileassets.exists()){            fileassets.mkdirs();        }        File fileEjChannel = new File(fileassets,"ej_channel");        if(!fileEjChannel.exists()){            fileEjChannel.createNewFile();        }        //打包apk位置        File fileChannel = new File(fileApk,"channel");        if(fileChannel.exists()){            fileChannel.delete();        }        File unSinedFiles = new File(fileChannel,"unsign");        File sinedFiles = new File(fileChannel,"sign");        unSinedFiles.mkdirs();        sinedFiles.mkdirs();        File fileChannelTxt = new File(inputParam.channel);        if(!fileChannelTxt.exists()){            System.out.println("channel.txt not exit");            return;        }        //获取所有渠道        InputStream in = new FileInputStream(fileChannelTxt);        int size = in.available();        byte[] buffer = new byte[size];        in.read(buffer);        in.close();        String allChannel = new String(buffer, "utf-8");        //获取所有渠道数组        String[] channels = allChannel.split(",");        //循环渠道打包        for(String content : channels){            {                OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(fileEjChannel),"UTF-8");                System.out.println("channel content:"+content);                //渠道名称加密                String channel = ChannelEncode.encode(content);                //不加密//                String channel = content;                System.out.println("channel:"+channel);                osw.write(channel, 0, channel.length());                osw.flush();                osw.close();                //压缩文件                File outApkUnsin = new File(unSinedFiles,"release-"+content+"-unsin.apk");                FileZipUtils.compress(tempFile,outApkUnsin);                //签名                File outApkSign = new File(sinedFiles,"release-"+content+"-sin.apk");                signWithV1sign(outApkUnsin,outApkSign);            }        }    }复制代码

使用方法

最后讲一下使用方式,由于本插件没有上传jcenter,所以需要下载下来编译一下,编译方式:

通过双击图中的uploadArchives 任务,会在项目的根目录创建本地maven仓库repo
再在项目中引入此插件即可

这是编译通过之后会在右侧出现:

任务,点击运行此任务即可打出渠道包

觉得还行就看看吧

转载地址:http://ptenx.baihongyu.com/

你可能感兴趣的文章
POJ 3663:Costume Party
查看>>
主机连接虚拟机 web服务
查看>>
ajaxSubmit的data属性
查看>>
NetStatusEvent info对象的状态或错误情况的属性
查看>>
linux命令学习
查看>>
Windows下第三方库安装Nuget与Vcpkg
查看>>
URL的截取问题
查看>>
My first post
查看>>
git分支
查看>>
Ehcache 缓存
查看>>
list删除重复元素
查看>>
绘制屏幕时给单选按钮分组
查看>>
TCP/IP协议、DoD模型、OSI模型
查看>>
java开发环境
查看>>
Can't create handler inside thread that has not called Looper.prepare()
查看>>
ADB命令详解
查看>>
urllib模块学习
查看>>
Flume案例Ganglia监控
查看>>
HDU 4001 To Miss Our Children Time DP
查看>>
12C 新特性--全库缓存
查看>>