Android插件化与其构建流程
来源:互联网 发布:centos git ssh配置 编辑:程序博客网 时间:2024/06/05 08:07
最近在调研Android插件化的实现方式,并准备用在公司的项目当中。最后调研发现,公司内部有一套插件化的工具。但是这套工具缺少自动化的构建方式。于是我的工作就变成了开发这么一个自动化构建脚本。本篇主要总结一个简版的插件化的形式。
插件化
插件化是将代码按照不同的业务进行拆分的一个过程。插件可以理解是一个业务模块。一般它需要依附于宿主,并以apk的形式存在于宿主的assets目录下。宿主是整个程序的基础,也是整个程序的框架。最终发布到应用商城的apk就是宿主。
程序的安装和启动就是宿主apk的安装和启动。宿主在首次启动过程中,会从assets目录下加载插件,加载成功之后会检查插件是否有更新,如果有更新,会直接下载。整个过程都是新开线程处理的。插件的最终更新是在下次启动宿主时完成的。下次启动的时候,最新的插件就会被加载,旧的会被删除掉。然后循环上面的过程。
其实也可以做到不重启更新插件,但是更新的条件是:在插件apk下载好之后,宿主当前没有展示插件activity时。目前我们还很难做到完美的实时更新。最主要的是这功能似乎没那么必要。
为什么要插件化?插件化不是因为可以实时更新,修复bug而存在的。它可以让我们更好的管理,维护代码。以业务为维度划分插件可以使得人员分工明确,代码的构建的速度得到大幅度提高。这也是它和热修复最大的区别。
在拆分代码的过程中,必然也会有公共库的存在。我们将插件以业务划分,公共库以功能划分。下面的图展示了整个的划分。
图中的provided 指:插件对公共库的引用,在构建过程中是只编译不打包到插件的apk。
构建流程
插件化之后的代码构建,将之前直接构建出一个apk,变成了要构建多个apk。但是这多个apk的构建并不是简单的一个接着一个构建。
首先插件需要依附宿主的公共库,宿主构建完成之后,公共库会被混淆。混淆的代码会使插件里的引用找不到。这个问题的解决是mapping文件。mapping文件是混淆映射文件,可以在宿主的progard的混淆规则文件中定义,比如:
-verbose-applymapping mapping.txt
这么配置之后,构建完的apk之后,会在build/outputs/mapping/目录下有对映flavor的mapping.txt文件生成。
对于插件,在其progard的混淆规则文件中添加配置:
-applymapping [mapping.txt]
中括号里的文件对应宿主生成的mapping.txt文件。
找到了解决方案,我们就可以按照先构建宿主,然后构建插件的顺序来就行构建了。
但是还有一个问题,插件构建完成之后, 我们需要将插件放入宿主的assets目录下。这么做宿主的签名就会失效,我们需要对宿主重新签名才能正确安装。
对于一个正常的apk的构建,签名是最后一道流程。我们也可以在宿主混淆任务执行完成之后,开始构建插件,然后将插件放入宿主的assets目录下。
我们选择上面的流程方案:
启动宿主构建–>寻找依赖–>打包–>混淆–>构建插件–>将插件apk放入宿主assets目录下–>签名apk。
构建插件
构建插件是指完成上面构建流程需要开发的gradle插件。这里简单介绍一下这个插件的实现,具体可以自己查看源码
在改变原有构建流程之前,我们还需要两个依赖配置:
provided,pluginCompile.
provided: 提供给插件引用公共组件,主要实现编译不打包功能:
provided project(path: ':publiclib')
android build tool已经提供了provided功能,但是不支持android library。在这里有详细的修改方式,使得其可以支持android library(只做了2.1.0版本)
pluginCompile: 提供给宿主引用插件:
pluginCompile project(path: ':pluginTest')
具体实现详见代码
有了配置之后,下面介绍一下构建流程的修改:
混淆的任务对应:transformclassesandresourceswithproguardfor。
我们只要拿到该task(下面对应injectTask),然后给它添加依赖:
injectTask.doLast(new Action<Task>() { @Override public void execute(Task task) { //混淆任务完成之后,将mapping文件copy到app项目的更目录 copyMapping(variant); } }); //注入plugin的assemble任务 injectTask.finalizedBy(assembleTask); //plugin任务执行完之后,将资源 assembleTask.doLast(new Action<Task>() { @Override public void execute(Task task) { //这里copy一次,原因aapt add 没找到能指定添加路径的参数。 String pluginDistPath =copyPluginApkToAssets(pluginVariantOutput); //这是签名之前的apk的路径 String packagedProcessAp = appVariantOutput.getProcessResources().getPackageOutputFile().getAbsolutePath(); pluginDistPath = pluginDistPath.replaceAll(project.getProjectDir().getAbsolutePath()+"/",""); AaptUtls.aaptAddRes(project,pluginDistPath,packagedProcessAp,project.getProjectDir().getAbsolutePath()); } });
往未签名的apk里添加文件,需要用到aapt,具体见AaptUtls.java文件。
备注:菜鸟一枚,还请大神们多多指点
- Android插件化与其构建流程
- Unity3D与android交互----构建android插件
- Unity3D与android交互----构建android插件
- Unity3D与android交互---构建android插件
- 插件化系列开发之九--Android 全面插件化 RePlugin 流程与源码解析
- android 浏览器插件开发 - 流程(1)
- android 浏览器插件开发 - 流程(2)
- android 浏览器插件开发 - 流程(1)
- 基于插件开发的Android实现流程
- android 浏览器插件开发 - 流程(2)
- android 浏览器插件开发 - 流程(1)
- Cordova Android Plugins插件开发流程
- 基于插件开发的Android实现流程
- Android官方开发文档Training系列课程中文版:使用Fragment构建动态UI之与其它Fragment通信
- [unity3d]Unity3D与android交互----构建android插件
- Unity3D与android交互----构建android插件(转)
- Dart入门—控制流程与其他
- jquery与其它插件冲突时
- CPU下的计时与GPU计时对比
- 对nginx学习记录
- 交叉编译工具链的构建原理
- New Year and Days
- python基础第二篇
- Android插件化与其构建流程
- SQL-SERVER2008 存储过程-子过程回滚
- MySql错误:[Err] 1292
- POJ 1258 Agri-Net(最小生成树-Prim)
- 15入门阶段综合练习
- 【HDU】6048
- 让你用一次就会爱上的 5 个 web 工具类产品
- How can I autologin to desktop with systemd?
- QT-输入框右键菜单翻译文件安装