64 ビット アーキテクチャのサポート

Google Play で公開するアプリは、64 ビット アーキテクチャをサポートする必要があります。64 ビット版のアプリを追加することで、パフォーマンスを向上させ、64 ビット ハードウェアのみで構成されたデバイスに対応できるようになります。

次の手順では、32 ビット版のアプリが 64 ビットデバイスをサポートしていることを確認します。

アプリを調べる

ライブラリや SDK もすべて含めて、Java プログラミング言語または Kotlin で記述されたコードだけを使用しているアプリは、64 ビットデバイスをサポートしています。アプリがネイティブ コードを使用している場合や、ネイティブ コードを使用しているかどうか不明な場合は、アプリを調べます。

クイック ステータス チェック

Google Play Console で既存のリリースが要件に準拠しているかどうかを確認します。

未公開のリリースでも、64 ビット要件に関する問題があれば Play Console に警告が表示されます。以下の画像は一例です。

アラートが表示された場合は次の手順を確認し、アプリを 64 ビットデバイスに対応させます。

アプリがネイティブ コードを使用しているか?

該当するのは次のようなアプリです。

  • アプリで C / C++(ネイティブ)コードを使用している。
  • サードパーティのネイティブ ライブラリとリンクしている。
  • ネイティブ ライブラリを使用するサードパーティ製アプリビルダーでビルドされている。

アプリに 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 ビットの両方のアーキテクチャ向けにビルドされた 1 つの APK またはバンドルには、両方の ABI 用フォルダがあり、それぞれに対応するネイティブ ライブラリ セットが含まれています。64 ビットに対応していない場合、32 ビット用の ABI フォルダだけがあり、64 ビット用のフォルダはないことがあります。

APK Analyzer を使用してネイティブ ライブラリを探す

APK Analyzer は、ビルドされた APK のさまざまな要素を評価するためのツールです。APK Analyzer を使用してネイティブ ライブラリを探し、64 ビット ライブラリが含まれていることを確認します。

  1. Android Studio を起動して、任意のプロジェクトを開きます
  2. メニューで、[Build] > [Analyze APK] を選択します。

    APK Analyzer を起動する

  3. 評価する APK を選択します。

  4. lib フォルダ内を調べます。「.so」ファイルがある場合はここにホストされています。ない場合、アプリは 64 ビットデバイスをサポートしているため、これ以上の対処は必要ありません。armeabi-v7a または x86 が見つかった場合は、32 ビット ライブラリが存在します。

  5. arm64-v8a フォルダまたは x86_64 フォルダに同様の「.so」ファイルがあるかどうかを確認します。

    APK Analyzer を起動する

  6. arm64-v8a ライブラリまたは x86_64 ライブラリがない場合は、ビルドプロセスを更新し、これらのアーティファクトをビルドして APK にパッケージ化します。

  7. 両方のライブラリがすでにパッケージ化されている場合は、64 ビット ハードウェアでアプリをテストするステップに進んでください。

APK を解凍してネイティブ ライブラリを探す

APK ファイルは ZIP ファイルに似た構造になっています。コマンドラインやその他の抽出ツールを使って 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-v7a ライブラリと arm64-v8a ライブラリが存在するため、アプリは 64 ビット アーキテクチャをサポートしていることがわかります。

64 ビット ライブラリでアプリをビルドする

次の手順では、64 ビット ライブラリをビルドする方法について説明します。ここでは、ソースからビルド可能なコードとライブラリを使用する場合についてのみ説明します。

外部の SDK またはライブラリを使用している場合は、上記の手順に沿って 64 ビット版を使用していることを確認してください。64 ビット版がない場合は、SDK またはライブラリの所有者に問い合わせてください。また、64 ビットデバイスのサポートを計画する際には、この点をご考慮ください。

Android Studio または Gradle でのビルド

Android Studio プロジェクトでは通常、基盤となるビルドシステムとして Gradle を使用するため、このセクションはどちらを使用する場合にも当てはまります。ネイティブ コードのビルドを可能にする方法は非常に簡単で、サポート対象のアーキテクチャに応じて arm64-v8a または x86_64 を、アプリの「build.gradle」ファイル内の ndk.abiFilters 設定に指定するだけです。

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 を使用してアプリをビルドする場合は、Application.mk ファイルを APP_ABI 変数を使用して編集することで 64 ビット ABI 用にビルドできます。

APP_ABI := armeabi-v7a arm64-v8a x86 x86_64

externalNativeBuild を使用している場合、このオプションは無効です。Gradle でのビルドについての説明をご覧ください。

32 ビットコードを 64 ビットに移植する

すでにパソコン上や iOS 上でコードを実行済みの場合、Android 向けに追加作業を行う必要はありません。64 ビットシステム用に初めてコードをビルドする場合、一番に対応しなければならないのは、int のような 32 ビット整数型にポインタが収まらなくなる問題です。

int 型、unsigned 型、uint32_t 型などにポインタを格納しているコードを更新します。Unix システムの場合は long とポインタのサイズが一致しますが、Windows の場合は一致しません。代わりに、意図を明確に記述できる uintptr_t 型や intptr_t 型を使用します。2 つのポインタの差を格納するには、ptrdiff_t 型を使用します。

ポインタ以外でも、intlong といった従来の型ではなく、<stdint.h> で定義する特定の固定幅の整数型を常に使用するようにしてください。

次のコンパイラ フラグを使用して、ポインタと整数との変換が正しく行われていないコードの場所を検出します。

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

同じ問題は、C / C++ オブジェクトへのポインタを保持する int フィールドが定義された Java クラスにも発生します。JNI ソース内で jint を検索して、必ず Java 側では long に切り替え、C++ 側では jlong に切り替えてください。

暗黙的な関数宣言は、64 ビットコードではより大きな危険を伴います。C / C++ は、暗黙的に宣言された関数(コンパイラが宣言を認識していない関数)の戻り値の型を int と想定します。関数の実際の戻り値の型がポインタだった場合、ポインタが int に収まる 32 ビットシステムでは正常に機能しますが、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*) など)に置き換えてください。

64 ビット用とは異なる 32 ビット用コードを条件付きでコンパイルする必要がある場合、一般的な 32 ビットと 64 ビット間の相違に対しては #if defined(__LP64__) を使用し、Android がサポートする個別のアーキテクチャに対しては __arm____aarch64__(arm64)、__i386__(x86)、__x86_64__ を使用することができます。

printfscanf のような関数の場合は、フォーマット文字列を調整します。従来のフォーマット指定子では、32 ビットと 64 ビットの両方のデバイスで正常に機能するような方法で 64 ビット型を指定することができないためです。この問題は、<inttypes.h> 内で PRI マクロや SCN マクロを使用することで解決できます。16 進ポインタの書き込みと読み取りには PRIxPTRSCNxPTR を使用し、移植する 64 ビット値の書き込みと読み取りには PRId64SCNd64 を使用します。

シフトする際は、1ULL を使用して、シフトする 64 ビット定数を取得することが必要になる場合があります。32 ビット専用の 1 は使用しないでください。

Android App Bundle を使用してサイズの増大を緩和する

64 ビット アーキテクチャのサポートをアプリに追加すると、APK のサイズが増大することがあります。32 ビットと 64 ビットの両方のネイティブ コードを同じ APK に含める場合、サイズへの影響を最小限に抑えるために、Android App Bundle 機能を利用することを強くおすすめします。

ゲーム デベロッパー

以下のよく使われている 3 つのエンジンは 64 ビットをサポートしています。

  • Unreal(2015 年から)
  • Cocos2d(2015 年から)
  • Unity(2018 年から)

Unity デベロッパー

サポート バージョンへのアップグレード

Unity はバージョン 2018.22017.4.16 で 64 ビットをサポートしています。

64 ビットをサポートしていないバージョンの Unity を使用している場合は、アップグレードするバージョンを決めて、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 バックエンドを使用します。64 ビット アーキテクチャをビルドするように Unity プロジェクトをセットアップする手順は次のとおりです。

  1. [Build Settings] に移動します。Unity のマークが [Platform] の [Android] の横に表示され、Android 向けのビルドであることを確認します。
    1. Unity のマークが Android プラットフォームの横に表示されていない場合は、[Android] を選択して [Switch Platform] をクリックします。
  2. [Player Settings] をクリックします。

    Unity のプレーヤー設定

  3. [Player Settings] パネル > [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 ビット要件に準拠しているかどうかはリリースレベルで評価されます。ただし、Android 9 Pie 以降を搭載しているデバイスには配信しない APK または App Bundle であれば、64 ビット要件は適用されません。

APK のいずれかが準拠していないとマークされていて、その APK が古いために準拠できない場合は、その APK のマニフェストの uses-sdk 要素に maxSdkVersion="27" 属性を追加することで、問題を回避できます。この APK は Android 9 Pie 以降を搭載するデバイスには配信されず、準拠に関する問題はありません。

RenderScript と 64 ビット要件への準拠

RenderScript を使用するアプリが、古いバージョンの Android ツールでビルドされている場合、64 ビット要件への準拠の問題が発生する可能性があります。21.0.0 より前のビルドツールの場合、コンパイラが外部 .bc ファイル内にビットコードを生成していることがあります。このような旧式の .bc ファイルは 64 ビット アーキテクチャではサポートされなくなったため、APK 内にそのファイルが存在することが原因で、準拠に関する問題が発生します。

この問題を解決するには、プロジェクト内の .bc ファイルをすべて削除して、環境を build-tools-21.0.0 以降にアップグレードし、Android Studio 内で renderscriptTargetApi を 21 以上に設定することで、コンパイラに .bc ファイルを生成しないように指示します。次に、アプリをビルドし直して、.bc ファイルがないかどうか検査し、Play Console にアップロードします。

64 ビット ハードウェアでアプリをテストする

64 ビット版のアプリは、32 ビット版と同じ品質と機能を提供する必要があります。アプリをテストして、ユーザーが最新の 64 ビットデバイスでアプリを快適に操作できることを確認します。

64 ビット専用デバイス

可能な限り、次のいずれかのオプションを使用して、厳格な 64 ビット専用環境でアプリをテストすることをおすすめします。

64 ビット専用のシステム イメージを持つ Google Pixel

アプリの開発とテストを容易にするために、一部の Google Pixel デバイスでは、厳格な 64 ビット専用環境を備えた特別なシステム イメージが、現在の Android プレビュー リリースの工場出荷時標準システム イメージとともに提供されています。

Android 14(ベータ版)

Android 14 の 64 ビット専用イメージを入手するには、ダウンロード ページの 64 ビット専用イメージのセクションをご覧ください。

工場出荷時のシステム イメージと同様に、Android Flash Tool を使用するか、手動でデバイスに書き込むことで、Android 14 の 64 ビット専用イメージをデバイスに書き込めます。

Android 13(QPR3 ベータ版 3.2)

Android 13 QPR3 の 64 ビット専用イメージを入手するには、ダウンロード ページの 64 ビット専用イメージのセクションをご覧ください。

工場出荷時のシステム イメージと同様に、Android Flash Tool を使用するか、手動でデバイスに書き込むことで Android 13 の 64 ビット専用イメージをデバイスに書き込めます。

Android Emulator

Android 12(API レベル 31)以降の Android Emulator のシステム イメージは 64 ビットのみです。Android 12(API レベル 31)以降のシステム イメージを使用して Android Virtual Device(AVD)を作成し、厳格な 64 ビット専用の環境を構築してアプリをテストします。

その他のデバイス オプション

これらのデバイスがない場合や Android Emulator を使用できない場合は、Google Pixel や他のメーカーの最近の主力デバイスなどの 64 ビット対応のデバイスを使用します。

アプリをインストールしてテストする

APK の最も簡単なテスト方法は、Android Debug Bridge(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 ビットデバイスでの実行時にアプリに影響する以下の問題が発生していないかどうかをご確認ください。アプリは影響を受けるライブラリに直接依存していない場合でも、アプリの依存関係にあるサードパーティのライブラリや SDK が依存している可能性があります。

SoLoader

ネイティブ コード ローダーの SDK SoLoader を使用している場合は、v0.10.4 以上に更新してください。アプリで SoLoader に依存する SDK を使用している場合は、影響を受ける SDK も最新の安定版に必ず更新してください。

SoLoader v0.9.0 以前では、システム ライブラリが /vendor/lib:/system/lib にあることを前提としています。このバグは、パスが存在する Google Pixel 7 などのデバイスでは検出できませんが、この前提条件が原因で、システム ライブラリが /vendor/lib64:/system/lib64 にしかないデバイスではクラッシュが発生します。

SoLoader が原因で発生するこの問題やその他の問題の修正について詳しくは、Google ヘルプセンターに記載されている回答をご覧ください。

OpenSSL

OpenSSL ライブラリを使用している場合は、OpenSSL 1.1.1i 以上に更新してください。アプリで、HTTPS 通信を提供する SDK や、OpenSSL に依存するその他の SDK を使用している場合は、その SDK も最新の OpenSSL バージョンを使用している最新バージョンに必ず更新してください。入手できない場合は、SDK プロバイダにお問い合わせください。

ARMv8.3 PAC 機能は、実行時にポインタを認証することでハードウェアを利用した制御フローの整合性を実現します。古いバージョンの OpenSSL はこの機能を誤って使用しているため、ARMv8.3a 以上をベースとするプロセッサを搭載したすべてのデバイスで実行時にクラッシュが発生します。

OpenSSL が原因で発生するこの問題やその他の問題の修正について詳しくは、Google ヘルプセンターに記載されている対応する回答をご覧ください。

BTI

ARMv8.5 以降は、JOP 攻撃から保護できるよう Branch Target Instruction(BTI)を使用しています。BTI でビルドされたライブラリのランダム オフセットに分岐する以前のバージョンの難読化 SDK を使用すると、アプリがクラッシュする可能性があります。命令は HINT でエンコードされるため、このバグは、BTI をサポートしていないデバイスでは検出できません。

公開する

アプリの準備ができたら、通常どおりに公開します。いつものように、おすすめの方法に沿ってアプリをデプロイしてください。アプリの品質が安定していることを確認するために、クローズド テストトラックを利用し、ユーザー数を制限して公開することをおすすめします。

メジャー アップデートの公開時と同様に、64 ビット対応のデバイスで徹底的にテストしてから、多くのユーザーに公開してください。