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空間比較大:
進(jìn)一步看下lib文件夾下的文件,可以清楚的看到不同處理器架構(gòu)文件的native庫(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)箩艺,我們可以看到我們的包小了很多:
通過(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包:
但是由于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)目之后:
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:
需要支持的處理器架構(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://proandroiddev.com/reducing-apk-size-by-using-abi-filters-and-apk-split-74a68a885f4e