在做UAF的时候,我产生了一个需求:我希望我可以把demo,UAF Client,UAF ASM分别打包成3个apk,又可以打包成1个apk。当分别打包的时候,UAF Client/UAF ASM是application;统一打包的时候,UAF Client/UAF ASM是library。我开始进行尝试。
方案1: 通过apply library 和 application plugin进行配置
初步想法
我希望在debug的时候,UAF Client/UAF ASM的build.gradle apply plugin: 'com.android.library'
,release的时候apply plugin: 'com.android.application'
。我找到识别debug和release的方法:
var debug = gradle.getStartParameter().getTaskRequests().toString().contains("Debug") if (debug) { apply plugin: 'com.android.library' } else { apply plugin: 'com.android.application' }
1234567 | var debug = gradle.getStartParameter().getTaskRequests().toString().contains("Debug")if (debug) { apply plugin: 'com.android.library'} else { apply plugin: 'com.android.application'} |
---|
因为我需要在Generate Signed APK中可以选择UAF Client导出apk,所以需要默认是application。(gradle进行sync的时候会进行一次配置,此时debug变量恒为false)
因为library module无可以配置applicationId,所以还需要:
android { defaultConfig { if (!debug) { applicationId "com.*****" } // ...... } }
123456789 | android { defaultConfig { if (!debug) { applicationId "com.*****" } // ...... }} |
---|
然后在demo中加入依赖:
debugCompile project(':asm') debugCompile project(':client')
123 | debugCompile project(':asm')debugCompile project(':client') |
---|
存在问题
如此配置导致的问题是gradle sync now失败。报错是“demo无法依赖一个application的module”。但不sync直接运行demo和Generate Signed APK都是可以的。一开始我以为是我debug判断条件有问题,使用println打印信息发现没有输出。
后来了解到gradle sync会遍历一遍gradle文件进行配置,再执行常规编译。在遍历过程中并没有**Debug这样的task进行判断,所以此时UAF Client/ASM是当作application来处理的。
初步想法改进
那为了可以sync成功,我只能把默认改为library了。
var debug = gradle.getStartParameter().getTaskRequests().toString().contains("Debug") if (!debug) { apply plugin: 'com.android.application' } else { apply plugin: 'com.android.library' }
1234567 | var debug = gradle.getStartParameter().getTaskRequests().toString().contains("Debug")if (!debug) { apply plugin: 'com.android.application'} else { apply plugin: 'com.android.library'} |
---|
这样一来,我就无法使用Generate Signed APK导出UAF Client/UAF ASM了。但同时我发现了一个有趣的现象:在这个配置之下,我导出demo-release.apk的同时,UAF Client和UAF ASM的release.apk也一并导出了。我猜测是配置过程由于我判断条件的干扰导致的。我试着导出demo-debug.apk,UAF Client和UAF ASM还是导出release.apk,但大小和原来不一样了(原本debug版本是带日志的,会大一点)。生成物是正确的,但名字不对。
然后我把混合/独立的判断条件从debug/release改为flavor控制之后,出现了更多的问题。
结论
不可行。
方案2:新建一个module,引用原library/复用原library代码
方案2一听就是靠谱的。通过新建一个module,引用原library module,专门用于导出apk;或通过配置,复用library module的main文件夹:
android { sourceSets { main.setRoot("../asm/src/main") } }
123456 | android { sourceSets { main.setRoot("../asm/src/main") }} |
---|
结论
可行。
思考
为什么我会没想到简单的方案2,而是在方案1中纠结良久,不可自拔呢?因为我不久之前在某个网站(貌似是简书)上看过一篇文章,它最后说明了如何调试多个apk,就是debug的时候把application的module改为library module,release的时候再独立打包。我只留了个印象,没有收藏这篇文章。而到了用到这个的时候我找不到原文章了,但我内心会一直认为该方案可行,且解决方法优雅。
我再想了想,其实合并多个apk对调试并没有什么优势,这样的编译时间反而更长,只让修改部分的apk重新安装还更快速。。
——————————
我再想了想,那篇文章好像讲的是多个独立模块调试时,可以拆开apk独立运行,不用一点修改就要重新打包整个工程,以提高速度。。不过有了 instant run 这个技巧也不是特别有用了。