Android打包aar後private可見性變public的問題及解決

Android打包aar後private可見性變public的問題及解決

問題

在編寫SDK的過程中發現,打包後的aar中一些類的private方法及變量居然全都變成了public,使用時全都可以隨便調用了!
有趣
這咋成?上面全都是private方法(實際private屬性也都變了),都叫a是因爲被混淆過

原因

排查發現問題發生在使用proguard進行混淆SDK之後,但是實際上因爲SDK邏輯比較簡單,proguard配置也很簡略,只有keep一些需要暴露出去的public的方法而已,也沒聽說會修改到private呀。最終還是在官方文檔找到了嫌疑人:

-allowaccessmodification
Specifies that the access modifiers of classes and class members may be broadened during processing. This can improve the results of the optimization step. For instance, when inlining a public getter, it may be necessary to make the accessed field public too. Although Java’s binary compatibility specifications formally do not require this (cfr. The Java Language Specification, Third Edition,Section 13.4.6), some virtual machines would have problems with the processed code otherwise. Only applicable when optimizing (and when obfuscating with the-repackageclasses option). Counter-indication: you probably shouldn’t use this option when processing code that is to be used as a library, since classes and class members that weren’t designed to be public in the API may become public.

簡單說就是允許proguard拓寬某些類以及類成員的可見性,以使其在混淆的優化(optimize)階段能夠優化得更好。同時也說了,不要在寫一個庫的時候使用這個選項,它會把原本想要隱藏的private方法暴露出去。

ok看樣子問題就是出在這個allowaccessmodification上,那我們就把它給刪了吧!收工!

等會,仔細一看我們的proguard-rules.pro裏並沒寫這個啊,也沒在文檔裏找到類似dontallowaccessmodification的選項,看上去是默認關閉的,那隻能是某個默認幫我們配置了混淆的地方,於是我們自然想到了build.gradle

android {
	...
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

這是我們在Android Studio中新建一個Module時,IDE自動幫我們作好的配置(當然一開始minifyEnabledfalse的),proguard-android-optimize.txt是Android的一些通用配置,主要是對Activity、View等Android組件、native方法、枚舉還有混淆註解@Keep提供混淆。同時它開啓並提供了一些優化選項,其中就有allowaccessmodification
就素它!
在Android gradle plugin 2.2之前這個文件在$ANDROID_HOME/tools/proguard/lib下,而2.2之後則是包括在gradle plugin中,並在build時動態生成的(可以追溯上面的getDefaultProguardFile方法後看到具體的生成方法)。在編譯後可以在[module]/build/intermediates/proguard-files中找到,同時它還有兩個類似的兄弟proguard-android.txtproguard-defaults.txt。另外可以看到文件名後綴有3.5.0,這是項目的gradle版本號。

解決

最根本的原因是最終的混淆配置中有allowaccessmodification ,只要想辦法不引入這一條就能解決問題,那我們可以:

1.使用另一個不開啓優化的proguard-android.txt

注意最後剩下的proguard-defaults.txt,在內容上跟proguard-android-optimize.txt是一樣的。

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

而這樣做的缺點是解決方式的粒度要稍大一些,只是爲了取消allowaccessmodification,但把整個optimize過程都取消了,有沒有辦法能既去掉這個選項,又保留optimize過程呢?

2.只使用自定義的proguard-rules.pro文件,同時手動合併默認文件中我們所需要的配置

buildTypes {
    release {
        minifyEnabled true
        proguardFiles 'proguard-rules.pro'
    }
}

這麼做是可行的,因爲實際上proguradFiles這個方法是這樣的:

@NonNull
public BuildType proguardFiles(@NonNull Object... files) {
    checkPostProcessingConfiguration(PostProcessingConfiguration.OLD_DSL, "proguardFiles");
    for (Object file : files) {
        proguardFile(file);
    }
    return this;
}

它接受一個可變數量的參數files,然後合併這些文件。默認的proguard.txt只是爲了方便使用,當然也可以不去用它。

這樣的好處是仍然保留了optimize過程,並且,整個混淆配置都在同一個自己定義的文件中,管理時都在自己可見的範圍內,而不是在build文件夾裏藏的很深。

缺點是,默認的混淆文件是跟gradle plugin版本相關的,這樣拷貝出來可能無法及時同步一些升級gradle後新增或者修改的內容。

總結

1.allowaccessmodification可能會導致打包後的方法和屬性的可見性拓寬

2.通用配置proguard-android-optimize.txt中包含allowaccessmodification選項

3.可以只使用自定義的proguard-rules.pro文件進行混淆

參考

官方文檔(看什麼都沒這個強)

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