6 月 3 日の「#Android11: The Beta Launch Show」にぜひご参加ください。

アプリのサイズを削減

多くの場合、ユーザーは大容量のアプリのダウンロードを避けます。特に新興市場では、接続が不安定な 2G、3G ネットワークや、従量課金制のプランを利用するユーザーが多いため、この傾向が顕著です。このページでは、アプリのダウンロード サイズを減らすことで、より多くのユーザーにアプリをダウンロードしてもらう方法を説明します。

Android App Bundle を使用してアプリをアップロードする

Google Play にアプリを公開するときにサイズをすぐに削減するには、アプリを Android App Bundle としてアップロードするのが最も簡単です。この新しいアップロード形式には、アプリのコンパイル済みコードとリソースがすべて含まれる一方で、APK の生成と署名は Google Play で行います。

Google Play の新しいアプリ配信モデルである「Dynamic Delivery」が、App Bundle を使用して、個々のユーザーのデバイス構成に合わせて最適化した APK を生成、配信するため、ユーザーは、アプリの実行に必要なコードとリソースをダウンロードするだけで済みます。これにより、デベロッパー側では、多様なデバイスをサポートするために複数の APK を生成、署名、管理する必要がなくなり、ユーザー側では、サイズの小さい最適化された APK をダウンロードできるようになります。

Google Play では、App Bundle を使用して公開されているアプリに対して 150 MB 以下の圧縮ダウンロード サイズ制限が適用されるため、アプリのダウンロード サイズをできるだけ小さくするために、ここに記載されているガイドラインを適用することをおすすめします。

署名済み APK をアップロードして Google Play に公開するアプリの場合、圧縮ダウンロード サイズは 100 MB 以下に制限されます。

Android Size Analyzer を使用する

Android Size Analyzer ツールを使用すると、アプリのサイズを縮小するさまざまな戦略を簡単に特定して実装できます。これは、Android Studio プラグインとスタンドアロン JAR のどちらの形でも使用できます。

アナライザを Android Studio で使用する

図 1 に示すように、Android Studio のプラグイン マーケットプレイスを使用して、Android Size Analyzer プラグインをダウンロードできます。プラグイン マーケットプレイスを開いて、プラグインをインストールする手順は次のとおりです。

  1. [File] > [Settings](Mac の場合は [Android Studio] > [Preference])を選択します。
  2. 左パネルの [Plugins] セクションを選択します。
  3. [Marketplace] タブをクリックします。
  4. 「Android Size Analyzer」プラグインを探します。
  5. Analyzer プラグインの [Install] ボタンをクリックします。

図 1. [Marketplace] タブの Android Size Analyzer プラグイン

プラグインをインストールしたら、メニューバーから [Analyze] > [Analyze App Size] を選択して、現在のプロジェクトでアプリサイズ分析を実行します。プロジェクトの分析が終わると、図 2 に示すように、アプリのサイズを縮小するためのおすすめの方法を表示するツール ウィンドウが表示されます。

図 2. おすすめの方法を表示する Android Size Analyzer プラグインのツール ウィンドウ

コマンドラインからアナライザを使用する

最新バージョンの Android Size Analyzer は、GitHub から TAR または ZIP ファイルとしてダウンロードできます。アーカイブを展開した後、次のいずれかのコマンドを使用して、Android プロジェクトまたは Android App Bundle で、size-analyzer スクリプト(Linux または MacOS)または size-analyzer.bat スクリプト(Windows)を実行します。

    ./size-analyzer check-bundle <path-to-aab>
    ./size-analyzer check-project <path-to-project-directory>
    

APK の構造を理解する

アプリのサイズを縮小する方法を学ぶ前に、アプリの APK の構造を理解しておくことをおすすめします。APK ファイルは、アプリを構成するすべてのファイルを含む ZIP アーカイブからなります。この ZIP には、Java クラスファイル、リソース ファイル、コンパイル済みリソースを含むファイルなどが含まれます。

APK のディレクトリ構成は次のとおりです。

  • META-INF/: CERT.SFCERT.RSA の署名ファイル、MANIFEST.MF マニフェスト ファイルが含まれます。
  • assets/: アプリが AssetManager オブジェクトを使用して取得できる、アプリのアセットが含まれます。
  • res/: resources.arsc にコンパイルされていないリソースが含まれます。
  • lib/: プロセッサのソフトウェア レイヤに固有のコンパイル済みコードが含まれます。このディレクトリには、プラットフォーム タイプごとのサブディレクトリ(armeabiarmeabi-v7aarm64-v8ax86x86_64mips など)が含まれます。

APK には次のファイルも含まれます。そのうち、AndroidManifest.xml のみが必須です。

  • resources.arsc: コンパイル済みのリソースが含まれます。このファイルには、res/values/ フォルダのすべての設定のうち XML コンテンツが含まれます。この XML コンテンツは、パッケージング ツールによって抽出され、バイナリ形式にコンパイルされて、コンテンツとしてアーカイブされます。このコンテンツには、言語の文字列とスタイルのほか、レイアウト ファイルや画像など、resources.arsc ファイルに直接含まれていないコンテンツへのパスが含まれます。
  • classes.dex: Dalvik / ART 仮想マシンで認識される DEX ファイル形式でコンパイルされたクラスが含まれます。
  • AndroidManifest.xml: コア Android マニフェスト ファイルが含まれます。このファイルには、アプリの名前、バージョン、アクセス権、参照されたライブラリ ファイルがリストされます。このファイルは Android のバイナリ XML 形式です。

リソースの数とサイズを縮小する

APK のサイズは、アプリの読み込み時間、メモリの使用量、消費電力に影響します。APK を縮小するための簡単な方法の 1 つが、APK に含まれるリソースの数とサイズの削減です。特に、アプリで不要になったリソースの削除や、画像ファイルの代わりとなるスケーラブルな Drawable オブジェクトの使用が可能です。ここでは、これらの方法に加え、APK 全体のサイズを小さくするためにアプリ内のリソースを削減するその他の方法について説明します。

未使用のリソースを削除する

lint ツールは、Android Studio の静的コード アナライザで、コードが参照していない res/ フォルダ内のリソースを検出します。lint ツールによって、プロジェクト内に未使用と思われるリソースが検出されると、以下の例のようなメッセージが出力されます。

    res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
        to be unused [UnusedResources]
    

注: lint ツールでは、assets/ フォルダ、リフレクションを介して参照されるアセット、アプリにリンクしたライブラリ ファイルはスキャンされません。また、リソースの存在を通知するのみで、削除はしません。

コードに追加したライブラリに、不要なリソースが含まれていることもあります。アプリの build.gradle ファイルで shrinkResources を有効にすると、Gradle によってリソースを自動的に削除できます。

    android {
        // Other settings

        buildTypes {
            release {
                minifyEnabled true
                shrinkResources true
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    

shrinkResources を使用するには、コードの圧縮も有効にする必要があります。ビルドプロセス時に、まず R8 によって未使用のコードが削除されます。次に、Android Gradle プラグインによって未使用のリソースが削除されます。

コードとリソースの圧縮、Android Studio の APK サイズ縮小の方法については、アプリの縮小、難読化、最適化をご覧ください。

Android Gradle Plugin 0.7 以上では、アプリでサポートする設定を宣言できます。Gradle は、resConfigresConfigs のフレーバーと defaultConfig オプションを使用してこの情報をビルドシステムに渡します。ビルドシステムは、サポートされない他の設定のリソースが APK に表示されることを防ぐため、これによって APK のサイズが縮小されます。この機能について詳しくは、未使用の代替リソースの削除をご覧ください。

ライブラリからのリソースの使用を最小限に抑える

通常 Android アプリを開発する場合は、外部のライブラリを使用してアプリのユーザビリティと汎用性を向上させます。たとえば、Android サポート ライブラリを参照して古いデバイスのユーザー エクスペリエンスを改善できます。また、Google Play 開発者サービスを使用してアプリ内のテキストを自動翻訳できます。

サーバーやデスクトップに対応するよう作成されたライブラリには、アプリに必要ないオブジェクトやメソッドが数多く含まれている可能性があります。ライセンスでライブラリの変更が許可されていれば、ライブラリのファイルを編集することで、アプリに必要なライブラリの部分のみを含めることができます。また、別のモバイル向けライブラリを使用して、アプリに特定の機能を追加することも可能です。

注: コード圧縮を使用すると、ライブラリの不要なコードを削除できます。ただし、ライブラリの大規模な内部依存関係は削除できません。

特定の密度のみをサポートする

Android は非常に多くのデバイスをサポートし、さまざまな画面密度に対応しています。Android 4.4(API レベル 19)以降のフレームワークでは、さまざまな密度(ldpimdpitvdpihdpi,xhdpixxhdpixxxhdpi)をサポートしています。Android はこれらのすべての密度に対応していますが、それぞれの密度にラスター形式のアセットをエクスポートする必要はありません。

特定の密度のデバイスを使用するユーザーの割合がごくわずかの場合は、その密度をアプリにバンドルする必要があるかどうかを検討してください。特定の画面密度のリソースを含めない場合、他の画面密度に合わせて設計された既存のリソースが自動的にスケーリングされます。

スケーリングした画像だけで足りる場合は、drawable-nodpi/ 内の画像のバリアントを 1 つにすることでスペースを大幅に縮小できます。すべてのアプリに xxhdpi 画像バリアントを少なくとも 1 つ含めることをおすすめします。

画面密度について詳しくは、画面サイズと画面密度をご覧ください。

ドローアブル オブジェクトを使用する

一部の画像では、フレームワークによって実行時に画像が動的に描画されるため、静的な画像リソースを必要としません。Drawable オブジェクト(XML の場合は <shape>)が APK 内で使用する容量はごくわずかです。また、XML で Drawable オブジェクトを使用すると、マテリアル デザイン ガイドラインを遵守したモノクロの画像が生成されます。

リソースを再利用する

同じ画像の色合いやシェードが異なるバージョンや回転したバージョンなど、画像のバージョンごとに別々のリソースが含まれていることがあります。Google では、同じリソースセットを再利用し、実行時に必要に応じてカスタマイズすることをおすすめします。

Android には、アセットの色を変更するユーティリティが用意されています。Android 5.0(API レベル 21)以降では、android:tint 属性と tintMode 属性を、以前のバージョンでは、ColorFilter クラスを使用して、アセットの色を変更できます。

また、別のリソースを回転させただけのリソースも削除できます。以下のコード スニペットは、画像の中央を中心に 180 度回転させることで「親指を立てる」画像を「親指を下げる」画像に変換する例です。

    <?xml version="1.0" encoding="utf-8"?>
    <rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/ic_thumb_up"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fromDegrees="180" />
    

コードからレンダリングする

画像の手続き型レンダリングによっても APK のサイズを縮小できます。手続き型レンダリングを使用すると、APK に画像ファイルが保存されなくなるため、スペースが解放されます。

PNG ファイルをクランチする

aapt ツールは、res/drawable/ 内の画像リソースを、ビルドプロセス中に可逆圧縮により最適化できます。たとえば、aapt ツールを使用すると、256 色以上を必要としないトゥルーカラーの PNG を、カラーパレットを使用する 8 ビットの PNG に変換できます。この変換により、画質を変えずにメモリの容量を縮小できます。

なお、aapt には次の制限があります。

  • aapt ツールでは、asset/ フォルダに含まれる PNG ファイルは圧縮されません。
  • aapt ツールで画像ファイルを最適化するには、使用される色が 256 色以下である必要があります。
  • aapt ツールにより、すでに圧縮されている PNG ファイルのサイズが大きくなることがあります。これを防ぐには、以下のように cruncherEnabled フラグを使用して Gradle で PNG ファイルに対するこのプロセスを無効にします。
    aaptOptions {
        cruncherEnabled = false
    }
    

PNG ファイルと JPEG ファイルを圧縮する

pngcrushpngquantzopflipng などのツールを使用すると、画質を損なわずに PNG ファイルのサイズを縮小できます。これらはすべて、画質を保ちながら PNG ファイルのサイズを縮小できるツールです。

pngcrush ツールは特に効果的です。このツールは、PNG フィルタと zlib(Deflate)パラメータを順番に調べ、フィルタやパラメータを組み合わせて画像を圧縮し、圧縮後の出力が最も小さい設定を選択します。

JPEG ファイルを圧縮するには、packJPGguetzli などのツールを使用できます。

WebP ファイル形式を使用する

Android 3.2(API レベル 13)以降を対象とする場合は、PNG ファイルや JPEG ファイルの代わりに、WebP ファイル形式を画像に使用することもできます。WebP 形式には非可逆圧縮モード(JPEG の置き換え)と透過モード(PNG の置き換え)がありますが、圧縮率は JPEG や PNG より高くなります。

既存の BMP、JPG、PNG、静的 GIF 画像は、Android Studio を使用して WebP 形式に変換できます。詳しくは、Android Studio を使用した WebP 画像の作成をご覧ください。

注: Google Play で APK が承認されるのは、ランチャー アイコンが PNG 形式の場合のみです。

ベクター グラフィックを使用する

ベクター グラフィックを使用して、解像度に依存しないアイコンやその他のスケーラブルなメディアを作成できます。これらのグラフィックを使用することで APK の容量を大幅に縮小できます。ベクター画像は Android では VectorDrawable オブジェクトとして表示されます。VectorDrawable オブジェクトを使用すると、100 バイトのファイルで画面サイズの鮮明な画像を生成できます。

ただし、システムが各 VectorDrawable オブジェクトをレンダリングするのには、かなりの時間がかかります。また、画像を大きなサイズで画面表示すると、さらに長い時間がかかります。そのため、ベクター グラフィックを使用するのは、画像を小さなサイズで表示する場合のみにすることを検討してください。

VectorDrawable オブジェクトの使用方法について詳しくは、ドローアブルの操作をご覧ください。

アニメーション画像にベクター グラフィックを使用する

フレーム単位のアニメーションの作成に AnimationDrawable を使用しないでください。アニメーションのフレームごとにビットマップ ファイルを含める必要があり、APK のサイズが著しく増大するためです。

アニメーションのベクター型ドローアブルを作成する場合は、代わりに AnimatedVectorDrawableCompat を使用してください。

ネイティブ コードと Java コードを削減する

アプリの Java コードベースとネイティブ コードベースのサイズを縮小する方法をいくつかご紹介します。

不要な生成コードを削除する

自動生成されるコードの容量をご確認ください。たとえば、多くのプロトコル バッファツールでは、生成されるメソッドやクラスの数が非常に多く、そのためにアプリのサイズが 2~3 倍になることがあります。

列挙を利用しない

1 つの列挙で、アプリの classes.dex ファイルのサイズが 1.0~1.4 KB ほど増えることがあります。システムが複雑だったり共有ライブラリがあったりすると、サイズがさらに大きくなる可能性があります。可能であれば、@IntDef アノテーションとコード圧縮を使用して列挙を取り除き、整数に変換することを検討してください。この型変換では、列挙の型の安全性がすべて保証されます。

ネイティブ バイナリのサイズを縮小する

アプリでネイティブ コードと Android NDK を使用している場合は、コードの最適化でも、アプリのリリース バージョンのサイズを縮小できます。次に、デバッグ シンボルを削除する方法とネイティブ ライブラリを抽出しない方法の 2 つの便利な方法を紹介します。

デバッグ シンボルを削除する

アプリが開発中でまだデバッグが必要なうちは、デバッグ シンボルの使用が妥当です。開発が完了したら、Android NDK で提供されている arm-eabi-strip ツールを使用して、不要なデバッグ シンボルをネイティブ ライブラリから削除できます。削除した後、リリースビルドをコンパイルできます。

ネイティブ ライブラリを抽出しない

アプリのリリース バージョンをビルドする場合は、アプリのマニフェストの <application> 要素に android:extractNativeLibs="false" を設定し、圧縮されていない .so ファイルを APK でパッケージ化します。このフラグを無効にすると、インストール時に PackageManager が APK からファイル システムに .so ファイルをコピーできなくなり、アプリの更新を小さくできるメリットもあります。Android Gradle プラグイン 3.6.0 以降を使用してアプリをビルドする場合、このプロパティはデフォルトで "false" に設定されます。

複数の小さい APK を維持する

APK には、追加の言語や画面密度ごとのリソースなど、ユーザーがダウンロードしても使用しないコンテンツが含まれることがあります。ユーザーのダウンロードを最小限に抑えるには、Android App Bundle を使用してアプリを Google Play にアップロードすることをおすすめします。App Bundle をアップロードすると、個々のユーザーのデバイス構成に合わせて最適化された APK が Google Play によって自動的に生成、配信されるため、ユーザーはアプリの実行に必要なコードとリソースをダウンロードするだけで済みます。これにより、デベロッパー側では、多様なデバイスをサポートするために複数の APK を生成、署名、管理する必要がなくなり、ユーザー側では、サイズの小さい最適化された APK をダウンロードできるようになります。

アプリを Google Play に公開しない場合は、画面サイズや GPU テクスチャのサポートなどの要因で区別された、複数の APK にアプリを分割できます。

ユーザーがアプリをダウンロードする場合は、デバイスに搭載されている機能や設定に基づいて適切な APK を受け取り、該当しない機能向けのアセットを受け取ることはありません。たとえば、ユーザーのデバイスが hdpi の場合、より高密度のディスプレイを搭載したデバイス向けの xxxhdpi リソースは必要ありません。

詳しくは、APK 分割の設定複数の APK の維持をご覧ください。