Android Studio 使用 Gradle 打包 Jar-IT藍豹

Android Studio 打 Jar 包一直是一個麻煩的事,按照網上現有的教程,打包一個混淆的 jar 需要完成下列步驟:

  1. 將 plugin 修改爲library後 build 出 aar,再提取 aar 裏面的 classes.jar

  2. 使用 jarjar 等工具剔除多餘的 class

  3. 對第二步得到的 jar 進行混淆

無論哪一步,所做的工作量都不少。於我個人而言,相當麻煩,於是花了些時間研究了下 Gradle 打 Jar 包。

代碼

廢話不多說,先上代碼( 注 :只在 Gradle Android Plugin 1.2.3 測試過)

build.gradle

  1. import com.android.build.gradle.AppPlugin

  2. import proguard.gradle.ProGuardTask

  3. apply plugin:'com.android.application'

  4. android {

  5. compileSdkVersion 22

  6. buildToolsVersion "22.0.1"

  7. defaultConfig {

  8. applicationId "org.chaos.demo.jar"

  9. minSdkVersion 22

  10. targetSdkVersion 22

  11. versionCode 1

  12. versionName "1.0"

  13. }

  14. buildTypes {

  15. release {

  16. minifyEnabled true

  17. proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'

  18. }

  19. }

  20. }

  21. dependencies {

  22. compile fileTree(dir:'libs', include:['*.jar'])

  23. }

  24. //dependsOn 可根據實際需要增加或更改

  25. task buildJar(dependsOn:['compileReleaseJava'], type:Jar){

  26. appendix ="demo"

  27. baseName ="androidJar"

  28. version ="1.0.0"

  29. classifier ="release"

  30. //後綴名

  31. extension ="jar"

  32. //最終的 Jar 包名,如果沒設置,默認爲 [baseName]-[appendix]-[version]-[classifier].[extension]

  33. archiveName ="AndroidJarDemo.jar"

  34. //需打包的資源所在的路徑集

  35. def srcClassDir =[project.buildDir.absolutePath +"/intermediates/classes/release"];

  36. //初始化資源路徑集

  37. from srcClassDir

  38. //去除路徑集下部分的資源

  39. // exclude "org/chaos/demo/jar/MainActivity.class"

  40. // exclude "org/chaos/demo/jar/MainActivity/$*.class"

  41. exclude "org/chaos/demo/jar/BuildConfig.class"

  42. exclude "org/chaos/demo/jar/BuildConfig/$*.class"

  43. exclude "**/R.class"

  44. exclude "**/R/$*.class"

  45. //只導入資源路徑集下的部分資源

  46. include "org/chaos/demo/jar/**/*.class"

  47. //注: exclude include 支持可變長參數

  48. }

  49. task proguardJar(dependsOn:['buildJar'], type:ProGuardTask){

  50. //Android 默認的 proguard 文件

  51. configuration android.getDefaultProguardFile('proguard-android.txt')

  52. //會根據該文件對 Jar 進行混淆,注意:需要在 manifest 註冊的組件也要加入該文件中

  53. configuration 'proguard-rules.pro'

  54. String inJar = buildJar.archivePath.getAbsolutePath()

  55. //輸入 jar

  56. injars inJar

  57. //輸出 jar

  58. outjars inJar.substring(0, inJar.lastIndexOf('/'))+"/proguard-${buildJar.archiveName}"

  59. //設置不刪除未引用的資源(類,方法等)

  60. dontshrink

  61. AppPlugin appPlugin = getPlugins().findPlugin(AppPlugin)

  62. if(appPlugin !=null){

  63. List<String> runtimeJarList

  64. if(appPlugin.getMetaClass().getMetaMethod("getRuntimeJarList")){

  65. runtimeJarList = appPlugin.getRuntimeJarList()

  66. }elseif(android.getMetaClass().getMetaMethod("getBootClasspath")){

  67. runtimeJarList = android.getBootClasspath()

  68. }else{

  69. runtimeJarList = appPlugin.getBootClasspath()

  70. }

  71. for(String runtimeJar : runtimeJarList){

  72. //給 proguard 添加 runtime

  73. libraryjars(runtimeJar)

  74. }

  75. }

  76. }

爲什麼已在 manifest 註冊的組件需要在 .pro 文件聲明對應的混淆規則?

可能各位注意到 proguardJar task 的第二行註釋,在 apk 的打包過程中,aapt 會在解析 manifest 後生成一個用於不混淆 manifest 中已註冊的組件的規則文件。然而我們的 task 只是依賴於compileReleaseJava(該 task 在執行 aapt 前), Gradle Android Plugin 中配置上述 aapt 生成的規則文件的代碼如下:

BasePlugin.groovy

  1. protectedFile createProguardTasks(@NonNullBaseVariantData variantData,

  2. @NullableBaseVariantData testedVariantData){

  3. ......

  4. // also the config file output by aapt

  5. proguardTask.configuration(variantData.proce***esourcesTask.proguardOutputFile)

  6. ......

  7. }

礙於技術原因,獲取不到proce***esourcesTask的實例,所以目前只能先添加對應的組件到規則文件中,還望知道怎麼獲取的朋友能夠分享下,謝謝。

使用方法

不需要混淆則運行命令

  1. gradle buildJar

  2. ./gradlew buildjar

需要混淆則運行

  1. gradle proguardJar

  2. ./gradlew proguardJar

總結

buildJar這部分相對比較簡單,很多內容網上都有教程。關鍵在於混淆,由於需要導入 runtime 相關的 jar,雖說可以寫死 runtime 的路徑,但是團隊每個人都有自己的安裝習慣,路徑不一定一致,於是乎看源碼翻了一段時間才找到相應的代碼。至於想更多個性化的朋友,建議從源碼入手。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章