複数のディメンションを持つ APK を複数作成する

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

Android アプリを開発して Google Play で複数の APK を利用する場合は、最初からおすすめの方法を採用し、開発プロセスで不必要な問題が生じないようにすることが重要です。このレッスンでは、アプリの APK を複数作成し、それぞれで異なる画面サイズクラスをカバーする方法について説明します。また、複数の APK のコードベースをできるだけ簡単に管理するために必要なツールも利用できます。

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

利用可能な非常に幅広い Android デバイスで機能するアプリを作成する場合、各デバイスでアプリが最適に表示されるようにする必要があります。大画面のスペースを活用できるだけでなく、小さな画面でも動作し、Android API の新機能やビジュアル テクスチャを最先端のデバイスで利用できるようにしますが、古い画面を無視してはいけません。最初は複数 APK のサポートが最良の解決策であるかのように見えるかもしれませんが、多くの場合、そうではありません。複数 APK ガイドの単一 APK の代替セクションには、Google のサポート ライブラリの使用など、単一 APK でこれらすべてを実現する方法についての有用な情報や、Android デベロッパー ガイド全体のリソースへのリンクが記載されています。

管理できる場合、アプリを単一の APK に制限することで、次のようないくつかの利点があります。

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

このレッスンの残りの部分では、このトピックについて調査し、リンクされたリソースにしっかりと内容を取り込んで、複数の APK がアプリに適していると判断したことを前提としています。

要件を図示する

まず、簡単なグラフを作成して、必要な APK の数と各 APK がカバーする画面サイズをすばやく判断します。幸いなことに、要件をすばやく簡単にまとめることができ、後で簡単に参照できます。たとえば、APK を API と画面サイズの 2 つのディメンションに分割するとします。可能な値のペアごとに行と列を含むテーブルを作成し、「blob」の色を各色で表します。各色は 1 つの APK を表します。

3 4 5 6 7 8 9 10 11 12 +
標準
特大

上記の図は、APK を 4 つに分ける場合の例です。青はすべての小/標準画面のデバイス用、緑は大画面デバイス用、赤は特大画面デバイス用です。すべて API 範囲は 3 ~ 10 です。すべての画面サイズに対応する紫色は特別なケースですが、API 11 以降でのみ有効です。さらに重要な点は、この表を見れば、特定の API と画面サイズの組み合わせをどの APK がカバーしているかをすぐに把握できることです。「Xoom で 3 ~ 10 の特大 APK をテストした」よりも「Xoom で赤色をテストした」の方がはるかに簡単です。このチャートを印刷して、コードベースで作業するすべての人に配布してください。そうすれば、仕事がずっと楽になります。

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

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

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

既存のアプリを変換して複数の APK をサポートする場合は、ローカライズされたすべての文字列ファイル、値のリスト、テーマの色、メニュー アイコン、レイアウト(APK 間で変更されないもの)をコードベースで調べて、すべてをライブラリ プロジェクトに入れます。あまり変更しないコードも ライブラリプロジェクトに配置してくださいこれらのクラスを拡張して、APK から APK に 1 つか 2 つのメソッドを追加することになるでしょう。

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

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

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

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

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

マニフェストを調整する

複数の APK を使用するアプリをユーザーが Google Play からダウンロードする場合、次の 2 つの単純なルールに基づいて、使用する適切な APK が選択されます。

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

たとえば、前述の複数の APK のセットについて考えてみましょう。各 APK は、「ターゲット」の画面サイズより大きいすべての画面サイズをサポートするように設定されています。先ほどのサンプルグラフを見てみましょう。

3 4 5 6 7 8 9 10 11 12 +
標準
特大

カバレッジが重複しても構わないため、各 APK がカバーするエリアは次のように記述できます。

  • 青はすべての画面サイズをカバーし、minSDK は 3 です。
  • 緑は大画面以上の画面サイズをカバーし、minSDK は 3 です。
  • 赤は特大画面(通常はタブレット)をカバーし、minSDK は 9 です。
  • 紫はすべての画面サイズをカバーし、minSDK は 11 です。

上記のルールでは、多くの重複があります。たとえば、API 11 の特大デバイスでは、指定された 4 つの APK のいずれも実行できると考えられます。ただし、「最も高いバージョン番号が優先」のルールを使用して、優先順位を次のように設定できます。

紫 ≥ 赤 ≥ 緑 ≥ 青

重複をすべて許容することには理由があります。Purple APK には、他の 2 つにはない要件があるとします。考えられる問題の原因の一覧については、Android デベロッパー ガイドの Google Play でのフィルタのページをご覧ください。たとえば、紫色には前面カメラが必要だとします。むしろ、Purple はすべて、前面カメラで面白いものを使うことにあります。ただし、API 11 以降のデバイスすべてに前面カメラが搭載されているわけではありません。その場合はどうなるでしょうか?

幸い、ユーザーがそのようなデバイスから Google Play を閲覧している場合、Google Play はマニフェストを確認し、Purple が前面カメラを要件としてリストしていることを確認して、静かに無視します。Purple とそのデバイスはデジタル天国と一致していると判断できます。これにより、Red が特大画面デバイスと互換性があるだけでなく、前面カメラの有無も考慮していないことがわかります。ユーザーは、引き続き Google Play からアプリをダウンロードできます。これは、前面カメラ全体に問題が発生しましたが、その特定の API レベルをサポートする APK が残っていたからです。

すべての APK を別々の「トラック」に保存するには、適切なバージョン コード スキームを使用することが重要です。推奨されるバージョンは、デベロッパー ガイドのバージョン コードのセクションに記載されています。セクション全体を読む価値はありますが、基本的な要点は、この APK セットの 2 桁で minSDK を、2 桁で最小/最大画面サイズ、3 桁でビルド番号を表します。これにより、デバイスが Android の新しいバージョン(10 から 11 など)にアップグレードされたときに、現在インストールされている APK よりも有効で優先される APK は、デバイスでは「アップグレード」と見なされます。APK のサンプルセットに適用するバージョン番号スキームは次のようになります。

青: 0304001, 0304002, 0304003...
緑: 0334001、0334002、0334003
赤: 0344001、0344002、0344003...
紫: 1104001、1104002、1104003...

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

青:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="0304001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="3" />
    <supports-screens android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true" />
    ...

緑:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="0334001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="3" />
    <supports-screens android:smallScreens="false"
        android:normalScreens="false"
        android:largeScreens="true"
        android:xlargeScreens="true" />
    ...

赤:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="0344001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="3" />
    <supports-screens android:smallScreens="false"
        android:normalScreens="false"
        android:largeScreens="false"
        android:xlargeScreens="true" />
    ...

紫:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="1104001" android:versionName="1.0" package="com.example.foo">
    <uses-sdk android:minSdkVersion="11" />
    <supports-screens android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true" />
    ...

技術的には、複数 APK は supports-screens タグまたは compatible-screens タグのいずれかで動作します。一般的には Supports-screens が推奨されますが、両方を使用することは一般におすすめできません。処理が不必要に複雑になり、エラーが発生する可能性が高くなります。また、マニフェストではデフォルト値(デフォルトでは「small」と「normal」は常に true)を利用するのではなく、各画面サイズの値を明示的に設定しています。これにより、こうした問題を軽減できます。たとえば、ターゲット SDK が 9 未満のマニフェストでは、xlarge はまだ存在しないため、自動的に false に設定されます。あえて明示してください。

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

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

  • すべての APK のパッケージ名は同じである必要があります。
  • APK はすべて、同じ証明書で署名する必要があります。
  • プラットフォーム バージョンで APK が重複している場合は、minSdkVersion が高い APK のほうがバージョン コードを高くする必要があります。
  • APK がサポートするすべての画面サイズをマニフェストで true に設定し、回避するすべての画面サイズを false に設定します。
  • マニフェスト フィルタで情報が矛盾していないかを再確認してください(特大画面でのみカップケーキをサポートする APK は誰も見ることができません)。
  • 各 APK のマニフェストは、サポートされる画面、OpenGL テクスチャ、プラットフォーム バージョンのうち少なくとも 1 つで一意である必要があります。
  • 1 台以上のデバイスで各 APK をテストします。それ以外では、ビジネスで最もカスタマイズ性の高いデバイス エミュレータの一つを開発マシンに置いておく必要があります。ぜひ利用してください。

また、市場に投入する前にコンパイル済み 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 の機能要件が暗黙的に追加されたことにあります。ほとんどの特大画面デバイス(すべてではないにしても)はテレフォニー ハードウェアを搭載していないタブレットであるため、このような場合、Google Play は、特大画面サイズとして報告できる大きさとテレフォニー ハードウェアの両方を備えたデバイスが今後登場するまで、このような 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 が目的のデバイスをターゲットにしていることを確認するため、該当のテストデバイスにアプリをダウンロードします。これで完了です。