這一次谷歌很強硬,App 再不支持,兩個月後將拒絕上架!

一. 序

事情是這樣的,前幾天收到 Google Play 的通知郵件,這纔想起來有幾款在 Google Play 上架的 App,尚未支持 64 位 CPU 架構。android

早在今年一月份,Google 就發佈通知,在今年 8 月 1 日開始,上架的 App,除了提供 32 位的版本以外,還須要提供 64 位的版本。架構

這眼看着離強制升級窗口,只剩下最後兩個月的時間,不少第三放來源的 so 支持庫,若是沒有提供 64 位的版本,還須要同步催促合做方更新。app

那今天就來聊聊 Android APK 升級 64 位 CUP 架構的細節,看看你的應用是否須要支持 64 位 CPU 架構,若是要支持,須要作什麼?ide

二. Android CPU 架構細節

2.1 這是強制規範

早在 2015 年 Google 發佈 Android 5.0 版本時,就加入了 64 位處理器的支持,當時就提出了以 19 年 8 月爲最後的更新支持期限,並在今年又重申了這個強制要求。性能

只要你的 App 存在國際版,須要上架 Google Play,這個規定都必須準守。測試

2.2 那些 APK 須要支持 64 位?

那假如你有一個國際化的 App 須要維護,在今年 8 月 1 日以後,更新 Google Play 時,就必須提供 64 位的版本。優化

那這裏說的 64 位版本支持,究竟是什麼?ui

若是你的應用,徹底是使用 Java 或者 Kotlin 編寫代碼,不包含任何原生(Native)的支持,那麼就表示這個應用已經支持 64 位。this

可是應用內使用了任何原生(Native)的支持(so 庫),就須要針對這些 so 文件,針對不一樣的 CPU 架構提供不一樣的版本的 so 支持。spa

須要注意的是,有些時候,在咱們自身的代碼中,確實沒有用到原生的支持,可是在 App 中使用的一些第三方庫中卻包含了。

此時最穩妥的方式,就是針對最終打包生成的 APK 文件進行分析,來判斷是否須要提供 64 位架構的支持。

那 CPU 架構是什麼?什麼又是 ABIs?

在 Android 中,雖然 ARM 的 CPU 架構是主流,可是目前至少支持幾類 CPU 架構,ARM 下的 ARMv5/ARMv7/ARMv8,x86 下的 x86/x86_64,以及很不常見的 MIPS 類架構。這裏的每一種 CPU 類型對應了一種 API(Application Binary Interface),例如 armeabi-v7a 中的 "armeabi"  指的就是 ARM 這種類型的 ABI,後面的 「v7a」 指的是 ARMv7。

一般咱們能夠簡單的理解:

這三個概念是相通的,一般在技術討論中,說的是一個東西。

2.3 爲何是強制的?

谷歌之因此會有強制更新的要求,很大一方面緣由是由於做爲開發者,更新補全 ABIs 的動力並不足。

主要緣由來自如下幾個方面:

1. APK 體積增大

針對不一樣 CPU 架構提供對應的 so 庫,固然是效率最高的作法。可是這種作法,最直接的影響,就是 APK 文件的增大,有些時候補全這些 so 支持,會致使整個 APK 體積有幾 MB 到幾十 MB 的增幅。

APK 體積優化,不少公司都將其算作是一個 API 指標,加入一個新特性,致使 APK 體積的增大,在不少時候都是不容許的,爲此換技術方案都是常有的事。

從增加的角度來看,越小的 APK,用戶下載的意願就更大,轉化率就越高。

可是隨着如今流量愈來愈便宜,近期 iOS 已經將 蜂窩數據下載限制從 150MB 放寬至 200MB,針對安裝包的體積優化標準,也能夠適當的放寬了。

2. 自己有必定的兼容性

應用市場中,不少 APP 其實都只有 armeabi 或者 armeabi-v7a 的支持,而市面上的設備,支持的並非只有這兩種 CPU 架構。

可是這並無影響在這些設備上運行這些 App,這就是 CPU 架構的兼容性。

不一樣架構,並不意味着之間必定是不兼容的,在不一樣版本下,其實提供了兩種 ABI 支持,分別是

  • 主要 ABI:與系統自己使用的原生代碼同樣,最優方案。
  • 輔助 ABI:支持的另外一個 ABI 方案,兼容方案。

這種兼容策略就不在這裏展開說了,最簡單的就是 64 位的 arm64-v8a 在支持自己的 CPU 架構以外,還兼容支持 armeabi-v7a、armeabi;x86_64 同時也兼容支持 X86 和 armeabi。

你看,雖然添加 64 位的支持,能夠有效的使用硬件的優點,提高性能,但大部分時候,採用兼容方案,是一種更簡單的方式。

3. 沒有對應架構的 so 文件

這個緣由就比較尷尬了,咱們 App 中使用到的原生代碼,其實有兩種。

一種是咱們本身編寫的,源碼在手,想提供對應的支持,修改配置從新編譯一下就解決了。

另外一種來自第三方提供的,這種時候咱們沒有源碼,沒法作到從新編譯,只能和第三方溝通,看能不能提供一個對應 CPU 架構的 so 庫。這種狀況就很是的不可控了。

例如比較常見的一個 WebView 的替換方案,騰訊 X5 內核,自己就不提供 X86 的庫。

官方給的建議是使用 armeabi 或者 armeabi-v7a。

在前文有提到,ABIs 自己是有一些兼容規則的,可是這種兼容規則,是有條件的。

舉個例子:64 位的 arm64-v8a 是能夠向下兼容的,可是這有個前提,那就是若是你的項目中,有 armeabi-v7a 和 arm64-v8a 兩個目錄,就須要保證這兩個目錄下支持的 so 庫文件保持一致。

在左邊的狀況下,若是 arm64-v8a 的手機用到 b.so 時,就會去 arm64-v8a 目錄下找,固然是找不到 b.so 文件的,就會直接拋異常,而不會再去 armeabi-v7a 目錄下繼續尋找。

若是須要提供多套 ABIs 的支持,就須要保證全部 ABI 目錄下,對應的 so 文件保持一致。

而在一些特殊的狀況下,咱們沒法提供對應平臺的 so 庫,例如騰訊 X5 內核這種狀況,就須要作個取捨了。

在沒有 Google Play 的強制策略下,同時又由於各方考慮,大多數時候咱們可能會捨棄其餘 ABIs 的支持。可是如今既然強制執行了,騰訊 X5 內核就可能升級以提供 64 位的 so 庫,畢竟一邊是沒法上架,另一遍是一個 WebView 的內核,誰都知道怎麼取捨。

3、支持 64 位架構

3.1 是否包含 64 位庫?

介紹了 Android 下 CPU 架構的一些細節,接下來就要開始正題了,如何升級並支持 64 位架構。

從前文中應該瞭解到,支持對應的 ABIs,反映在項目中,就是存在對應 ABIs 架構的目錄,而且目錄中有完備的 so 庫支持。

Google 並不要求咱們支持全部的 64 位架構,可是對於已經支持的每種原生 32 位架構,就必須包含對應的 64 位架構。

例如:

  • 對於 ARM 架構,有 armeabi-v7a(32位) 就必須 arm64-v8a(64位)。
  • 對於 x86 架構,有 x86(32位) 就必須有 x86_64(64位)

這就要求咱們有對應的目錄,而且目錄中包含對應的 so 文件。APK 中提供了完備的 ABIs 支持,運行的以後,會選取對應的最優支持進行加載和使用。

須要注意的是,有時候咱們將 32 位的 so 複製到 64 位中,運行不會出現異常,可是這依然存在隱患。最好的辦法是根據不一樣的架構,編譯對應的 so 文件,原則上,咱們的目標是確保應用能夠在僅支持 64  位架構的環境中正常運行。

3.2 判斷是否支持 64 位架構

前面也提到,咱們的項目中,可能會引入一些第三方庫,致使在不明確的狀況下,引入了一些預期以外的 ABIs 庫。

一般咱們的作法是在 Gradle 中增長 abiFilters 過濾,來確保不會在打包輸出的 APK 中存在預期以外的 ABIs 目錄和 so 庫。

ndk {
    //設置支持的SO庫架構
    abiFilters 'armeabi-v7a' 
}

那麼咱們拿最終打包輸出的 APK 文件去分析,是最穩妥的辦法。

分析的方法有兩種:

1. AS 的 APK 分析器

在 Android Studio 中,從菜單依次選擇  Build → Analyze APK…

選擇須要分析的 APK 文件,查看其 lib 目錄,是否存在預期的 ABIs 目錄以及完備的 so 文件。

2. 使用 zipinfo 命令進行分析

獲得待分析的 APK 文件,就能夠經過 zipinfo + grep 命令,輸出其內包含的 so 文件。

> zipinfo -1 YOUR_APK_FILE.apk | grep \.so$
    lib/armeabi-v7a/libmain.so
    lib/armeabi-v7a/libmono.so
    lib/armeabi-v7a/libunity.so
    lib/arm64-v8a/libmain.so
    lib/arm64-v8a/libmono.so
    lib/arm64-v8a/libunity.so

依然是去看對應目錄和 so 文件是否完備。

3.3 在 64 位設備上測試應用

支持 64 位架構是爲了讓咱們利用 CPU 的特性,以提高性能,可是穩定依然是咱們首先要保證的,因此在升級以後,就須要進行測試。

要測試 App,最簡單的方式是使用 adb 命令安裝該應用,能夠配合 --abi 參數,用以指示要將那些 so 庫,安裝到設備上,這樣咱們在這個設備上安裝的 App,就會僅包含咱們制定的庫。

# 成功安裝 APK :
> adb install --abi armeabi-v7a YOUR_APK_FILE.apk
Success

# 若是 APK 中不包含 64 位 so 文件:
> adb install --abi arm64-v8a YOUR_APK_FILE.apk
adb: failed to install YOUR_APK_FILE.apk: Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]

# 若是你的設備(手機)不支持 64 位架構
> adb install --abi arm64-v8a YOUR_APK_FILE.apk
ABI arm64-v8a not supported on this device

去年上市的手機,大部分都是 64 位架構的,找一款來測試便可。

3.4 分包處理

若是咱們的應用只須要在國內分發,當前的策略對咱們並不影響,保持原樣就行了。可是若是存在國際版,須要上架 Google Play 就必定要重視這次升級。

在 Google Play 上傳 APK,是能夠根據 CPU 架構上傳不一樣的 APK 的,也就是咱們能夠針對 32 位上傳一個 APK,再上傳一個 64 位的 APK。

此時就須要用到 Gradle 的打包技巧了,分別輸出幾個僅包含對應平臺的 APK,以此完成 Google Play 的要求,分別上傳 32 位的支持 APK 和 64 位的支持 APK,這樣可以 APK 文件不至於增大不少。

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
    project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]

    android.applicationVariants.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
        }
    }
 }

這裏利用 Gradle 的 splite 配置,有興趣能夠直接查閱文檔,就不展開講了。

四. 小結時刻

在本文中,咱們借這次 Google Play 的強制支持 64 位架構的事情,講解了 Android 下 so 庫的一些兼容問題。

若是你在 Google Play 上有應用須要更新,別忘了提早準備須要的 so 庫,大多數原生支持的第三方庫,在此以前其實都已經提供了對應的 64 位架構。咱們只須要在最終日期以前,仔細的進行增長 so 文件,以達到適配的效果。

更新完成以後,別忘了測試,本文就到這裏,你有什麼更新的看法,歡迎在留言區討論。

相關文章
相關標籤/搜索