一鍵檢索未適配 64 位架構(gòu)的 so 文件

點(diǎn)贊關(guān)注,不再迷路贴彼,你的支持對我意義重大泛粹!

?? Hi,我是丑丑截亦。本文 GitHub · Android-NoteBook 已收錄,這里有 Android 進(jìn)階成長路線筆記 & 博客柬讨,歡迎跟著彭丑丑一起成長崩瓤。(聯(lián)系方式 & 入群方式在 GitHub)


前言

  • 最近,各大應(yīng)用市場都在推動(dòng)應(yīng)用支持 64 位架構(gòu)踩官,你的 App 已經(jīng)支持了嗎却桶?
  • 在這篇文章里,我將帶你完成 64 位架構(gòu)的的適配工作蔗牡。同時(shí)會(huì)帶你建立關(guān)于 ABI 的基本認(rèn)識(shí)颖系,并為你帶來我的 Gradle 插件 EasyPrivacy,幫助你檢測工程中的 64 位適配問題辩越。如果能幫上忙嘁扼,請務(wù)必點(diǎn)贊加關(guān)注,這真的對我非常重要黔攒。

目錄


1. 概述

1.1 CPU 和 ABI 的關(guān)系

CPU 架構(gòu)是 CPU 廠商定義的 CPU 規(guī)范趁啸,目前主流的 CPU 架構(gòu)分為兩大類:

  • 復(fù)雜指令集(CISC): 例如 Intel 和 AMD 的 X86 架構(gòu);
  • 精簡指令集(RISC): 例如 IBM 的 PowerPC 架構(gòu)督惰、ARM 的 ARM 架構(gòu)不傅。

應(yīng)用二進(jìn)制接口(Application Binary Interface, ABI)定義了機(jī)器代碼和操作系統(tǒng)的交互,與我們熟知 API 會(huì)以一個(gè)接口源碼實(shí)體存在不同赏胚,ABI 更應(yīng)該理解為一種規(guī)范访娶。 ABI 包含信息詳見 Android ABI —— 官方文檔

1.2 Android 支持 的 ABI

不同的 Android 設(shè)備使用不同的 CPU,不同 CPU 支持的 ABI 也不同觉阅。目前崖疤,Android 設(shè)備支持的 ABI 類型如下:

ABI 描述
armeabi 第 5 代、第 6 代的ARM 處理器留拾,基本退出歷史舞臺(tái)
armeabiv-v7a 第 7 代及以上的 ARM 處理器戳晌,正在逐步退出歷史舞臺(tái)
arm64-v8a 第 8 代、64 位 ARM 處理器痴柔,目前是主流
x86 / x86_64 一般是模擬器

不同 CPU 支持的 ABI 情況如下:

armeabi armeabi-v7a arm64-v8a x86 x86_64 mips mips64
ARMv5 /
ARMv6
?
ARMV7 ? ?
ARMV8 ? ? ?
X86 ? ? ?
X86-64 ? (不支持) ? ?
MIPS ?
MIPS64 ? ?

提示: 通過 Build.SUPPORTED_ABIS 可以得到設(shè)備支持的 ABI 列表沦偎,并且是按照偏好排序的。

1.3 主要 ABI 和輔助 ABI

每個(gè) CPU 架構(gòu)都有一個(gè)主要 ABI 和(可選的)兼容的輔助 ABI,64 位 CPU 可以兼容 32 位 ABI(例如 x86_64 兼容 x86豪嚎,反過來不行)搔驼。 需要注意的是:只有使用主要 ABI 才能獲得最佳性能(例如 x86 兼容 armeabi ),這就是應(yīng)用市場著手推動(dòng) 64 位架構(gòu)適配的根本原因侈询。


2. 為 Android 設(shè)備適配 64 位架構(gòu)

2.1 64 位架構(gòu)適配的時(shí)間節(jié)點(diǎn)

海外應(yīng)用市場早在 19 年就在推進(jìn) 64 位架構(gòu)的適配舌涨,從 2019 年 8 月 1 日起,在 Google Play 上發(fā)布的應(yīng)用就必須支持 64 位架構(gòu)扔字。至于國內(nèi)應(yīng)用市場囊嘉,大致的時(shí)間節(jié)點(diǎn)如下(以 小米、VIVO革为、OPPO 為例):

  • 至 2021 年 12 月底扭粱,在應(yīng)用市場發(fā)布的應(yīng)用必須支持 64 位架構(gòu);
  • 至 2022 年 8 月底震檩,對于支持 64 位的硬件系統(tǒng)琢蛤,將只接收 64 位版本的 APK;
  • 至 2023 年 12 月底抛虏,硬件將僅支持 64 位 APK博其,

2.2 Android 系統(tǒng) ABI 管理

在安裝應(yīng)用時(shí),PMS 服務(wù)將掃描 APK 文件迂猴,從中查找出 APK 中主要 ABI 類型的 so 文件:

lib/<primary-abi>/lib<name>.so

如果沒有找到慕淡,則會(huì)去查找 APK 文件中輔助 ABI 類型的 so 文件:

lib/<secondary-abi>/lib<name>.so

完成查找后,PMS 會(huì)將它們復(fù)制到 app 目錄下的 so 庫路徑(例如:/data/app/[packagename]/lib/arm64)错忱,并在應(yīng)用運(yùn)行時(shí)執(zhí)行到 System.loadLibrary(...) 時(shí)加載到內(nèi)存中儡率。如果沒有查找到匹配的 so 文件,不會(huì)中斷安裝過程以清,但在運(yùn)行時(shí)會(huì)崩潰儿普。

關(guān)于加載 so 文件的過程,我們在 《說說 so 庫從加載到卸載的全過程》 這篇文章里已經(jīng)討論過了掷倔。你可以回去看看眉孩,主要源碼在:DexPathList.java

—— 圖片引用自愛奇藝技術(shù)團(tuán)隊(duì)

可以看到,適配 64 位架構(gòu)到底是做什么呢勒葱?說到底就是為系統(tǒng)提供性能最高的主要 ABI so 文件浪汪。 上層應(yīng)用的重點(diǎn)就是提供 64 位的 so 文件,我們可以將需要做的事情拆解為三部分:

  • 1凛虽、檢索不支持 64 位 的 so 文件(EasyPrivacy 插件)
  • 2死遭、構(gòu)建 64 位 APK
  • 3、分發(fā) 64 位 APK

3. EasyPrivacy 插件檢索 so 文件

關(guān)于如何檢索 APK 中不支持 64 位 的 so 文件凯旋,官方提供了兩種方法呀潭,具體可參考 官方文檔

  • 1钉迷、通過 APK 分析器分析(直接將 APK 拖到 Android Studio 上);
  • 2钠署、解壓縮 APK 并通過 grep 命令來分析糠聪。

這兩種方法基本可以滿足要求,但操作上太費(fèi)時(shí)間谐鼎,也無法直接提示 so 文件是通過哪個(gè)組件來集成的 (例如舰蟆,push.aar 內(nèi)部集成了 libc++_shared.so,通過 APK 知曉該 so 文件是來自 push.aar)狸棍。為了快速檢索到項(xiàng)目中不支持 64 位 的 so 文件身害,貼心的我已經(jīng)幫你實(shí)現(xiàn)為一個(gè) EasyPrivacy 插件。源碼地址:https://github.com/pengxurui/EasyPrivacy

3.1 添加依賴

  • 1草戈、依賴 EasyPrivacy 插件

在項(xiàng)目級 build.gradle 中聲明遠(yuǎn)程倉庫题造,并依賴 EasyPrivacy 插件:

項(xiàng)目級 build.gradle

buildscript {
    repositories {
        ...
        google()
        mavenCentral()
        // JitPack 倉庫
        maven { url "https://jitpack.io" }
    }
    dependencies {
        ...
        classpath 'com.github.pengxurui:EasyPrivacy:v1.0.2
    }
}
  • 2、應(yīng)用 EasyPrivacy 插件

在應(yīng)用級或者模塊級 build.gradle 中應(yīng)用 EasyPrivacy 插件:

build.gradle

apply plugin: 'com.pengxr.easyprivacy'
...

執(zhí)行 Sync Gradle 之后猾瘸,可以在 Gradle 面板中看到新增的檢測任務(wù),具體位于 privacy 任務(wù)組:

3.2 執(zhí)行 support 64-bit abi

執(zhí)行 support 64-bit abi 任務(wù)丢习,將檢索該模塊的 Gradle 依賴樹中的 so 文件牵触,從中篩選出其中沒有完成 64 位適配的 so 文件。例如咐低, 項(xiàng)目中存在 armeabiv-v7a 類型的 libc++_shared.so 文件揽思,但沒有提供對應(yīng)的 64 位arm64-v8a 類型,就會(huì)在分組so in armeabiv-v7a, but not in arm64-v8a:中增加提示见擦。

3.3 分析日志

以下是在 sample 模塊的日志輸出:

...
> Configure project :sample
...
> Task :sampleLib:copyReleaseJniLibsProjectOnly UP-TO-DATE
> Task :sample:mergeReleaseNativeLibs UP-TO-DATE
> Task :sample:support 64-bit abi
EasyPrivacy => Support 64-bit abi start.
EasyPrivacy => so: /Users/pengxurui/.gradle/caches/transforms-2/files-2.1/297c6c751393f4fc48ae19ba461e118a/openDefault-4.2.7/jni/armeabi-v7a/libweibosdkcore.so
EasyPrivacy => so: /Users/pengxurui/.gradle/caches/transforms-2/files-2.1/297c6c751393f4fc48ae19ba461e118a/openDefault-4.2.7/jni/x86/libweibosdkcore.so
EasyPrivacy => so: /Users/pengxurui/.gradle/caches/transforms-2/files-2.1/297c6c751393f4fc48ae19ba461e118a/openDefault-4.2.7/jni/armeabi/libweibosdkcore.so
EasyPrivacy => so: /Users/pengxurui/workspace/public/EasyPrivacy/sample/build/intermediates/merged_jni_libs/release/out/armeabi-v7a/libbsdiff.so
EasyPrivacy => so: /Users/pengxurui/workspace/public/EasyPrivacy/sample/build/intermediates/merged_jni_libs/release/out/x86/libbsdiff.so
EasyPrivacy => so: /Users/pengxurui/workspace/public/EasyPrivacy/sample/build/intermediates/merged_jni_libs/release/out/armeabi/libbsdiff.so
EasyPrivacy => so: /Users/pengxurui/workspace/public/EasyPrivacy/sampleLib/build/intermediates/library_jni/release/jni/armeabi-v7a/libgetuiext3.so
EasyPrivacy => so: /Users/pengxurui/workspace/public/EasyPrivacy/sampleLib/build/intermediates/library_jni/release/jni/armeabi-v7a/libc++_shared.so
EasyPrivacy => so: /Users/pengxurui/workspace/public/EasyPrivacy/sampleLib/build/intermediates/library_jni/release/jni/arm64-v8a/libgetuiext3.so

EasyPrivacy => armeabi size: 2
EasyPrivacy => armeabiv-v7a size: 4
EasyPrivacy => arm64-v8a size: 1
EasyPrivacy => x86 size: 2
EasyPrivacy => x86_64 size: 0
EasyPrivacy => mips size: 0
EasyPrivacy => mips_64 size: 0

so in armeabi, but not in arm64-v8a:
[openDefault-4.2.7:libweibosdkcore.so]  [:libbsdiff.so] 

so in armeabiv-v7a, but not in arm64-v8a:
[openDefault-4.2.7:libweibosdkcore.so]  [:libbsdiff.so]  [:libc++_shared.so]    

so in x86, but not in x86-64:
[openDefault-4.2.7:libweibosdkcore.so]  [:libbsdiff.so] 

so in mips, but not in mips-64:

從以上日志可以看出钉汗,[openDefault-4.2.7:libweibosdkcore.so][:libbsdiff.so]鲤屡、[:libc++_shared.so] 這三個(gè) so 文件沒有提供 arm64-v8a 類型损痰,這部分就是你需要做適配的內(nèi)容。

其中 openDefault-4.2.7 是 so 文件所處的 aar 的 pom 信息酒来,你可以根據(jù)這個(gè)信息來判斷需要適配的 SDK卢未。另外,像 :libbsdiff.so 這種則屬于直接集成在工程中的 so 文件堰汉。


4. 構(gòu)建 64 位 APK

完成適配工作后辽社,現(xiàn)在需要構(gòu)建出 64 位的 APK。根據(jù)應(yīng)用市場的要求翘鸭,你需要構(gòu)建出三種包:

  • 1滴铅、32 位包
  • 2、64 位包
  • 3就乓、32 / 64 位包(同時(shí)包含 32 位 和 64 位兩種 so 文件)

4.1 ndk.abiFilters 配置

通過 ndk. abiFilters 配置可以過濾出需要打包到 APK 中的 so 文件汉匙,例如以下配置將會(huì)把 armeabi-v7aarm64-v8a 兩種 ABI 類型的 so 文件打包到 APK 中:

應(yīng)用級 build.gradle

android {
    ...
    defaultConfig {
        ...
        ndk {
            abiFilters "armeabi-v7a","arm64-v8a"
        }
    }
}

4.2 splits 配置

ndk.abiFilters 配置可以將所有支持的 ABI 的 so 文件都打包進(jìn) APK拱烁,缺點(diǎn)是包體積增大。其實(shí)盹兢,應(yīng)用市場是支持單獨(dú)分發(fā) 32 位和 64 位 APK 包的能力的邻梆,我們可以使用 splits 配置。例如以下配置會(huì)將每種 ABI 類型單獨(dú)打包绎秒。universalApk 為 ture 時(shí)還會(huì)額外構(gòu)建一個(gè)包含所有 ABI 類型的 APK浦妄。

android {
    ...
    defaultConfig {
        ...
        splits {
            abi {
                enable true
                reset()
                include 'armeabi-v7a', 'arm64-v8a'
                universalApk false
            }
        }
    }
}

5. 總結(jié)

EasyPrivacy 框架的源碼我已經(jīng)放在 Github 上了,源碼地址:https://github.com/pengxurui/EasyPrivacy见芹。我也寫了一個(gè)簡單的 Sample Demo剂娄,你可以直接運(yùn)行體驗(yàn)下。歡迎批評玄呛,歡迎 Issue~

最近幾個(gè)月阅懦,你是否經(jīng)常會(huì)收到應(yīng)用市場的隱私整改郵件呢?是的徘铝,在中國用戶隱私意識(shí)得到強(qiáng)化的同時(shí)耳胎,針對 App 的隱私規(guī)范整改也在一步步收緊,海外(Google Play/App Store)走過的老路惕它,最終我們也得走一遍呀怕午!

我們會(huì)發(fā)現(xiàn)隱私整改是每個(gè) App 都無法規(guī)避的問題,具備共性淹魄。我想做一個(gè)專門針對隱私整改的 Gradle 插件 EasyPrivacy郁惜,幫助開發(fā)者快速發(fā)現(xiàn)工程中隱私問題。市面上目前有類似的工具嗎甲锡,可以分享給我兆蕉。或者你可以說說那些最讓你頭疼的整改問題(給我提 Featureg吐佟)


參考資料

創(chuàng)作不易虎韵,你的「三連」是丑丑最大的動(dòng)力,我們下次見缸废!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末劝术,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子呆奕,更是在濱河造成了極大的恐慌养晋,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梁钾,死亡現(xiàn)場離奇詭異绳泉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)姆泻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門零酪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冒嫡,“玉大人,你說我怎么就攤上這事四苇⌒⒘瑁” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵月腋,是天一觀的道長蟀架。 經(jīng)常有香客問我,道長榆骚,這世上最難降的妖魔是什么片拍? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮妓肢,結(jié)果婚禮上捌省,老公的妹妹穿的比我還像新娘。我一直安慰自己碉钠,他們只是感情好纲缓,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著喊废,像睡著了一般色徘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上操禀,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機(jī)與錄音横腿,去河邊找鬼颓屑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛耿焊,可吹牛的內(nèi)容都是我干的揪惦。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼罗侯,長吁一口氣:“原來是場噩夢啊……” “哼器腋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起钩杰,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤纫塌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后讲弄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體措左,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年避除,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了怎披。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胸嘁。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖凉逛,靈堂內(nèi)的尸體忽然破棺而出性宏,到底是詐尸還是另有隱情,我是刑警寧澤状飞,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布毫胜,位于F島的核電站,受9級特大地震影響昔瞧,放射性物質(zhì)發(fā)生泄漏指蚁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一自晰、第九天 我趴在偏房一處隱蔽的房頂上張望凝化。 院中可真熱鬧,春花似錦酬荞、人聲如沸搓劫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枪向。三九已至,卻和暖如春咧党,著一層夾襖步出監(jiān)牢的瞬間秘蛔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工傍衡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留深员,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓蛙埂,卻偏偏與公主長得像倦畅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子绣的,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

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