Android Studio 打 Jar 包一直是一个麻烦的事,按照网上现有的教程,打包一个混淆的 jar 需要完成下列步骤:
- 将 plugin 修改为library后 build 出 aar,再提取 aar 里面的 classes.jar
- 使用 jarjar 等工具剔除多余的 class
- 对第二步得到的 jar 进行混淆
无论哪一步,所做的工作量都不少。于我个人而言,相当麻烦,于是花了些时间研究了下 Gradle 打 Jar 包。
代码
废话不多说,先上代码( 注 :只在 Gradle Android Plugin 1.2.3 测试过)
build.gradle
-
import com.android.build.gradle.AppPlugin
-
import proguard.gradle.ProGuardTask
-
apply plugin:‘com.android.application‘
-
android {
-
compileSdkVersion 22
-
buildToolsVersion "22.0.1"
-
defaultConfig {
-
applicationId "org.chaos.demo.jar"
-
minSdkVersion 22
-
targetSdkVersion 22
-
versionCode 1
-
versionName "1.0"
- }
-
buildTypes {
-
release {
-
minifyEnabled true
-
proguardFiles getDefaultProguardFile(‘proguard-android.txt‘),‘proguard-rules.pro‘
- }
- }
- }
-
dependencies {
-
compile fileTree(dir:‘libs‘, include:[‘*.jar‘])
- }
- //dependsOn 可根据实际需要增加或更改
-
task buildJar(dependsOn:[‘compileReleaseJava‘], type:Jar){
-
appendix ="demo"
-
baseName ="androidJar"
-
version ="1.0.0"
-
classifier ="release"
- //后缀名
-
extension ="jar"
- //最终的 Jar 包名,如果没设置,默认为 [baseName]-[appendix]-[version]-[classifier].[extension]
-
archiveName ="AndroidJarDemo.jar"
- //需打包的资源所在的路径集
-
def srcClassDir =[project.buildDir.absolutePath +"/intermediates/classes/release"];
- //初始化资源路径集
-
from srcClassDir
- //去除路径集下部分的资源
- // exclude "org/chaos/demo/jar/MainActivity.class"
- // exclude "org/chaos/demo/jar/MainActivity/$*.class"
-
exclude "org/chaos/demo/jar/BuildConfig.class"
-
exclude "org/chaos/demo/jar/BuildConfig/$*.class"
-
exclude "**/R.class"
-
exclude "**/R/$*.class"
- //只导入资源路径集下的部分资源
-
include "org/chaos/demo/jar/**/*.class"
- //注: exclude include 支持可变长参数
- }
-
task proguardJar(dependsOn:[‘buildJar‘], type:ProGuardTask){
- //Android 默认的 proguard 文件
-
configuration android.getDefaultProguardFile(‘proguard-android.txt‘)
- //会根据该文件对 Jar 进行混淆,注意:需要在 manifest 注册的组件也要加入该文件中
-
configuration ‘proguard-rules.pro‘
-
String inJar = buildJar.archivePath.getAbsolutePath()
- //输入 jar
- injars inJar
- //输出 jar
-
outjars inJar.substring(0, inJar.lastIndexOf(‘/‘))+"/proguard-${buildJar.archiveName}"
- //设置不删除未引用的资源(类,方法等)
- dontshrink
-
AppPlugin appPlugin = getPlugins().findPlugin(AppPlugin)
-
if(appPlugin !=null){
-
List<String> runtimeJarList
-
if(appPlugin.getMetaClass().getMetaMethod("getRuntimeJarList")){
-
runtimeJarList = appPlugin.getRuntimeJarList()
-
}elseif(android.getMetaClass().getMetaMethod("getBootClasspath")){
-
runtimeJarList = android.getBootClasspath()
-
}else{
-
runtimeJarList = appPlugin.getBootClasspath()
- }
-
for(String runtimeJar : runtimeJarList){
- //给 proguard 添加 runtime
-
libraryjars(runtimeJar)
- }
- }
- }
为什么已在 manifest 注册的组件需要在 .pro 文件声明对应的混淆规则?
可能各位注意到 proguardJar task 的第二行注释,在 apk 的打包过程中,aapt 会在解析 manifest 后生成一个用于不混淆 manifest 中已注册的组件的规则文件。然而我们的 task 只是依赖于compileReleaseJava(该 task 在执行 aapt 前), Gradle Android Plugin 中配置上述 aapt 生成的规则文件的代码如下:
BasePlugin.groovy
-
protectedFile createProguardTasks(@NonNullBaseVariantData variantData,
-
@NullableBaseVariantData testedVariantData){
- ......
- // also the config file output by aapt
-
proguardTask.configuration(variantData.processResourcesTask.proguardOutputFile)
- ......
- }
碍于技术原因,获取不到processResourcesTask的实例,所以目前只能先添加对应的组件到规则文件中,还望知道怎么获取的朋友能够分享下,谢谢。
使用方法
不需要混淆则运行命令
- gradle buildJar
- 或
-
./gradlew buildjar
需要混淆则运行
- gradle proguardJar
- 或
-
./gradlew proguardJar
总结
buildJar这部分相对比较简单,很多内容网上都有教程。关键在于混淆,由于需要导入 runtime 相关的 jar,虽说可以写死 runtime 的路径,但是团队每个人都有自己的安装习惯,路径不一定一致,于是乎看源码翻了一段时间才找到相应的代码。至于想更多个性化的朋友,建议从源码入手。
?
Android Studio 使用 Gradle 打包 Jar-IT蓝豹
原文:http://wuchengyi-1994.iteye.com/blog/2246677