優(yōu)化ApK大小之ABI Filters 和 APK split

Demo例子代碼:https://github.com/sayhellotogithub/AbifiltersAndSplit

Android支持多種CPU處理器架構(gòu):

  • mips
  • mips64
  • armeabi
  • armeabi-v7a
  • arm64-v8a
  • x86
  • x86_64

想要在項(xiàng)目中使用 native 類庫(kù),我們必須對(duì)要支持的處理機(jī)框架提供對(duì)應(yīng)編譯包企锌。每個(gè)處理器架構(gòu)需要我們提供一個(gè)或多個(gè)包含native代碼的.so文件哎榴。

當(dāng)我們決定支持處理器架構(gòu)的時(shí)候寡具,相應(yīng)的APK會(huì)瘋狂的增大侥袜。對(duì)于用戶來(lái)說(shuō)設(shè)備架構(gòu)只需要一個(gè)子集芬沉,但當(dāng)用戶下載APK時(shí)望蜡,會(huì)全部下載(對(duì)用戶來(lái)說(shuō)相當(dāng)?shù)牟缓茫?/p>

通過(guò)Android Studio 查看APK文件棍厂,可以發(fā)現(xiàn)lib文件夾占用APK空間比較大:


lib文件夾

進(jìn)一步看下lib文件夾下的文件,可以清楚的看到不同處理器架構(gòu)文件的native庫(kù)的大谐毒恪:


native so庫(kù)

當(dāng)前 Google Play Store 上傳APK限制是100MB书蚪。而我們的native庫(kù)占用APK應(yīng)用一半以上的空間。為了減少APK的大小蘸吓,我們需要限制支持的處理器架構(gòu)善炫。
在這里我介紹兩種技術(shù):

  • ABI Filters
  • APK Split

ABI Filters

ABI (Application Binary Interface)是兩個(gè)程序模塊之間的接口; 通常撩幽,其中一個(gè)是庫(kù)文件或者是操作系統(tǒng)

ABI filters 可以讓我們包含進(jìn)APK里處理器架構(gòu)native文件库继。
在defaultConfig中加入如下配制:

        ndk {
            abiFilters "arm64-v8a", "armeabi-v7a"
        }

通過(guò)指定處理器的架構(gòu)箩艺,我們可以看到我們的包小了很多:


abiFilters "arm64-v8a", "armeabi-v7a"

通過(guò)abiFilters配制有利有弊,在這里以用戶角度與開(kāi)發(fā)者角角來(lái)分析下宪萄。

  • 用戶角度:APK包含了用戶用不到的類庫(kù)艺谆,造成APK變大,用戶需要花更多的網(wǎng)絡(luò)流量及下載的等待時(shí)間拜英;

  • 開(kāi)發(fā)者角度:這種方案提供了單一的APK静汤,節(jié)省開(kāi)發(fā)者的維護(hù)成本。

如果我們考慮到包大小超過(guò)100M或者用戶角度的話居凶,ABI filters不再是一個(gè)可選方案虫给。我們需要確保用戶下載的只有用戶需要的native庫(kù)。這時(shí)我們需要使用APK split 技術(shù)侠碧。

APK split

APK split 允許我們自動(dòng)生成多個(gè)APK文件抹估。我們可以通過(guò)屏幕密度(mdpi, hdpi, xhdpi…)或者處理器架構(gòu)(arm64-v8a, armeabi-v7a…)來(lái)進(jìn)行拆分。
通過(guò)處理架構(gòu)配制:

 splits{
        // Configures multiple APKs based on ABI.
        abi {
            // Enables building multiple APKs per ABI.
            enable true

            // By default all ABIs are included, so use reset() and include to specify that we only
            // want APKs for x86, armeabi-v7a, and mips.
            reset()

            // Specifies a list of ABIs that Gradle should create APKs for.
            include "x86", "x86_64", "armeabi-v7a", "arm64-v8a"

            // Specifies that we want to also generate a universal APK that includes all ABIs.
            universalApk true
        }
    }

生成Debug包:


APK split

但是由于Debug包拆分不是必須的弄兜,我們可以配制僅對(duì)release包用效药蜻。

splits {
        abi {
            def isReleaseBuild = false

            gradle.startParameter.taskNames.find {
                // Enable split for release builds in different build flavors
                // (assemblePaidRelease, assembleFreeRelease, etc.).
                if (it ==~ /:app:assemble.*Release/) {
                    isReleaseBuild = true
                    return true // break
                }

                return false // continue
            }

            // Enables building multiple APKs per ABI.
            enable isReleaseBuild
            universalApk true
        }
    }

運(yùn)行項(xiàng)目之后:


Release

Version codes

由于應(yīng)用商店不允許上傳具有相同的VersionCode的多個(gè)APK包。我們需要對(duì)每個(gè)Release包生成對(duì)應(yīng)的VersionCode替饿。

  // Map for the version code that gives each ABI a value.
    def abiCodes = ['armeabi-v7a':1, 'arm64-v8a':2,'x86':3, 'x86_64':4]

    // APKs for the same app that all have the same version information.
    android.applicationVariants.all { variant ->
        // Assigns a different version code for each output APK.
        variant.outputs.each {
            output ->
                def abiName = output.getFilter(com.android.build.OutputFile.ABI)
                output.versionCodeOverride = abiCodes.get(abiName, 0) * 100000 + variant.versionCode
        }
    }

我們通過(guò)Android Studio 查看app-arm64-v8a-release APK文件语泽,發(fā)現(xiàn)versionCode變成了20001:


app-arm64-v8a-release

需要支持的處理器架構(gòu)

由于處理器架構(gòu)為armeabi-v7a、arm64-v8a占市場(chǎng)的99%以上的份額视卢,因此我們必須要支持踱卵。

這里有一份Android 處理器架構(gòu)的匯總建議:

  • mips (已棄用)
  • mips64 (已棄用)
  • armeabi (已棄用)
  • armeabi-v7a (需要支持—?現(xiàn)在最流行的處理器架構(gòu))
  • arm64-v8a (需要支持?—?armeabi-v7a的新版本)
  • x86 (可選, 設(shè)備非常有限,可以用于模擬器debugging)
  • x86_64 (可選, 設(shè)備非常有限据过,可以用于模擬器debugging)

相關(guān)的參考

https://developer.android.com/google/play/publishing/multiple-apks.html#HowItWorks

https://medium.com/androiddevelopers/smallerapk-part-4-multi-apk-through-abi-and-density-splits-477083989006

https://proandroiddev.com/reducing-apk-size-by-using-abi-filters-and-apk-split-74a68a885f4e

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颊埃,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蝶俱,更是在濱河造成了極大的恐慌班利,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榨呆,死亡現(xiàn)場(chǎng)離奇詭異罗标,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)积蜻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門闯割,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人竿拆,你說(shuō)我怎么就攤上這事坷剧∑切疲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵颗圣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任牛郑,我火速辦了婚禮,結(jié)果婚禮上敬鬓,老公的妹妹穿的比我還像新娘淹朋。我一直安慰自己,他們只是感情好钉答,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布础芍。 她就那樣靜靜地躺著,像睡著了一般数尿。 火紅的嫁衣襯著肌膚如雪者甲。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天砌创,我揣著相機(jī)與錄音虏缸,去河邊找鬼。 笑死嫩实,一個(gè)胖子當(dāng)著我的面吹牛刽辙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甲献,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼宰缤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了晃洒?” 一聲冷哼從身側(cè)響起慨灭,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎球及,沒(méi)想到半個(gè)月后氧骤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吃引,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年筹陵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镊尺。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡朦佩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出庐氮,到底是詐尸還是另有隱情语稠,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布弄砍,位于F島的核電站仙畦,受9級(jí)特大地震影響输涕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜议泵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桃熄。 院中可真熱鬧先口,春花似錦、人聲如沸瞳收。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)螟深。三九已至谐宙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間界弧,已是汗流浹背凡蜻。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留垢箕,地道東北人划栓。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像条获,于是被迫代替她去往敵國(guó)和親忠荞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容