? ? ? ? 最近公司的項(xiàng)目需要把現(xiàn)在已有的項(xiàng)目打包成一個(gè)aar包給第三方合作方遏餐,在從原來(lái)的app生成一個(gè)apk文件,變?yōu)橐粋€(gè)aar的輸出過(guò)程中家浇,遇到了一些問(wèn)題瘫寝,也隨便根據(jù)網(wǎng)上的資料了解了關(guān)于生成一個(gè)aar包需要注意的相關(guān)知識(shí)點(diǎn),下面就帶大家一起看看一個(gè)已有項(xiàng)目及汉,生成一個(gè)aar可能遇到的問(wèn)題和項(xiàng)目知識(shí)點(diǎn)匯總吧沮趣。
相關(guān)知識(shí)點(diǎn)匯總:
一:打包相關(guān)的指令使用?
二:生成aar需要注意的事項(xiàng)?
三:混淆基礎(chǔ)知識(shí)與aar與jar如何做混淆?
四:遇到的問(wèn)題匯總?
五:擴(kuò)展閱讀
一:打包相關(guān)的指令使用
指令一:gradlew webpdecoder:aR(assemble Release)
解析:編譯webpdecoder Module release版本
指令二:gradlew clean webpdecoder:aR(assemble Release)
解析:清除webpdecoder Module的緩存數(shù)據(jù)
指令三:gradlew webpdecoder:artifactoryPublish -P verName=1.0.0 -P verCode=1000000
解析:編譯webpdecoder的相關(guān)版本到遠(yuǎn)程artifactory庫(kù)
指令四:gradlew app:assembleZhaoxi
解析:編譯app Module的Zhaoxi版本
備注:jar與aar的簡(jiǎn)單區(qū)別
*.jar:只包含了class文件與清單文件,不包含資源文件坷随,如圖片等所有res中的文件房铭。
*.aar:包含所有資源 驻龟,class以及res資源文件全部包含。
二:生成aar需要注意的事項(xiàng)
注意事項(xiàng)一:主項(xiàng)目需要依賴AAR中所依賴的遠(yuǎn)程庫(kù)缸匪,否則會(huì)出現(xiàn)ClassNotFound異常
這里也許某個(gè)依賴庫(kù)你們的版本會(huì)發(fā)生沖突翁狐,這就需要你們協(xié)調(diào)了。
注意事項(xiàng)二:資源命名最好統(tǒng)統(tǒng)加上你的項(xiàng)目名字前綴豪嗽,比如圖片資源谴蔑、string、color龟梦、dimens隐锭、layout等等,反正res目錄下所有文件最好都使用統(tǒng)一的加前綴命名计贰,防止跟宿主app下的資源重復(fù)钦睡,因?yàn)閍ar引用跟源碼引用起到的效果一樣一樣的,所有很容易出現(xiàn)資源重復(fù)引用的問(wèn)題躁倒,所以加上前綴非常有必要荞怒。
android {
????resourcePrefix "<前綴>"
}
需要說(shuō)明的是,resourcePrefix 只是起約束作用秧秉,不會(huì)自動(dòng)幫你修改資源的名稱褐桌,我們需要手動(dòng)加上前綴,否則報(bào)錯(cuò)象迎。
注意事項(xiàng)三:如果該aar包里面有微信支付荧嵌,分享等第三方庫(kù),你要在主工程中使用砾淌,要記得在gradle里面替換applicationId啦撮,或者用你主工程的包名和key去獲取第三方操作的key和id,以分享為例汪厨,如果你清單文件中的分享KEY與主項(xiàng)目中的build gradle文件中的分享KEY不同的話赃春,就會(huì)報(bào)清單文件異常的。
注意事項(xiàng)四:butterknife需要統(tǒng)一用8.4.0以上的版本劫乱,不然報(bào)錯(cuò) 织中;依我的建議,最好不用衷戈,否則有你好受的抠璃。
注意事項(xiàng)五:如果在aar的MyAppliction里面使用了類(lèi)的管理器,那么在打包成aar的時(shí)候需要將代碼抽出來(lái)做個(gè)獨(dú)立的類(lèi)管理器脱惰,記住一點(diǎn),打包成aar之后所有和application有關(guān)的東西都要檢查替換窿春,避免出現(xiàn)空指針異常拉一。
注意事項(xiàng)六:AAR模塊用butterknife需要把資源R改為R2(批量替換)
注意事項(xiàng)七:布局文件不要重名采盒,否則會(huì)報(bào)找不到Id的異常
注意事項(xiàng)八:aar不能使用assets原始資源工具,不支持在庫(kù)模塊中使用原始資源文件(保存在 assets/ 目錄中)蔚润,使用的任何原始資源都必須存儲(chǔ)在應(yīng)用模塊自身的assets/目錄中磅氨。
2.1、成型的項(xiàng)目(有依賴)如何快速打包AAR
第一步:修改app下的bulid gradle文件嫡纠,把a(bǔ)pply plugin: 'com.android.application’修改成apply plugin: ‘com.android.library’
第二步:注釋調(diào)defaultConfig下的applicationId
第三步:AndroidManifest.xml文件烦租,修改application并且注釋調(diào)首先啟動(dòng)的Activity啟動(dòng)的action
第四步:如果你自己自定義了Application,需要去掉除盏,因?yàn)锳AR中是沒(méi)有Application的叉橱,那問(wèn)題來(lái)了,我們?cè)瓉?lái)在Application中的初始化代碼怎么辦者蠕?這個(gè)簡(jiǎn)單窃祝,我們可以單獨(dú)寫(xiě)一個(gè)Options類(lèi),提供給調(diào)用者踱侣,讓他傳遞過(guò)來(lái)application粪小,這樣我們就可以在這個(gè)類(lèi)中做一些初始化操作了。
三:混淆基礎(chǔ)知識(shí)與aar與jar如何做混淆
3.1抡句、ProGuard作用
1探膊、壓縮(Shrinking):默認(rèn)開(kāi)啟,用以減小應(yīng)用體積待榔,移除未被使用的類(lèi)和成員逞壁,并且會(huì)在優(yōu)化動(dòng)作執(zhí)行之后再次執(zhí)行(因?yàn)閮?yōu)化后可能會(huì)再次暴露一些未被使用的類(lèi)和成員)。如果想要關(guān)閉壓縮究抓,在proguard-rules.pro文件中加入:
# 關(guān)閉壓縮
-dontshrink
2猾担、優(yōu)化(Optimization):默認(rèn)開(kāi)啟,在字節(jié)碼級(jí)別執(zhí)行優(yōu)化刺下,讓?xiě)?yīng)用運(yùn)行的更快绑嘹。同上,如果想要關(guān)閉優(yōu)化橘茉,在proguard-rules.pro文件中加入:
# 關(guān)閉優(yōu)化
-dontoptimize
-optimizationpasses n 表示proguard對(duì)代碼進(jìn)行迭代優(yōu)化的次數(shù)工腋,Android一般為5
3、混淆(Obfuscation):默認(rèn)開(kāi)啟畅卓,增大反編譯難度擅腰,類(lèi)和類(lèi)成員會(huì)被隨機(jī)命名,除非用keep保護(hù)翁潘。
# 關(guān)閉混淆
-dontobfuscate
備注:混淆后默認(rèn)會(huì)在工程目錄app/build/outputs/mapping/release下生成一個(gè)mapping.txt文件趁冈,這就是混淆規(guī)則,我們可以根據(jù)這個(gè)文件把混淆后的代碼反推回源本的代碼,所以這個(gè)文件很重要渗勘,注意保護(hù)好沐绒。
3.2、實(shí)現(xiàn)保持不混淆的兩種方法:
方法一:使用@Keep注解
在proguard-rules.pro配置文件中加入以下規(guī)則
#手動(dòng)啟用support keep注解
#http://tools.android.com/tech-docs/support-annotations
-dontskipnonpubliclibraryclassmembers
-printconfiguration
-keep,allowobfuscation @interface android.support.annotation.Keep
-keep @android.support.annotation.Keep class *
-keepclassmembers class * {
@android.support.annotation.Keep *;
}
方法二:proguard-rules.pro中添加不混淆規(guī)則
添加相關(guān)配置:
buildTypes {
release {
minifyEnabled true //true開(kāi)啟混淆配置旺坠,false關(guān)閉
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.duqian_android_keystore
}
debug{//省略}
}
proguard-rules.pro 文件來(lái)定義項(xiàng)目打包的混淆選項(xiàng)模板:
#--------------------------1.實(shí)體類(lèi)---------------------------------
# 如果使用了Gson之類(lèi)的工具要使被它解析的JavaBean類(lèi)即實(shí)體類(lèi)不被混淆乔遮。(這里填寫(xiě)自己項(xiàng)目中存放bean對(duì)象的具體路徑)
-keep class com.php.soldout.bean.**{*;}
#--------------------------2.第三方包-------------------------------
#Gson
-keepattributes Signature
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keep class com.google.gson.* { *;}
-dontwarn com.google.gson.**
#butterknife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
#-------------------------3.與js互相調(diào)用的類(lèi)------------------------
#-------------------------4.反射相關(guān)的類(lèi)和方法----------------------
#-------------------------5.基本不用動(dòng)區(qū)域--------------------------
#指定代碼的壓縮級(jí)別
-optimizationpasses 5
#包明不混合大小寫(xiě)
-dontusemixedcaseclassnames
#不去忽略非公共的庫(kù)類(lèi)
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
#混淆時(shí)是否記錄日志
-verbose
#優(yōu)化??不優(yōu)化輸入的類(lèi)文件
-dontoptimize
#預(yù)校驗(yàn)
-dontpreverify
# 保留sdk系統(tǒng)自帶的一些內(nèi)容 【例如:-keepattributes *Annotation* 會(huì)保留Activity的被@override注釋的onCreate、onDestroy方法等】
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
# 記錄生成的日志數(shù)據(jù),gradle build時(shí)在本項(xiàng)根目錄輸出
# apk 包內(nèi)所有 class 的內(nèi)部結(jié)構(gòu)
-dump proguard/class_files.txt
# 未混淆的類(lèi)和成員
-printseeds proguard/seeds.txt
# 列出從 apk 中刪除的代碼
-printusage proguard/unused.txt
# 混淆前后的映射
-printmapping proguard/mapping.txt
# 避免混淆泛型
-keepattributes Signature
# 拋出異常時(shí)保留代碼行號(hào),保持源文件以及行號(hào)
-keepattributes SourceFile,LineNumberTable
#-----------------------------6.默認(rèn)保留區(qū)-----------------------
# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclassmembers public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(***);
}
}
#保持 Serializable 不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 保持自定義控件類(lèi)不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context,android.util.AttributeSet);
}
# 保持自定義控件類(lèi)不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context,android.util.AttributeSet,int);
}
# 保持自定義控件類(lèi)不被混淆
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# 保持枚舉 enum 類(lèi)不被混淆
-keep classmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 不混淆R文件中的所有靜態(tài)字段取刃,我們都知道R文件是通過(guò)字段來(lái)記錄每個(gè)資源的id的蹋肮,字段名要是被混淆了,id也就找不著了璧疗。
-keep classmembers class **.R$* {
public static <fields>;
}
#如果引用了v4或者v7包
-dontwarn android.support.**
# 保持哪些類(lèi)不被混淆
-keep public class * extends android.app.Application
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.preference.Preference
-keep class com.zhy.http.okhttp.**{*;}
-keep class com.wiwide.util.** {*;}
# ============忽略警告坯辩,否則打包可能會(huì)不成功=============
-ignorewarnings
混淆的一些基本規(guī)則:
規(guī)則一:一顆星
解析:表示只是保持該包下的類(lèi)名,而子包下的類(lèi)名還是會(huì)被混淆病毡;
-keep class cn.hadcn.test.*
規(guī)則二:兩顆星
解析:表示把本包和所含子包下的類(lèi)名都保持濒翻;用以上方法保持類(lèi)后,你會(huì)發(fā)現(xiàn)類(lèi)名雖然未混淆啦膜,但里面的具體方法和變量命名還是變了有送。
-keep class cn.hadcn.test.**
規(guī)則三:既想保持類(lèi)名,又想保持里面的內(nèi)容不被混淆
解析:-keep class cn.hadcn.test.* {*;}
規(guī)則四:用extends僧家,implements等這些Java規(guī)則雀摘,避免所有繼承Activity的類(lèi)被混淆
解析:-keep public class * extends android.app.Activity
規(guī)則五:保留一個(gè)類(lèi)中的內(nèi)部類(lèi)不被混淆則需要用$符號(hào),如下例子表示保持ScriptFragment內(nèi)部類(lèi)JavaScriptInterface中的所有public內(nèi)容不被混淆八拱。
解析:-keepclassmembers class cc.ninty.chat.ui.fragment.ScriptFragment$JavaScriptInterface {
public *;
}
規(guī)則六:保護(hù)類(lèi)下的特定內(nèi)容阵赠,<fields>或<methods>前面加上private 、public肌稻、native等來(lái)進(jìn)一步指定不被混淆的內(nèi)容
解析:
<init>;?????//匹配所有構(gòu)造器
<fields>;???//匹配所有域
<methods>;??//匹配所有方法
-keep class cn.hadcn.test.One {
????public <methods>;
}
規(guī)則七:One類(lèi)下的所有public方法都不會(huì)被混淆清蚀,還可以加入?yún)?shù),比如以下表示用JSONObject作為入?yún)⒌臉?gòu)造函數(shù)不會(huì)被混淆爹谭。
解析:
-keep class cn.hadcn.test.One {
????public <init>(org.json.JSONObject);
}
規(guī)則八:不需要保持類(lèi)名枷邪,只需要把該類(lèi)下的特定方法保持不被混淆,需要用keepclassmembers 诺凡,如此類(lèi)名就不會(huì)被保持
解析:
Android混淆的方法和通配符對(duì)照表:
Proguard關(guān)鍵字
不需要混淆的類(lèi)匯總:
一:jni方法不可混淆东揣,因?yàn)檫@個(gè)方法需要和native方法保持一致
# 保持native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
二:反射用到的類(lèi)不混淆(否則反射可能出現(xiàn)問(wèn)題)
三:AndroidMainfest中的類(lèi)不混淆,所以四大組件和Application的子類(lèi)和Framework層下所有的類(lèi)默認(rèn)不會(huì)進(jìn)行混淆腹泌,自定義的View默認(rèn)也不會(huì)被混淆嘶卧。所以像網(wǎng)上貼的很多排除自定義View,或四大組件被混淆的規(guī)則在Android Studio中是無(wú)需加入的
四:與服務(wù)端交互時(shí)凉袱,使用GSON芥吟、fastjson等框架解析服務(wù)端數(shù)據(jù)時(shí),所寫(xiě)的JSON對(duì)象類(lèi)不混淆,否則無(wú)法將JSON解析成對(duì)應(yīng)的對(duì)象
五:使用第三方開(kāi)源庫(kù)或者引用其他第三方的SDK包時(shí)运沦,如果有特別要求泵额,也需要在混淆文件中加入對(duì)應(yīng)的混淆規(guī)則
六:有用到WebView的JS調(diào)用也需要保證寫(xiě)的接口方法不混淆
七:Parcelable的子類(lèi)和Creator靜態(tài)成員變量不混淆,否則會(huì)產(chǎn)生Android.os.BadParcelableException異常
# 保持Parcelable不被混淆
-keep class * implements Android.os.Parcelable {
public static final Android.os.Parcelable$Creator *;
}
八:使用enum類(lèi)型時(shí)需要注意避免以下兩個(gè)方法混淆携添,因?yàn)閑num類(lèi)的特殊性,以下兩個(gè)方法會(huì)被反射調(diào)用
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
備注:發(fā)布一款應(yīng)用除了設(shè)minifyEnabled為ture篓叶,你也應(yīng)該設(shè)置zipAlignEnabled為true烈掠,像Google Play強(qiáng)制要求開(kāi)發(fā)者上傳的應(yīng)用必須是經(jīng)過(guò)zipAlign的,zipAlign可以讓安裝包中的資源按4字節(jié)對(duì)齊缸托,這樣可以減少應(yīng)用在運(yùn)行時(shí)的內(nèi)存消耗左敌。
四:遇到的問(wèn)題匯總
問(wèn)題一:AAR 內(nèi)部三方庫(kù)依賴的問(wèn)題
解析:項(xiàng)目的開(kāi)發(fā)過(guò)程中,發(fā)現(xiàn)一個(gè)問(wèn)題:
使用 Android Studio 打包出來(lái)的 AAR 俐镐,不會(huì)將其依賴的三方庫(kù)打包進(jìn)去矫限。
舉個(gè)例子,library Test 依賴了 okhttp,打包成了 Test.aar ,app 使用本地方式引用了 Test.aar佩抹,但是無(wú)法使用 okhttp叼风,為了不報(bào)錯(cuò),app還需要添加 okhttp 依賴棍苹。
Google Android Studio 的負(fù)責(zé)人在 stackoverflow 上解釋了 為什么 Android Studio 不能將多個(gè)依賴打包進(jìn)一個(gè) AAR 文件的原因无宿,是因?yàn)閷⒉煌膌ibrary打包在一起,涉及到資源和配置文件智能合并枢里,所以是個(gè)比較復(fù)雜的問(wèn)題孽鸡,同時(shí)也容易造成相同的依賴沖突。
這個(gè)問(wèn)題可以通過(guò)使用 Maven依賴解決栏豺,因?yàn)閘ibrary Module上傳Maven后彬碱,會(huì)生成一個(gè).pom 文件,記錄library Module 的依賴奥洼。當(dāng) Gradle依賴Maven上的這個(gè)庫(kù)時(shí)巷疼,會(huì)通過(guò)pom文件下載對(duì)應(yīng)依賴。如果不想要對(duì)應(yīng)依賴的話溉卓,可以通過(guò)下面的方法關(guān)閉 Gradle的依賴傳遞皮迟。
舉個(gè)例子如下:
//正常依賴
implementation 'com.chemao.android:chemao-sdk:1.2.3'
//關(guān)閉全部依賴傳遞-方法1
implementation 'com.chemao.android:chemao-sdk:1.2.3@aar'
//關(guān)閉全部依賴傳遞-方法2
implementation('com.chemao.android:chemao-sdk:1.2.3') {
????transitive = false
}
問(wèn)題二:提示無(wú)法找到ninja相關(guān)指令
解析:需要把SDK相關(guān)bin相關(guān)文件..Sdk\cmake\3.10.2.4988404\bin配置到環(huán)境變量中,添加到環(huán)境變量Path路徑中。
問(wèn)題三:無(wú)法找到文件build\intermediates\proguard-files\proguard-android.txt-3.1.3文件
解析:自己在項(xiàng)目中添加build等文件夾,并添加proguard-android.txt-3.1.3文件翔横,proguard-android.txt文件的可以在
Sdk\tools\proguard目錄下找到深胳。
問(wèn)題四:NDK的版本需要降級(jí),否則無(wú)法編譯
解析:在tools菜單的SDK Manager中窍育,下載舊版本的NDK缭黔。
五:擴(kuò)展閱讀
1币旧、http://www.reibang.com/p/f391d0a6691e(Android-打包AAR步驟以及最為關(guān)鍵的注意事項(xiàng)1嫱肌)
2班套、https://blog.csdn.net/fesdgasdgasdg/article/details/76560341(Android 中.aar文件生成方法與用法)
3、http://www.reibang.com/p/8f7e32015836(合并AAR踩坑之旅)
4故河、https://blog.csdn.net/qq_32452623/article/details/79220522(Android-少不了的 AAR 文件常識(shí)吱韭,最好知道的注意事項(xiàng))
5、https://www.pianshen.com/article/9986545936/(Android SDK開(kāi)發(fā)之a(chǎn)ar從0到1 踩坑史)
6鱼的、https://blog.csdn.net/p876643136/article/details/90668769(android打包混淆及語(yǔ)法規(guī)則詳解)
7理盆、http://www.reibang.com/p/be7ec1819d2f?utm_campaign=maleskine&utm_content=note&utm_medium=
seo_notes&utm_source=recommendation(Android優(yōu)雅的進(jìn)行混淆——使用@Keep注解)
8、https://www.cnblogs.com/renhui/p/9299786.html(Android代碼混淆配置總結(jié))