各種の API レベル用の APK を複数作成する

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

Android アプリを開発して Google Play で複数の APK を利用する場合は、最初から適切な方法を採用し、開発プロセスで不要な問題の発生を防ぐことが重要です。このレッスンでは、わずかに異なる API レベル範囲をカバーする複数の APK を作成する方法を説明します。また、複数 APK のコードベースをできるだけ効率的に管理するために必要なツールも紹介します。

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

複数の世代の Android プラットフォームで動作するアプリを作成する場合、下位互換性を犠牲にすることなく、新しいデバイスの新しい機能をアプリで利用できる必要があります。初めからは複数 APK のサポートが最善のソリューションに思えるかもしれませんが、多くの場合はそうではありません。複数 APK のデベロッパー ガイドの単一 APK を代わりに使用するセクションには、Google のサポート ライブラリの使用など、単一 APK で目的を達成する方法に関する有用な情報が含まれています。また、この記事にあるリフレクションのようなコンピューティング コストの高い手法に頼らずに、単一 APK で特定の API レベルでのみ実行されるコードを作成する方法を学ぶこともできます。

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

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

この後のレッスンでは、トピックを調査し、リンク先のリソースの資料を慎重に吟味したうえで、複数 APK がアプリにとって正しい選択であると判断したという前提に立って説明を進めます。

要件を図示する

まず、簡単なグラフを作成して、必要な APK の数と、各 APK がカバーする API 範囲を素早く判断します。参考として、Android デベロッパー ウェブサイトのプラットフォームのバージョン ページでは、特定のバージョンの Android プラットフォームを搭載したアクティブなデバイスの相対数に関するデータを提供しています。また、初めは簡単そうに見えますが、各 APK がどの API レベルのセットをターゲットにするかを把握するのは、かなりのスピードで困難になります。特に、重複が発生する可能性が高いです。要件の図は短時間で簡単に作成でき、後で手軽に参照できるので便利です。

複数 APK のチャートを作成するには、まず Android プラットフォームのさまざまな API レベルを表すセルの行から開始します。Android の将来のバージョンを表すため、最後に追加のセルをスローします。

3 4 5 6 7 8 9 10 11 12 13 +

次に、個々の APK を表す色をセルに塗ります。次の図は、各 APK を API レベルの特定の範囲に適用する 1 つの例を示しています。

3 4 5 6 7 8 9 10 11 12 13 +

この図が完成したら、チームに配布します。プロジェクトでのチーム コミュニケーションはすぐにシンプルになりました。「API レベル 3 ~ 6 の APK はどうだった?Android 1.x の APK はどう?」と尋ねる代わりに、うまくいってる?」と尋ねる代わりに、「Blue APK の今後の予定は?」と尋ねるだけです。

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

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

注: ライブラリ プロジェクトを作成してインクルードする方法の実装の詳細はこのレッスンの範囲外ですが、Android ライブラリを作成するを読むとわかりやすくなります。

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

一方、アプリをゼロから作成する場合は、できる限り最初にライブラリ プロジェクトにコードを記述し、必要な場合にのみ個々の APK に移動するようにします。長い目で見れば、この blob を 1 つに追加し、次に別の blob、さらに数か月後に blob をライブラリ セクションに移動できないか判断しようと試みるよりも、ずっと管理が容易です。

新しい 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 で再実装する必要がなくなります。

マニフェストを調整する

ユーザーが複数の APK を使用するアプリを Google Play からダウンロードする場合、使用すべき APK は次の 2 つのシンプルなルールによって選択されます。

  • マニフェストで特定の APK が適格であることが示されている必要がある
  • 適格な APK のうち、バージョン番号が最も大きいものが優先される

例として、前述の複数 APK のセットを取り上げます。どの APK の最大 API レベルも設定していないと仮定します。個別に見積もると、各 APK の可能な範囲は次のようになります。

3 4 5 6 7 8 9 10 11 12 13 +
3 4 5 6 7 8 9 10 11 12 13 +
3 4 5 6 7 8 9 10 11 12 13 +

minSdkVersion の値が大きい APK もより高いバージョン コードを持つ必要があるため、versionCode の値は赤 ≥ 緑 ≥ 青色であることがわかっています。したがって、結果的にこの図は次のように簡略化できます。

3 4 5 6 7 8 9 10 11 12 13 +

さらに、赤の APK には他の 2 つにはない要件があると仮定します。 Android デベロッパー ガイドの Google Play 上のフィルタページには、考えられる要因の完全なリストがあります。たとえば、赤色には前面カメラが必要であるとします。実際、赤色の APK の最大の目的は、前面カメラと API 11 で追加された優れた新機能を組み合わせることです。しかし、実のところ、API 11 をサポートするすべてのデバイスに前面カメラが搭載されているわけではありません。最悪!

幸いなことに、ユーザーがそのようなデバイスから Google Play を閲覧している場合、Google Play はマニフェストを確認し、Red が前面カメラを要件としてリストしていることを認識します。Red とそのデバイスはデジタル天国には一致しないと判断した結果、赤はそのまま無視します。Green は、maxSdkVersion が定義されていないため、API 11 を搭載したデバイスと上位互換性があるだけでなく、前面カメラの有無も関係ないことを確認します。前面カメラの問題はあるものの、その特定の API レベルをサポートする APK がまだ存在していたため、ユーザーは Google Play からアプリをダウンロードできます。

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

青: 03001, 03002, 03003, 03004...
緑: 07001、07002、07003、07004...
赤: 11001, 11002, 11003, 11004...

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

青:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="03001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="3" />
    ...

緑:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="07001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="7" />
    ...

赤:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="11001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="11" />
    ...

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

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

  • すべての APK は同じパッケージ名を持つ必要があります
  • すべての APK は同じ証明書で署名する必要があります
  • プラットフォーム バージョンで APK が重複している場合、minSdkVersion が大きい APK の方が、大きいバージョン コードを持つ必要があります
  • マニフェスト フィルタを念入りにチェックして競合する情報がないことを確認します(Cupcake バージョンの特大画面のみをサポートする 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: 'small' 'normal' 'large' 'xlarge'
supports-any-density: 'true'
locales: '--_--'
densities: '120' '160' '240'

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

その原因は、必要な SEND_SMS 権限の追加により、android.hardware.telephony の機能要件が暗黙的に追加されたことにあります。API 11 は Honeycomb(タブレット向けに最適化された Android のバージョン)であり、Honeycomb デバイスにはテレフォニー ハードウェアがないため、すべてのケースで Google Play はこの APK を除外します。ただしこれは、将来、より上位の API レベルとテレフォニー ハードウェアの両方を備えたデバイスが登場するまでのことです。

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

<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 が目的のデバイスをターゲットにしていることを確認するため、該当のテストデバイスにアプリをダウンロードします。これで完了です。