各種の GL テクスチャ用の APK を複数作成する

アプリを Google Play に公開する場合は、Android App Bundle を作成してアップロードしてください。そうすることで、各ユーザーのデバイス構成に合わせて最適化された APK が Google Play によって自動的に生成、配信されるため、ユーザーはアプリの実行に必要なコードとリソースをダウンロードするだけで済みます。複数の APK を公開するという方法は、Google Play に公開しない場合は便利ですが、各 APK のビルド、署名、管理を自分で行う必要があります。

Android アプリを開発して Google Play で複数の APK を利用する場合は、最初から適切な方法を採用し、開発プロセスで不必要なトラブルが生じるのを避けることが重要です。このレッスンでは、アプリの複数の APK を作成し、各 APK で OpenGL テクスチャ形式の異なるサブセットをサポートする方法を説明します。また、複数 APK のコードベースをできるだけ簡単に維持するために必要なツールも入手できます。

複数 APK の必要性を確認する

すべての使用可能な Android 搭載デバイスで動作するアプリを作成する場合、すべてのデバイスが同じ GL テクスチャのセットをサポートするわけではないとはいえ、個々のデバイスでアプリの外観が最適になるようにしたいと考えるのが自然です。最初は複数 APK をサポートすることが最善のように思えるかもしれませんが、多くの場合そうではありません。複数 APK のデベロッパー ガイドの単一 APK の代用セクションには、サポートされているテクスチャ形式を実行時に検出する方法など、単一 APK でこれを実現する方法に関する有用な情報が記載されています。状況によっては、すべての形式をアプリケーションにバンドルし、実行時に使用する形式を選択する方が簡単な場合もあります。

アプリを単一 APK に限定できるのであれば、次のような利点があります。

  • 公開とテストがより簡単になります
  • 管理するコードベースは 1 つだけです
  • アプリはデバイス構成の変更に適応できます
  • 複数のデバイスにまたがるアプリの復元が機能します
  • 市場選好、ある APK から次の APK への「アップグレード」の動作、どの APK がどのクラスのデバイスに対応するかなどを考慮する必要がありません

このレッスンの残りの部分では、トピックを調査し、リンクされているリソースの素材をしっかりと理解したうえで、複数 APK がアプリに適したパスであると判断したことを前提としています。

要件を図示する

Android デベロッパー ガイドの supports-gl-texture ページには、サポートされている一般的なテクスチャの便利なリファレンスが掲載されています。このページには、特定のテクスチャ形式をサポートするスマートフォン(またはスマートフォンのファミリー)に関するヒントもあります。一般的には、APK の 1 つで ETC1 をサポートすることをおすすめします。このテクスチャ形式は、OpenGL ES 2.0 仕様に対応するすべての Android 搭載デバイスでサポートされているからです。

ほとんどの Android 搭載デバイスは複数のテクスチャ形式をサポートしているので、優先順位を設定する必要があります。まず、アプリがサポートするすべての形式を含む図を作成します。一番左のセルに優先順位が最も低い形式を配置します(これはおそらく、パフォーマンスと互換性の点で現実的なデフォルトといえる堅実な ETC1 になるでしょう)。次に、各セルに APK を表す色を塗ります。

ETC1 ATI PowerVR

図を色分けするメリットは、このガイドのモノクロ化を軽減するだけではありません。チーム内のコミュニケーションも容易になります。各 APK を「ETC1 テクスチャ フォーマットをサポートしているもの」などではなく、「青」、「緑」、「赤」などと呼ぶことができます。

ライブラリ プロジェクトにすべての共通のコードとリソースを配置する

これは、既存の Android アプリを変更する場合でもゼロから作成する場合でも、コードベースに対して最初に実施すべき非常に重要な作業です。ライブラリ プロジェクトに含まれるものはすべて 1 回更新するだけで済みます(言語ローカライズされた文字列、カラーテーマ、共有コードのバグ修正など)。これにより、開発時間を短縮し、簡単に回避できるミスの可能性が低減されます。

注: ライブラリ プロジェクトを作成してインクルードする実装の詳細はこのレッスンでは扱いませんが、Android ライブラリの作成を参照すると速やかに実装できます。

既存のアプリを変換して複数 APK のサポートに使用する場合は、ローカライズされたすべての文字列ファイル、値のリスト、テーマの色、メニュー アイコン、APK 全体で変更されないレイアウトをコードベースで調べて、それらをすべてライブラリ プロジェクトに配置します。ほとんど変更されないコードもライブラリ プロジェクトに配置する必要があります。おそらく、これらのクラスを拡張して、APK から APK にメソッドを 1 ~ 2 個追加できます。

一方、アプリをゼロから作成する場合は、できる限り最初にライブラリ プロジェクトにコードを記述し、必要な場合にのみ個々の APK に移動するようにします。コードを個別に APK に追加していき、数か月経った後でどうすれば大量のコードをライブラリ セクションに移動できるかに頭を悩ませるより、上記のように長期的な視野に立って管理する方がはるかに簡単です。

新しい APK プロジェクトを作成する

リリースする APK ごとに別個の Android プロジェクトが必要です。整理しやすいように、ライブラリ プロジェクトと、すべての関連する APK プロジェクトを同じ親フォルダの下に配置します。また、各 APK は同じパッケージ名を持つ必要がありますが、必ずしもパッケージ名をライブラリと共有する必要はありません。前述のスキームに従って 3 つの APK を使用する場合、ルート ディレクトリは次のようになります。

alexlucas:~/code/multi-apks-root$ ls
foo-blue
foo-green
foo-lib
foo-red

プロジェクトを作成したら、ライブラリ プロジェクトを各 APK プロジェクトへの参照として追加します。可能であれば、ライブラリ プロジェクトで開始アクティビティを定義し、APK プロジェクトでそのアクティビティを拡張します。ライブラリ プロジェクトで開始アクティビティを定義すると、すべてのアプリの初期化を 1 か所にまとめることができるため、個々の APK でアナリティクスの初期化、ライセンス チェックの実行、APK 間であまり変更されないその他の初期化手順などの「ユニバーサル」タスクを再実装する必要がなくなります。

マニフェストを調整する

ユーザーが複数 APK を使用するアプリを Google Play でダウンロードする場合、次の単純なルールで適切な APK が選択されます。

  • マニフェストで特定の APK が適格であることが示されている必要がある
  • 適格な APK のうち、バージョン番号が最も大きいものが優先される
  • APK にリストされたテクスチャ形式のいずれかが市場で販売されているデバイスでサポートされていれば、そのデバイスは適格と見なされる

GL テクスチャに関しては、最後のルールが重要です。それは、具体的には、同じアプリで異なる GL 形式を使用する際は細心の注意を払う必要があることを意味しています。たとえば、99% の時間は PowerVR を使用し、スプラッシュ画面でのみ ETC1 を使用するとします。その場合、マニフェストでは必ず両方の形式のサポートを宣言します。ETC1 のみをサポートするデバイスは互換性があると見なされるので、アプリをダウンロードしたユーザーは予想外のクラッシュ メッセージに驚くことになるかもしれません。一般的には、GL テクスチャ サポートに基づいて各種のデバイスをターゲットにするために複数 APK を使用する場合、APK ごとにテクスチャ形式は 1 つにします。

つまり、実際上、テクスチャのサポートでは、他の 2 つの複数 APK のディメンション(API レベルと画面サイズ)とは少し事情が異なります。どのデバイスにも 1 つの API レベルと 1 つの画面サイズのみがあり、その範囲をサポートするかどうかは APK 次第です。テクスチャを使用する場合、APK では通常 1 つのテクスチャをサポートし、デバイスは多くのテクスチャをサポートします。多くの APK をサポートする 1 台のデバイスではしばしば重複が発生しますが、その解決策はいつもと同様に、バージョン コードです。

例として、数台のデバイスについて、前に定義した APK が各デバイスに適合する数を確認します。

FooPhone Nexus S Evo
ETC1 ETC1 ETC1
PowerVR ATI TC

利用可能な場合は PowerVR 形式と ATI 形式の両方が ETC1 よりも優先されると仮定すると、「最大のバージョン番号が優先する」ルールに従って、各 APK の versionCode 属性を赤 ≥ 緑 ≥ 青のように設定すると、それらをサポートするデバイスでは常に赤と緑の両方が青よりも選択されます。また、赤と緑の両方をサポートするデバイスが登場した場合は、赤が選択されます。

すべての APK を別個の「トラック」に保存するには、適切なバージョン コードのスキームを用意することが重要です。デベロッパー ガイドのバージョン コード セクションに記載されているスキームの使用をおすすめします。上記の例の APK セットは 3 つの可能なディメンションのうち 1 つのみを扱うので、各 APK を 1, 000 単位で区切り、そこから増分すれば十分です。次に例を示します。

青: 1001, 1002, 1003, 1004...
緑: 2001, 2002, 2003, 2004...
赤:3001, 3002, 3003, 3004...

以上をまとめると、Android マニフェストは次のようになります。

青:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="1001" android:versionName="1.0" package="com.example.foo">
    <supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
    ...

緑:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="2001" android:versionName="1.0" package="com.example.foo">
    <supports-gl-texture android:name="GL_AMD_compressed_ATC_texture" />
    ...

赤:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="3001" android:versionName="1.0" package="com.example.foo">
    <supports-gl-texture android:name="GL_IMG_texture_compression_pvrtc" />
    ...

リリース前チェックリストを確認する

Google Play にアップロードする前に、次の項目を念入りにチェックしてください。次に示すのは複数 APK と特に関連の深い項目であり、Google Play にアップロードするすべてのアプリ用の完全なチェックリストではないことにご注意ください。

  • すべての APK は同じパッケージ名を持つ必要があります
  • すべての APK は同じ証明書で署名する必要があります
  • マニフェスト フィルタで競合する情報を再確認します(XLARGE 画面でカップケーキのみをサポートする APK は誰にも表示されません)。
  • 各 APK のマニフェストは、サポートされる画面、OpenGL のテクスチャ、プラットフォーム バージョンのうち、少なくとも 1 つで一意であることが必要です
  • 1 台以上のデバイスで各 APK をテストします。それとは別に、開発マシンには、業界で最もカスタマイズしやすいデバイス エミュレータの 1 つが搭載されています。ぜひ利用してください。

また、市場に出す前にコンパイル済みの APK を検査して、アプリが Google Play に表示されるのを妨げるような不測の要因がないかを確認することも重要です。そのためには、「aapt」ツールを使用すると非常に便利です。Aapt(Android Asset Packaging Tool)は、Android アプリを作成およびパッケージ化するビルドプロセスの一部であり、アプリを手軽に検査できるツールでもあります。

>aapt dump badging
package: name='com.example.hello' versionCode='1' versionName='1.0'
sdkVersion:'11'
uses-permission:'android.permission.SEND_SMS'
application-label:'Hello'
application-icon-120:'res/drawable-ldpi/icon.png'
application-icon-160:'res/drawable-mdpi/icon.png'
application-icon-240:'res/drawable-hdpi/icon.png'
application: label='Hello' icon='res/drawable-mdpi/icon.png'
launchable-activity: name='com.example.hello.HelloActivity'  label='Hello' icon=''
uses-feature:'android.hardware.telephony'
uses-feature:'android.hardware.touchscreen'
main
supports-screens: 'xlarge'
supports-any-density: 'true'
locales: '--_--'
densities: '120' '160' '240'

aapt の出力を調べる際は、supports-screens と compatible-screens の値に競合がないこと、マニフェストで設定した権限の結果として意図しない「uses-feature」値が追加されていないことを確認してください。上記の例では、APK はすべてのデバイスではなく、ほとんどのデバイスには表示されません。

その原因は、必要な SEND_SMS 権限の追加により、android.hardware.telephony の機能要件が暗黙的に追加されたことにあります。大部分の xlarge デバイスはテレフォニー ハードウェアを搭載していないタブレットであるため、Google Play はこのような場合にこの APK を除外します。ただし、今後、xlarge 画面のサイズをレポートするのに十分な大きさで、テレフォニー ハードウェアも搭載したデバイスが登場するまでは、この APK が除外されます。

幸いにも、上記の問題は、マニフェストに次の行を追加すれば簡単に解決できます。

<uses-feature android:name="android.hardware.telephony" android:required="false" />

また、android.hardware.touchscreen 要件も暗黙的に追加されます。タッチスクリーンがないデバイスの TV で APK を表示するには、マニフェストに次の行を追加する必要があります。

<uses-feature android:name="android.hardware.touchscreen" android:required="false" />

リリース前チェックリストの確認が完了したら、Google Play に APK をアップロードします。Google Play を閲覧したときにアプリが表示されるまで少し時間がかかることがあります。表示されたら、最後にもう一度チェックを行います。APK が目的のデバイスをターゲットにしていることを確認するため、該当のテストデバイスにアプリをダウンロードします。これで完了です。