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

2019 年 8 月 1 日以降、Google Play で公開するアプリは 64 ビット アーキテクチャをサポートする必要があります。64 ビット CPU は、高速かつ豊かなエクスペリエンスをユーザーに提供します。64 ビット バージョンのアプリを追加することで、パフォーマンスを向上させ、将来のイノベーションに備え、64 ビット ハードウェアのみで構成されたデバイスに対応できるようになります。

このガイドでは、32 ビット バージョンのアプリを 64 ビットデバイスで使用できるようにするために今すぐできることについて説明します。

アプリを調べる

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

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

アプリが 64 ビット要件を満たしているかどうかを簡単にチェックするには、Play Console にアクセスして、既存のリリースが準拠しているかどうか確認します。

Play Console では、未公開のリリースに 64 ビット要件に関する問題がある場合にも、警告が表示されます。次に例を示します。

このようなアラートが表示された場合は、以下の手順に沿ってアプリの対応を行ってください。

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

まず、アプリでネイティブ コードを使用しているかどうかを確認します。次の場合は、アプリでネイティブ コードを使用しています。

  • アプリで 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 Analyzer を使用してネイティブ ライブラリを探す

APK Analyzer は、ビルドした APK のさまざまな面を評価するツールです。ここでは、APK Analyzer を使用してネイティブ ライブラリを探し、64 ビット ライブラリを含めるようにします。

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

    APK Analyzer を起動する

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

  4. lib フォルダ内を調べます。「.so」ファイルはこのフォルダ内にあります。アプリ内で「.so」ファイルがまったく見つからない場合、そのアプリは対応済みのため、これ以上の対処は必要ありません。armeabi-v7a または x86 が見つかった場合は、32 ビット ライブラリが存在します。

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

    APK Analyzer を起動する

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

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

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

APK ファイルは ZIP ファイルに似た構造になっており、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-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 設定に指定するだけです。

// Your app's build.gradle
    apply plugin: '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'
    // ...
    

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 ビット整数型にポインタが収まらなくなったことです。int 型、unsigned 型、uint32_t 型などにポインタを格納しているコードを更新する必要があります。Unix システムの場合は long とポインタのサイズが一致しますが、Windows の場合は一致しないため、代わりに、意図が明確な uintptr_t 型や intptr_t 型を使用する必要があります。ptrdiff_t 型を使用すると、2 つのポインタ間の違いを格納できます。

ポインタ以外でも、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 を使用します。

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

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

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

Android App Bundle を使用するようにアプリを切り替えると、APK サイズが改善され、現在のサイズよりも削減できる場合があります。

ゲーム デベロッパー

サードパーティ製のゲームエンジンの移行は、リードタイムの長い集中的なプロセスです。幸い、以下のよく使われている 3 つのエンジンはすべて、64 ビットをサポートしています。

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

Unity デベロッパー

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

Unity は、バージョン 2018.2 とバージョン 2017.4.16 で 64 ビットのサポートを開始しました。

64 ビットをサポートしていないバージョンを使用している場合は、アップグレードするバージョンを決めて、Unity から提供されているガイドに沿って環境を移行します。必ず、64 ビット ライブラリをビルド可能なバージョンにアプリがアップグレードされるようにしてください。Unity では、最新の LTS バージョンのエディタにアップグレードして、最新の機能とアップデートを利用するよう推奨しています。

以下の表に、Unity の各種バージョンと推奨事項を示します。

Unity のバージョン 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] に移動して、Android 向けにビルドされることを確認します(Unity のマークが 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 ファイルがないかどうか検査し、Play Console にアップロードします。

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 ビット対応のデバイスで徹底的にテストしてから多くのユーザーに公開してください。