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

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

このガイドでは、32 ビット版のアプリを 64 ビットデバイスで使用できるようにするためにすぐに開始できる手順をご紹介します。

アプリを調べる

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

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

アプリが 64 ビット要件を満たしているかどうかを調べるには、Play Console で既存のリリースが要件に準拠しているかどうかを確認する方法が簡単です。

未公開のリリースでも、64 ビット要件に関する問題があれば Play Console に警告が表示されます。次の例をご覧ください。

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

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

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

  • アプリで 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 ビットの両方のアーキテクチャ向けにビルドされた 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」ファイルはこのフォルダ内にあります。アプリ内で「.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 設定に指定するだけです。

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 型を使用するようにします。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 を使用します。

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

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 を使用している場合は、アップグレードするバージョンを決めて、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 ビット対応のデバイスが必要です。Google の Pixel やその他の主力デバイスなど、さまざまな人気機種が 64 ビットに対応しています。

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