アプリのサイズを削減

ユーザーは、サイズが大きすぎると思われるアプリのダウンロードを避けることがよくあります。この傾向は、デバイスが不安定な 2G や 3G ネットワークに接続している場合や、データの上限があるプランで契約している新興国の市場で顕著です。このページでは、より多くのユーザーにアプリをダウンロードしてもらえるように、アプリのダウンロード サイズを減らす方法について説明します。

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

アプリを Android App Bundle としてアップロードし、Google Play に公開したら、すぐにアプリのサイズを保存します。Android App Bundle は、アプリのコンパイル済みコードとリソースがすべて含まれるアップロード形式ですが、APK の生成と署名は Google Play が行います。

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

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

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 のサイズを小さくするには、APK に含まれるリソースの数とサイズを小さくします。特に、アプリで不要になったリソースの削除や、画像ファイルの代わりとなるスケーラブルな Drawable オブジェクトの使用が可能です。このセクションでは、こうした方法に加え、アプリ内のリソースを削減して APK 全体のサイズを小さくするその他の方法について説明します。

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

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

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

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

Kotlin

android {
    // Other settings.

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

Groovy

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

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

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

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

ネイティブ アニメーション画像のデコード

Android 12(API レベル 31)では、NDK ImageDecoder API が拡張され、アニメーション GIF とアニメーション WebP のファイル形式を使用する画像から、すべてのフレームとタイミング データをデコードできるようになりました。

サードパーティ ライブラリの代わりに ImageDecoder を使用すると、さらに APK サイズを縮小できます。また、セキュリティとパフォーマンスに関連する今後のアップデートを利用できます。

ImageDecoder API について詳しくは、API referenceGitHub のサンプルをご覧ください。

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

Android は、次のようなさまざまな画面密度をサポートしています。

  • ldpi
  • mdpi
  • tvdpi
  • hdpi
  • xhdpi
  • xxhdpi
  • xxxhdpi

Android は上記のすべての密度に対応していますが、それぞれの密度にラスター形式のアセットをエクスポートする必要はありません。

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

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

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

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

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

リソースを再利用する

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

Android には、android:tint 属性と tintMode 属性のいずれかを使用して、アセットの色を変更するためのユーティリティがいくつか用意されています。

また、別のリソースを回転させただけのリソースも削除できます。以下のコード スニペットは、画像の中央を中心に 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 ファイルが大きく表示される場合があります。これを防ぐには、以下のように isCrunchPngs フラグを使用して PNG ファイルに対するこのプロセスを無効にします。
  • Kotlin

        buildTypes.all { isCrunchPngs = false }
        

    Groovy

        buildTypes.all { isCrunchPngs = false }
        

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

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

pngcrush ツールは特に効果的です。このツールは、フィルタとパラメータの各組み合わせを使用して画像を圧縮し、PNG フィルタと zlib(Deflate)パラメータを反復処理します。次に、圧縮された出力が最も小さくなる構成を選択します。

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

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

PNG ファイルや JPEG ファイルを使用する代わりに、WebP ファイル形式を画像に使用することもできます。WebP 形式には、JPG や PNG などのような非可逆圧縮と透過性があり、JPEG や PNG よりも圧縮率が優れています。

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

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

ベクター グラフィックを使用して、解像度に依存しないアイコンやその他のスケーラブルなメディアを作成できます。これらのグラフィックを使用して 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 ツールを使用して、不要なデバッグ シンボルをネイティブ ライブラリから削除できます。その後、リリースビルドがコンパイルできます。

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

アプリのリリース バージョンをビルドする場合は、アプリの build.gradle.kts ファイルの falseuseLegacyPackaging を設定し、圧縮されていない .so ファイルを APK でパッケージ化します。このフラグを無効にすると、PackageManager はインストール中に .so ファイルを APK からファイル システムにコピーできなくなります。この方法で、アプリのアップデートのサイズを小さくできます。

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

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

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

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

詳しくは、複数の APK のビルド複数の APK のサポートをご覧ください。