公司和A公司有技術合作,需要把接口封裝成sdk供A公司調用,我被安排來做這個事情。這里記錄一下封裝jar並混淆的過程中遇到的一些問題,本文使用的IDE是AndroidStudio。
1.新建項目之后看到proguard-rules.pro中並沒有混淆java文件的代碼,於是百度-->>復制-->>粘貼-->>運行,可是反編譯apk之后發現根本沒有混淆代碼。這是真么回事呢?proguard-rules.pro文件寫錯了?沒有配置到gradle文件里?查了很多資料,再加上多次的實驗,我終於找到問題的所在。之前一直看到gradle文件配置混淆文件的上面還有一行——minifyEnabled false 從來沒有深究過有什么意義(以后還是要多研究一下這些不起眼的小細節,沒准那一天就把你拌趴下了),原來這個標志就是代碼混淆的開關,默認是關閉的,所以之前雖然配置了混淆文件,但是並沒有執行代碼混淆。把這個標志位置為true,再運行就發現混淆起作用了。結論:進行代碼混淆時,要先把開關(minifyEnabled )打開!
2.如何封裝jar包呢?只在AndroidStudio上創建過工程,怎么才能達成jar包呢?網上介紹了一些方法,讓我在gradle文件里面新建任務大概是這個樣子
task makeJar(type: Copy) { delete 'build/libs/mysdk.jar' from('build/intermediates/bundles/release/') into('build/libs/') include('classes.jar') rename ('classes.jar', 'mysdk.jar') } makeJar.dependsOn(build)
一開始我也是這么做的,還真的在build/libs目錄下面生成了一個mysdk.jar文件。后來仔細看了這一段代碼,發現這段代碼先是執行了build,然后把build/intermediates/bundles/release目錄下生成的classes.jar文件改了一個名字而已,實在是太雞肋了。你自己運行工程,直接把build/intermediates/bundles/release目錄下的classes.jar拷貝出來就行了,沒必要這么麻煩。結論:build輸出文件中已包含jar包,不必再想辦法生成jar,jar包位置build/intermediates/bundles/release/classes.jar
3.封裝什么東西?由於合作的事情還在談,我並不知道最終的交付的sdk有什么要求,所以我做了兩個方面的嘗試,第一:僅封裝接口;第二:提供接口和UI。先說第一種,我使用的方法和一般添加Module Library並不相同,我只是添加了一個普通的java的jar,Module中只有代碼和gralde沒有Manifest,沒有res。下面是我的gradle文件,幫助理解
apply plugin: 'java' dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile files('libs/android.jar') compile 'com.google.code.gson:gson:2.5' compile 'com.squareup.okhttp:okhttp:2.5.0' compile 'com.squareup.okio:okio:1.6.0' }
這個地方有幾點需要注意的,android.jar去哪里找?我注意到工程的最下面有一個External Library目錄,這個目錄關聯了工程的依賴文件。右鍵之后選擇file path就可以看到jar的位置了,然后去這個目錄下邊拷貝出來就行了。像這樣
我嘗試講gson、okhttp的jar包也通過compile files引用,但是在主工程里面提示類沒有定義,只有通過這種方式,才不會報錯。結論:我封裝的jar和界面沒有關系,所以我用了一種更干凈的方法,來生成jar。
4.運行程序,因為我沒有使用“apply plugin: 'com.android.library'”所以目錄結構跟上面又不太一樣,我的目錄結構是這樣的,module名為meddo
可以看到build/libs下面已經生成好了一個jar。我把meddo.jar文件拷貝出來開始進行混淆。
5.jar混淆,這里使用的是sdk中包含的工具,具體位置sdk\tools\proguard\bin\proguardgui.bat。使用這個工具之前要做好准備工作:a.准備好要混淆的jar(上面的meddo.jar);b.准備好jar中使用的第三方jar(我這里使用到了android.jar,okhttp-2.5.0.jar,okio-1.6.0.jar,gson-2.5.jar);c.准備好混淆配置文件。
介紹一下我這邊項目的具體情況:I)我寫了一個外觀類MeddoInterface,並在這個類中開放出兩個方法init(Context)和UserLogin(HashMap<String,String>,ResultCallBack<UserLoginResponse>) II)封裝了訪問網絡的操作,使用的是okhttp,中間用到了Gson,反射來解析數據
下面是混淆文件,有些冗余的東西,不要見怪
-optimizationpasses 5 -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontpreverify -dontshrink#混淆jar的時候一定要配置,不然會把沒有用到的代碼全部remove 我本來封裝一個jar就是給別人調用的,全部刪掉就沒有東西了 -verbose -keepattributes Signature #過濾泛型 用到發射,泛型等要添加這個 -keepattributes *Annotation* -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* #如果你使用了ProGuard來導入第三方jar這個地方就不用配置了 #-libraryjars ../meddo/libs/android.jar #-libraryjars ../meddo/libs/gson-2.5.jar #-libraryjars ../meddo/libs/okhttp-2.5.0.jar #-libraryjars ../meddo/libs/okio-1.6.0.jar -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class com.android.vending.licensing.ILicensingService -keepclasseswithmembernames class * { native <methods>; } -keepclasseswithmembernames class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembernames class * { public <init>(android.content.Context, android.util.AttributeSet, int); } -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } #公開兩個方法供使用者調用 -keep public class com.hsji.makejar.MeddoInterface{ public static void UserLogin(java.util.HashMap, com.hsji.makejar.network.ResultCallback); public static void init(android.content.Context); } #解析數據是用的的bean 完全不混淆,不然解析json數據時什么都找不到 -keep public class com.hsji.makejar.UserLoginResponse{*;} #不要混淆ResultCallback的public方法 -keep public class com.hsji.makejar.network.ResultCallback{ public <methods>; } #okhttp -dontwarn com.squareup.okhttp.** -keep class com.squareup.okhttp.** { *;} -dontwarn okio.** -keep class okio.** {*;} #json -dontwarn com.google.gson.** -keep class com.google.gson.**{*;}
ok,現在我們原料都有了,開始混淆吧!
step1:
導入ProGuard配置文件
step2:導入需要混淆的jar和第三方jar,填寫輸出文件,這里額外添加一個一個java\jre7\lib\rt.jar(具體以自己電腦環境為准)
step3:進入Process標簽頁,點擊右下角的Process!按鈕,開始混淆,很快就混淆好了
注:以上為個人的方法,不喜勿噴
關於proguard文件的配置可以參考這篇文章《android 混淆文件proguard.cfg詳解》