最近在研究APP瘦身,碰巧又遇到armeabi、armeabi-v7a、arm64-v8a等ABI相關的知識點,決心記錄下來以作分享。
目前現狀
首先我們分析下國內的淘寶、微信,以及國外的Facebook、Twitter都使用了哪些ABI。
我們對這4家APK進行Analyze,可以發現Facebook和Twitter只使用了armeabi-v7a,而微信和淘寶只使用了armeabi,分析結果如下圖所示:
大廠並沒有按照我們的理解使用不同的ABI針對不同的CPU?其實筆者發現攜程、餓了麼、百度糯米都是隻使用了armeabi,阿里系的淘票票使用了armeabi、x86(如果你有興趣,可以通過爬取分析一下應用市場的前100名都使用了哪些ABI)。知識點回顧
首先,我們來看下Google老大哥是怎麼介紹的ABI的,翻譯官方文件:
不同 Android 手機使用不同的 CPU,因此支援不同的指令集
CPU 與指令集的每種組合都有其自己的應用二進位制介面(或 ABI)
ABI 可以非常精確地定義應用的機器程式碼在執行時如何與系統互動
您必須為應用要使用的每個 CPU 架構指定 ABI
表 1. ABI 和支援的指令集。
各版本分析如下:- mips / mips64: 極少用於手機可以忽
- x86 / x86_64: x86 架構的手機都會包含由 Intel 提供的稱為 Houdini 的指令集動態轉碼工具,實現對 arm .so 的相容,再考慮 x86 1% 以下的市場佔有率,x86 相關的兩個 .so 也是可以忽略的
- armeabi: ARM v5 這是相當老舊的一個版本,缺少對浮點數計算的硬體支援,在需要大量計算時有效能瓶頸
- armeabi-v7a: ARM v7 目前主流版本
- arm64-v8a: 64位支援
具體含義
如果你基礎比較好的話,看完Google老大哥的介紹的話,就明白了:不同的 CPU 支援不同的指令集。當我們需要我們APP支援儘可能多的不同CPU的時候,只需要將不同版本的so檔案放置在不同的目錄下,APK安裝執行的時候會根據自己需要而自己選取。
但是這樣卻帶來一個問題,APK檔案較大,影響使用者下載。
那我們是否可以只放置一些呢?
必然可以!
我們繼續看Google老大哥是怎麼說的:
- 為實現最佳效能,應直接針對主要 ABI進行編譯。例如,基於 ARMv5TE的典型裝置只會定義主要 ABI:armeabi
- 相反,基於ARMv7的典型裝置將主要ABI定義為armeabi-v7a,而將輔助ABI定義為armeabi,因為它可以執行為每個ABI生成的應用原生二進位制檔案
- 許多基於x86的裝置也可行 armeabi-v7a 和 armeabi NDK 二進位制檔案
- 對於這些裝置,主要ABI將是 x86,輔助ABI是armeabi-v7a
- 基於 MIPS的典型裝置只定義主要ABI:mips
- 安裝應用時,軟體包管理器服務將掃描APK,查詢以下形式的任何共享庫:
lib/<primary-abi>/lib<name>.so 複製程式碼
- 如果未找到,並且您已定義輔助 ABI,該服務將掃描以下形式的共享庫:
lib/<secondary-abi>/lib<name>.so 複製程式碼
- 找到所需的庫時,軟體包管理器會將它們複製到應用的 data 目錄 (data/data/<package_name>/lib/) 下的/lib/lib.so
分析
上面說,如果根本沒有共享物件檔案,應用也會構建並安裝,但在執行時會崩潰。所以有時候我們遇到
Exception:Java.lang.UnsatisfiedLinkError: dlopen failed: library “/***.so” not found
複製程式碼
此時我們首先要想到的,是不是so檔案沒有放置,或者是在armeabi放置a.so,b.so,但是在armeabi-v7a只放置了b.so,沒有放置a.so。
這裡強調一下:雖然arm64-v8a是可以向下相容的,但是也是相容的有限制的:
其下有armeabi-v7a,armeabi ;armeabi-v7a向下相容armeabi。對於一個cpu是arm64-v8a架構的手機,它執行app時,進入jnilibs去讀取庫檔案時,先看有沒有arm64-v8a資料夾,如果沒有該資料夾,去找armeabi-v7a資料夾,如果沒有,再去找armeabi資料夾,如果連這個資料夾也沒有,就丟擲異常; 如果有arm64-v8a資料夾,那麼就去找特定名稱的.so檔案。 如果有arm64-v8a資料夾,那麼就去找特定名稱的.so檔案,注意:如果沒有找到,不會再往下(armeabi-v7a資料夾)找了,而是直接丟擲異常。
注意:
- 如果沒有找到,不會再往下(armeabi-v7a資料夾)找了,而是直接丟擲異常。
- 如果你的專案用到了第三方依賴,如果只保留一個ABI的時候,建議在Build中加入ndk.abiFilters
- 例如:第三方aar檔案,如果這個sdk對abi的支援比較全,可能會包含armeabi、armeabi-v7a、x86、arm64-v8a、x86_64五種abi,而你應用的其它so只支援armeabi、armeabi-v7a、x86三種,直接引用sdk的aar,會自動編譯出支援5種abi的包。但是應用的其它so缺少對其它兩種abi的支援,那麼如果應用執行於arm64-v8a、x86_64為首選abi的裝置上時,就會==crash==了哦。
defaultConfig {
ndk {
abiFilters "armeabi"// 指定ndk需要相容的ABI(這樣其他依賴包裡x86,armeabi,arm-v8之類的so會被過濾掉)
}
}
複製程式碼
總結
-
如果你希望APK針對不同CPU有不同的版本,你可以使用胖二進位制的方式,在不同的目錄下面放置不同的so檔案。這樣相容性更廣、效能好些,但是APK大些;
-
如果你希望APK小一些,你可以像淘寶、微信、FaceBook、Twitter一樣,一個api闖天下,至於選擇armeabi、armeabi-v7a看你市場使用者了。目前主流手機cpu多屬於armeabi-v7a;
-
當然,你也可以動態檢查系統環境,如果是x86就去下載相關庫,然後載入......這樣可以減少apk體積。
作者:微信公眾號新增公眾號-遛狗的程式設計師 ,或者可以掃描以下二維碼關注相關技術文章。
當然喜愛技術,樂於分享的你也可以可以新增作者微訊號: