Android 多CPU架構支持所需要了解的知識

Android 多CPU架構支持所需要了解的知識

Android系統目前支持以下七種不同的CPU架構:ARMv5,ARMv7 (從2010年起),x86 (從2011年起),MipS (從2012年起),ARMv8,MIPS64和x86_64 (從2014年起),每一種都關聯著一個相應的ABI。ABI是指應用基于哪種指令集來進行編譯。 如果項目中使用到了NDK,它將會生成.so文件,Android應用支持的ABI取決于APK中位于lib/ABI目錄中的.so文件,其中ABI可能是上面說過的七種ABI中的一種。 Android包管理器安裝APK時,如果在對應的lib/ABI目錄中存在.so文件的話,會自動選擇APK包中為對應系統ABI預編譯好的.so文件。當一個應用安裝在設備上,只有該設備支持的CPU架構對應的.so文件會被安裝。在x86設備上,libs/x86目錄中如果存在.so文件的 話,會被安裝,如果不存在,則會選擇armeabi-v7a中的.so文件,如果也不存在,則選擇armeabi目錄中的.so文件(因為x86設備也支 持armeabi-v7a和armeabi)。

問題

如果我們平時開發過程中沒有很好注意這些,那么就會帶來一些兼容性的問題。 比如:你的App支持armeabi-v7ax86架構,然后使用 Android Studio 新增了一個函數庫依賴,這個函數庫包含.so文件并支持更多的CPU架構,那么在某些進行上可能會發生Crash,會出現"UnsatisfiedLinkError""dlopen: failed"等等問題:

AndroidRuntime:

.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[***********] couldn't find "lib*******.so"

或者

AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: "*********.so" is 32-bit instead of 64-bit

這是因為,你添加的一些庫可能里面做了更多的架構適配,因為只要出現了這個目錄,系統就只會在這個目錄里找.so文件而不會遍歷其他的目錄,所以就出現了找不到so文件的情況(因為其他目錄沒有這個so文件)。 舉個例子來詳細說明一下:我們的APP只支持armeabi-v7a和x86架構,然后我們的APP使用了一個第三方的Library,而這個Library提供了AMR64等更多類型CPU架構的支持,構建APK的時候,這些ARM64的SO庫依然會被打包進APK里面,也就是說我們自己的SO庫沒有對應的ARM64的SO庫,而第三方的Library卻有。這時候,某些ARM64的設備安裝該APK的時候,發現我們的APK里帶有ARM64的SO庫,會誤以為我們的APP已經做好了AMR64的適配工作,所以只會選擇安裝APK里面ARM64類型的SO庫,這樣會導致我們自己項目的SO庫沒有被正確安裝(雖然armeabi-v7a和x86類型的SO庫確實存在APK包里面)。

解決辦法

給我們自己的SO庫也提供AMR64支持,或者不打包第三方Library項目的ARM64的SO庫。 使用第二種方案時,可以把APK里面不需要支持的ABI文件夾給刪除,然后重新打包,而在Android Studio下,則可以通過以下的構建方式指定需要類型的SO庫。 這個時候我們就需要使用:

defaultConfig { ...... ndk { abiFilters "", "" } }

來解決這些問題。 如果你用的Android Studio編譯器,那么abiFilters后面加的應該是jniLibs/ABI里面所支持的機型。(當然這個目錄也可以通過在build.gradle文件中的設置jniLibs.srcDir屬性自己指定)。

總結

APP多架構支持

我們平時用的so的存放位置: - Android Studio工程放在jniLibs/ABI目錄中(當然也可以通過在build.gradle文件中的設置jniLibs.srcDir屬性自己指定) - Eclipse工程放在libs/ABI目錄中(這也是ndk-build命令默認生成.so文件的目錄) - AAR壓縮包中位于jni/ABI目錄中(.so文件會自動包含到引用AAR壓縮包的APK中) - 最終這些so會放在編譯好的APK文件中的lib/ABI目錄中 所有的x86/x86_64/armeabi-v7a/arm64-v8a設備都支持armeabi架構的.so文件,x86設備能夠很好的運行ARM類型函數庫,但并不保證100%不發生crash,特別是對舊設備。64位設備(arm64-v8a, x86_64, mips64)能夠運行32位的函數庫,但是以32位模式運行,在64位平臺上運行32位版本的ART和Android組件,將丟失專為64位優化過的性能(ART,webview,media等等)。 基于這些問題,我們應該盡可能為每種CPU類型都提供對應的SO庫。 因此以減少APK包大小為由來減少架構的支持顯然不是一個好的理由,因為也可以選擇在應用市場上傳指定ABI版本的APK,生成不同ABI版本的APK可以在build.gradle中如下配置:

android { ... splits { abi { enable true reset() include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for universalApk true //generate an additional APK that contains all the ABIs } } // map for the version code

PR

oject.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9] android.

application

Variants.all { variant -> // assign different version code for each output variant.outputs.each { output -> output.versionCodeOverride = project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode } } }

NDK生成支持多種CPU架構的SO

在android NDK項目的根目錄下面有一個libs文件夾,這個文件夾下面有下面七個文件夾中的一個或者多個:arm64-v8a,armeabi,armeabi-v7a,mips,mips64,x86,x86_64。 默認情況下,NDK的編譯系統根據 “armeabi” ABI生成機器代碼。可以使用APP_ABI 來選擇一個不同的ABI,我們可以通過下面的配置來制定支持的ABI:

TARGET_CPU_API := all APP_ABI := all

或者是

TARGET_CPU_API := armeabi armeabi-v7a x86 x86_64 arm64-v8a mips mips64 APP_ABI := armeabi armeabi-v7a x86 x86_64 arm64-v8a mips mips64

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容