支援 64 位元架構

Stay organized with collections Save and categorize content based on your preferences.

2019 年 8 月 1 日起,在 Google Play 上發布的應用程式必須支援 64 位元架構。64 位元 CPU 可以為使用者提供更快速、更豐富的體驗。為應用程式新增 64 位元版本,不僅能提升效能、有助於日後創新,還能為使用僅限 64 位元硬體的裝置提前做好準備。

本指南說明目前您可採取的步驟,以確保 32 位元應用程式可支援 64 位元的裝置。

評估應用程式

如果應用程式只使用以 Java 程式設計語言或 Kotlin 編寫的程式碼 (包括所有程式庫或 SDK),則應用程式已可支援 64 位元裝置。如果應用程式使用了任何原生程式碼,或您不確定是否已使用,您就必須對應用程式進行評估並採取行動。

快速檢查狀態

如要快速確認應用程式是否符合 64 位元版本要求,請前往 Play 管理中心查看現有版本,確認是否符合規定:

如果草稿版本有與 64 位元版本要求相關的任何問題,Play 管理中心也會顯示警告,範例如下:

如果看到快訊,請按照下列步驟為應用程式做好準備。

應用程式是否使用原生程式碼?

首先,請檢查應用程式是否使用了任何原生程式碼。 如果符合下列條件,即表示應用程式使用原生程式碼:

  • 在應用程式中使用任何 C/C++ (原生) 程式碼。
  • 連結到任何第三方原生資料庫。
  • 由使用原生資料庫的第三方應用程式建構工具所建構。

應用程式中是否有 64 位元程式庫?

如要檢查是否有 64 位元程式庫,最簡單的方式就是檢查 APK 檔案的結構。建構完成後,APK 會連同應用程式所需的所有原生資料庫一併封裝。原生資料庫則會根據 ABI 儲存在多個資料夾中。系統不必支援每一個 64 位元架構,但每個支援的原生 32 位元架構都必須納入對應的 64 位元架構。

如果是 ARM 架構,32 位元程式庫位於 armeabi-v7a。 相應的 64 位元程式庫則位於 arm64-v8a

如果是 x86 架構,請為 32 位元尋找 x86,64 位元則尋找 x86_64

首先,請確認這兩個資料夾中都有原生資料庫。重點回顧:

平台 32 位元程式庫資料夾 64 位元程式庫資料夾
ARM lib/armeabi-v7a lib/arm64-v8a
x86 lib/x86 lib/x86_64

請注意,每個資料夾中的程式庫組合可能完全相同,也可能不完全相同,這取決於應用程式的實際情況。您應達成的目標是確保應用程式在僅限 64 位元的環境中能正確執行。

在一般情況下,同時針對 32 位元和 64 位元架構建構的 APK 或軟體包會有這兩種 ABI 的資料夾,每個資料夾中都有一組對應的原生資料庫。如果系統不支援 64 位元版本,您可能會看到 32 位元的 ABI 資料夾,而非 64 位元資料夾。

使用 APK 分析工具尋找原生資料庫

APK 分析工具是一項可讓您評估所建立 APK 各項層面的工具。在以下情境中,我們將使用這項工具來尋找原生資料庫,並確定當中有 64 位元程式庫。

  1. 開啟「Android Studio」,然後開啟任何專案
  2. 從選單中選取「Build」>「Analyze APK…」

    啟動 APK 分析工具

  3. 選擇要評估的 APK。

  4. 查看「lib」資料夾,您可以在其中找到任何的「.so」檔案。如果在應用程式中找不到任何「.so」檔案,代表應用程式已準備就緒,不需要採取進一步行動。如果看到 armeabi-v7ax86,就表示有 32 位元程式庫。

  5. 查看「arm64-v8a」或「x86_64」資料夾中是否有類似的「.so」檔案。

    啟動 APK 分析工具

  6. 如果沒有看到任何 arm64-v8ax86_64 程式庫,請更新建構程序,以便開始在 APK 中建構並封裝這些構件。

  7. 如果兩個程式庫都已封裝完畢,就可以略過這個步驟並直接在 64 位元硬體上測試應用程式

透過將 APK 解壓縮來尋找原生資料庫

APK 檔案結構與 ZIP 檔案類似,而且也可以解壓縮。如果偏好使用指令列或其他任何解壓縮工具,則可以選擇將 APK 解壓縮這個方式。

您只需將 APK 檔案解壓縮 (取決於解壓縮工具,您可能必須將檔案重新命名為 .zip),然後按照上述指南查看已解壓縮的檔案,即可確認應用程式是否已為支援 64 位元裝置做好準備。

例如,您可以透過指令列執行下列指令:

:: Command Line
> 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

在這個範例中,您可以發現有 armeabi-v7aarm64-v8a 程式庫,這表示應用程式支援 64 位元架構。

透過 64 位元程式庫建構應用程式

以下操作說明適用於建構 64 位元程式庫。不過請注意,以下說明內容僅涵蓋您可以透過原始碼建構的程式碼和程式庫。

如果使用任何外部 SDK 或程式庫,請按照上述步驟操作,確保使用的是 64 位元版本。如果無法取得 64 位元版本,請與 SDK 或程式庫擁有者聯絡,並在規劃支援 64 位元裝置時將這一點納入考量。

使用 Android Studio 或 Gradle 進行建構

大部分的 Android Studio 專案都使用 Gradle 做為基礎建構系統,因此本節適用於使用這兩種工具進行建構的情況。依據您想支援的架構而定,為原生程式碼啟用版本和在應用程式「build.gradle」檔案的 ndk.abiFilters 設定中加入 arm64-v8a 和/或 x86_64 一樣簡單:

Groovy

// Your app's build.gradle
plugins {
  id 'com.android.app'
}

android {
   compileSdkVersion 27
   defaultConfig {
       appId "com.google.example.64bit"
       minSdkVersion 15
       targetSdkVersion 28
       versionCode 1
       versionName "1.0"
       ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
// ...

Kotlin

// Your app's build.gradle
plugins {
    id("com.android.app")
}

android {
    compileSdkVersion(27)
    defaultConfig {
        appId = "com.google.example.64bit"
        minSdkVersion(15)
        targetSdkVersion(28)
        versionCode = 1
        versionName = "1.0"
        ndk {
            abiFilters += listOf("armeabi-v7a","arm64-v8a","x86","x86_64")
        }
// ...

使用 CMake 進行建構

如果應用程式是透過 CMake 建構,您可以將 arm64-v8a 傳遞到「-DANDROID_ABI」參數,以便針對 64 位元 ABI 進行建構:

:: Command Line
> cmake -DANDROID_ABI=arm64-v8a … or
> cmake -DANDROID_ABI=x86_64 …

如果您使用 externalNativeBuild,這個方法不會起任何作用。詳情請參閱「使用 Gradle 進行建構」一節。

使用 ndk-build 進行建構

如果應用程式是以 ndk-build 建構,您可以透過使用 APP_ABI 變數修改 Application.mk 檔案來為 64 位元 ABI 建構:

APP_ABI := armeabi-v7a arm64-v8a x86 x86_64

如果您使用 externalNativeBuild,這個方法不會起任何作用。詳情請參閱「使用 Gradle 進行建構」一節。

將 32 位元程式碼移植至 64 位元

如果程式碼已經可以在電腦或 iOS 上執行,則不須為 Android 額外進行任何設定。如果這是第一次為 64 位元系統建構程式碼,您必須解決的主要問題是指標無法再納入如 int 這類 32 位元整數。您必須更新可將指標儲存至 intunsigneduint32_t 等類型指標的程式碼。在 Unix 系統上,long 與指標大小相符,然而在 Windows 上並不是如此,因此您必須改用 uintptr_tintptr_t 這類意圖顯而易見的程式碼。使用 ptrdiff_t 類型來儲存兩個指標間的差異。

請一律優先採用 <stdint.h> 中定義的特定固定寬度整數類型,而非 intlong 等傳統類型,即便是對於非指標類型也是如此。

請使用以下編譯器旗標,找出程式碼在指標和整數之間轉換錯誤的情況:

-Werror=pointer-to-int-cast
-Werror=int-to-pointer-cast
-Werror=shorten-64-to-32

含有 int 欄位 (其中有 C/C++ 物件指標) 的 Java 類別有同樣的問題。在 JNI 原始碼中搜尋 jint,並確定已切換至 long (Java 端) 和 jlong (C++ 端)。

對於 64 位元程式碼,隱式函式宣告更加危險。C/C++ 假設隱式宣告的函式傳回類型 (也就是編譯器未偵測到宣告的函式) 為 int。如果函式的實際傳回類型是指標,這對於在 32 位元系統上運作並沒有問題,在這類系統上,您的指標可在 int 使用。然而,對 64 位元系統來說,這個編譯器執行到一半就無法正常運作。例如:

// This function returns a pointer:
// extern char* foo();

// If you don't include a header that declares it,
// when the compiler sees this:
char* result = foo();

// Instead of compiling that to:
result = foo();

// It compiles to something equivalent to:
result = foo() & 0xffffffff;

// Which will then cause a SIGSEGV if you try to dereference `result`.

以下編譯器旗標會將隱式函式宣告的警告轉變為錯誤,讓您可以更容易找到和修正這個問題:

-Werror=implicit-function-declaration

如果您有內嵌組譯器,就必須將其重新編寫或使用一般 C/C++ 實作。

如果擁有硬式編碼的類型大小 (例如 8 或 16 個位元組),請將其替換為對等的 sizeof(T) 運算式 (例如 sizeof(void*))。

如需有條件地為 32 位元編譯不同於 64 位元的程式碼,可以使用 #if defined(__LP64__) 來處理一般 32/64 間的差異;針對 Android 支援的特定架構,則可以使用 __arm____aarch64__ (arm64)、__i386__ (x86) 和 __x86_64__

由於傳統格式指定碼不允許使用對 32 位元和 64 位元裝置都正確的方式來指定 64 位元類型,您必須為 printfscanf 這類函式調整格式字串。使用 <inttypes.h> 中的 PRISCN 巨集就能解決這個問題,PRIxPTRSCNxPTR 用於寫入/讀取十六進位指標,而 PRId64SCNd64 則可透過移植的方式寫入/讀取 64 位元值。

轉移時,您可能需要使用 1ULL 取得要轉移的 64 位元常數,而不能使用僅 32 位元的 1

透過 Android App Bundle 減少大小增加量

為應用程式新增 64 位元架構這項支援後,可能會導致 APK 大小增加。我們強烈建議您善用 Android App Bundle 功能,這樣當您在同一個 APK 中納入 32 位元與 64 位元的原生程式碼時,才能將對大小造成的影響減至最低。

將應用程式改為使用 Android App Bundle 有助於「縮減」APK 大小,進而縮減目前應用程式的大小。

遊戲開發人員

我們瞭解遷移第三方遊戲引擎是一個耗費人力的過程,而且需要很長的前置時間。幸好,三大最常使用的引擎目前都支援 64 位元:

  • Unreal (自 2015 年開始支援)
  • Cocos2d (自 2015 年開始支援)
  • Unity (自 2018 年開始支援)

Unity 開發人員

升級至支援的版本

Unity 自版本 2018.22017.4.16 開始提供 64 位元支援。

如果發現所使用的 Unity 版本不支援 64 位元,請決定要升級的版本,並按照 Unity 提供的指南來遷移環境,確保應用程式升級至可建構 64 位元程式庫的版本。Unity 建議升級至最新 LTS 版本的編輯器,以便取得最新功能和更新。

以下圖表概述各種 Unity 版本和建議做法:

Unity 版本 版本是否支援 64 位元? 建議做法

2020.x

✔️

確保建構設定能夠輸出 64 位元程式庫。

2019.x

✔️

確保建構設定能夠輸出 64 位元程式庫。

2018.4 (LTS)

✔️

確保建構設定能夠輸出 64 位元程式庫。

2018.3

✔️

確保建構設定能夠輸出 64 位元程式庫。

2018.2

✔️

確保建構設定能夠輸出 64 位元程式庫。

2018.1

提供 64 位元實驗性支援。

2017.4 (LTS)

✔️

2017.4.16 起開始支援。 確保建構設定能夠輸出 64 位元程式庫。

2017.3

✖️

升級至支援 64 位元的版本。

2017.2

✖️

升級至支援 64 位元的版本。

2017.1

✖️

升級至支援 64 位元的版本。

<=5.6

✖️

升級至支援 64 位元的版本。

變更建構設定以便輸出 64 位元程式庫

如果使用的是支援 64 位元 Android 資料庫的 Unity 版本,您可以調整版本設定來產生 64 位元的應用程式版本。您也必須使用 IL2CPP 後端做為指令碼後端 (詳情請參閱這裡的說明)。如要設定 Unity 專案來建構 64 位元架構,請按照下列指示操作:

  1. 前往「Build Settings」,確認 Unity 標誌是否顯示在「Platform」下方的「Android」旁,藉此確定您是針對 Android 進行建構。
    1. 如果 Unity 標誌並未顯示在 Android 平台旁,請選取「Android」,然後按一下「Switch Platform」
  2. 按一下「Player Settings」

    Unity 中的「Player Settings」

  3. 依序前往「Player Settings Panel」>「Settings for Android」>「Other settings」>「Configuration」

  4. 將「Scripting Backend」設為「IL2CPP」

  5. 勾選「Target Architecture」>「ARM64」核取方塊。

    在 Unity 中設定目標架構

  6. 照常建構!

請注意,如要針對 ARM64 進行建構,您必須為該平台量身打造所有資產。請按照 Unity 的指南來減少 APK 大小,並考慮善用 Android App Bundle 功能來減少大小增加量。

多個 APK 和 64 位元版本遵循

請注意,如果您目前使用 Google Play 支援多個 APK 的機制發布應用程式,系統會根據發布層級來評估 64 位元版本規定的遵循情形。不過,64 位元版本規定不適用於未在 Android 9 Pie 以上版本裝置發行的 APK 或應用程式套件。

如果其中一個 APK 標示為不符合版本要求,但版本已過舊,無法修正為符合要求,其中一種策略是在 APK 資訊清單的 uses-sdk 元素中新增 maxSdkVersion="27" 屬性。如此一來,這個 APK 將無法發布至搭載 Android 9 Pie 以上版本的裝置,也不會再干擾遵循版本要求。

RenderScript 和 64 位元版本遵循

如果應用程式使用 RenderScript,並且以舊版 Android 工具建構,則該應用程式可能會遇到 64 位元版本遵循問題。如果使用版本低於 21.0.0 的建構工具,編譯器可能會將產生的中間碼放到外部 .bc 檔案中。64 位元架構不再支援這些舊版 .bc 檔案,因此,如果 APK 中出現這些檔案,就會造成版本遵循的問題。

如要修正問題,請移除專案中的所有 .bc 檔案,將環境升級至 build-tools-21.0.0 以上版本,然後將 Android Studio 中的 renderscriptTargetApi 設為 21+,藉此指示編譯器不要產生 .bc 檔案。接著,重新建構應用程式並檢查是否有 .bc 檔案,然後將其上傳至 Play 管理中心。

在 64 位元硬體上測試應用程式

應用程式的 64 位元版本應與 32 位元版本擁有相同的品質,並提供同樣的功能組合。針對應用程式進行測試,確保最新版 64 位元裝置的使用者在使用應用程式時可享有良好體驗。

如要開始測試應用程式,您必須擁有支援 64 位元的裝置。市面上有許多支援 64 位元架構的熱門裝置,例如 Google 的 Pixel 和其他旗艦裝置。

測試 APK 最簡單的方法是使用 ADB 安裝應用程式。在多數情況下,您可以提供 --abi 做為參數,指出要將哪些程式庫安裝到裝置上。這樣在裝置上安裝應用程式時便只會包含 64 位元的程式庫。

:: Command Line
# A successful install:
> adb install --abi armeabi-v7a YOUR_APK_FILE.apk
Success

# If your APK does not have the 64-bit libraries:
> 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]

# If your device does not support 64-bit, an emulator, for example:
> adb install --abi arm64-v8a YOUR_APK_FILE.apk
ABI arm64-v8a not supported on this device

安裝成功後,請依照平常的方法測試應用程式,確保其品質與 32 位元版本相同。

發布

當您準備好發布應用程式時,請照常發布。一如往常,請繼續按照這些最佳做法部署應用程式。建議您利用封閉測試群組,僅向少數使用者推出應用程式,以確保應用程式的品質一致。

在推出重大更新時,請務必先在支援 64 位元架構的裝置上進行全面測試,再將應用程式發布給更多目標對象。