多くの場合、ユーザーは大容量のアプリのダウンロードを避けます。特に新興市場では、接続が不安定な 2G、3G ネットワークや、従量課金制のプランを利用するユーザーが多いため、この傾向が顕著です。このページでは、アプリのダウンロード サイズを減らすことで、より多くのユーザーにアプリをダウンロードしてもらう方法を説明します。
Android App Bundle を使用してアプリをアップロードする
Google Play にアプリを公開するときにサイズをすぐに削減するには、アプリを Android App Bundle としてアップロードするのが最も簡単です。この新しいアップロード形式には、アプリのコンパイル済みコードとリソースがすべて含まれる一方で、APK の生成と署名は Google Play で行います。
Google Play の新しいアプリ配信モデルが、App Bundle を使用して、個々のユーザーのデバイス設定に合わせて最適化された APK を生成、配信するので、ユーザーは、アプリの実行に必要なコードとリソースをダウンロードするだけで済みます。これにより、デベロッパー側では、多様なデバイスをサポートするために複数の APK をビルド、署名、管理する必要がなくなり、ユーザー側では、サイズの小さい最適化された APK をダウンロードできるようになります。
Google Play では、App Bundle を使用して公開されているアプリに対して 150 MB 以下の圧縮ダウンロード サイズ制限が適用されるため、アプリのダウンロード サイズをできるだけ小さくするために、ここに記載されているガイドラインを適用することをおすすめします。
署名済み APK をアップロードして Google Play に公開するアプリの場合、圧縮ダウンロード サイズは 100 MB 以下に制限されます。
APK の構造を理解する
アプリのサイズを縮小する方法を学ぶ前に、アプリの APK の構造を理解しておくことをおすすめします。APK ファイルは、アプリを構成するすべてのファイルを含む ZIP アーカイブからなります。この ZIP には、Java クラスファイル、リソース ファイル、コンパイル済みリソースを含むファイルなどが含まれます。
APK のディレクトリ構成は次のとおりです。
META-INF/
:CERT.SF
、CERT.RSA
の署名ファイル、MANIFEST.MF
マニフェスト ファイルが含まれます。assets/
: アプリがAssetManager
オブジェクトを使用して取得できる、アプリのアセットが含まれます。-
res/
:resources.arsc
にコンパイルされていないリソースが含まれます。 lib/
: プロセッサのソフトウェア レイヤに固有のコンパイル済みコードが含まれます。このディレクトリには、プラットフォーム タイプごとのサブディレクトリ(armeabi
、armeabi-v7a
、arm64-v8a
、x86
、x86_64
、mips
など)が含まれます。
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 によってリソースを自動的に削除できます。
Groovy
android { // Other settings buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
Kotlin
android { // Other settings buildTypes { getByName("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 は、resConfig
、resConfigs
のフレーバーと defaultConfig
オプションを使用してこの情報をビルドシステムに渡します。ビルドシステムは、サポートされない他の設定のリソースが APK に表示されることを防ぐため、これによって APK のサイズが縮小されます。この機能について詳しくは、未使用の代替リソースの削除をご覧ください。
ライブラリからのリソースの使用を最小限に抑える
通常 Android アプリを開発する場合は、外部のライブラリを使用してアプリのユーザビリティと汎用性を向上させます。たとえば、Android サポート ライブラリを参照して古いデバイスのユーザー エクスペリエンスを改善できます。また、Google Play 開発者サービスを使用してアプリ内のテキストを自動翻訳できます。
サーバーやデスクトップに対応するよう作成されたライブラリには、アプリに必要ないオブジェクトやメソッドが数多く含まれている可能性があります。ライセンスでライブラリの変更が許可されていれば、ライブラリのファイルを編集することで、アプリに必要なライブラリの部分のみを含めることができます。また、別のモバイル向けライブラリを使用して、アプリに特定の機能を追加することも可能です。
注: コード圧縮を使用すると、ライブラリの不要なコードを削除できます。ただし、ライブラリの大規模な内部依存関係は削除できません。
ネイティブ アニメーション画像のデコード
Android 12(API レベル 31)では、NDK ImageDecoder
API が拡張され、アニメーション GIF とアニメーション WebP のファイル形式を使用する画像から、すべてのフレームとタイミング データをデコードできるようになりました。この API が Android 11 で導入されたときは、これらの形式のアニメーションに含まれる最初の画像のみをデコードしていました。
サードパーティ ライブラリの代わりに ImageDecoder
を使用すると、さらに APK サイズを縮小できます。また、セキュリティとパフォーマンスに関連する今後のアップデートを利用できます。
API について詳しくは、API reference
と GitHub のサンプルをご覧ください。
特定の密度のみをサポートする
Android は非常に多くのデバイスをサポートし、さまざまな画面密度に対応しています。Android 4.4(API レベル 19)以降のフレームワークでは、さまざまな密度(ldpi
、mdpi
、tvdpi
、hdpi,
、xhdpi
、xxhdpi
、xxxhdpi
)をサポートしています。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 ファイルのサイズが大きくなることがあります。これを防ぐには、以下のようにisCrunchPngs
フラグを使用して PNG ファイルに対するこのプロセスを無効にします。
Groovy
buildTypes.all { isCrunchPngs = false }
Kotlin
buildTypes.all { isCrunchPngs = false }
PNG ファイルと JPEG ファイルを圧縮する
pngcrush、pngquant、zopflipng などのツールを使用すると、画質を損なわずに PNG ファイルのサイズを縮小できます。これらはすべて、画質を保ちながら PNG ファイルのサイズを縮小できるツールです。
pngcrush
ツールは特に効果的です。このツールは、PNG フィルタと zlib(Deflate)パラメータを順番に調べ、フィルタやパラメータを組み合わせて画像を圧縮し、圧縮後の出力が最も小さい設定を選択します。
JPEG ファイルを圧縮するには、packJPG、guetzli などのツールを使用できます。
WebP ファイル形式を使用する
Android 3.2(API レベル 13)以降を対象とする場合は、PNG ファイルや JPEG ファイルの代わりに、WebP ファイル形式を画像に使用することもできます。 WebP 形式には非可逆圧縮モード(JPEG の置き換え)と透過モード(PNG の置き換え)がありますが、圧縮率は JPEG や PNG より高くなります。
既存の BMP、JPG、PNG、静的 GIF 画像は、Android Studio を使用して WebP 形式に変換できます。詳しくは、Android Studio を使用した 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
ツールを使用して、不要なデバッグ シンボルをネイティブ ライブラリから削除できます。削除した後、リリースビルドをコンパイルできます。
ネイティブ ライブラリを抽出しない
アプリのリリース バージョンをビルドする場合は、useLegacyPackaging
をアプリの build.gradle
ファイルの false
に設定するようにして、圧縮されていない .so
ファイルを APK でパッケージ化します。このフラグを無効にすると、インストール時に PackageManager
が APK からファイル システムに .so
ファイルをコピーできなくなり、アプリの更新を小さくできるメリットもあります。
複数の小さい APK を維持する
APK には、追加の言語や画面密度ごとのリソースなど、ユーザーがダウンロードしても使用しないコンテンツが含まれることがあります。ユーザーのダウンロードを最小限に抑えるには、Android App Bundle を使用してアプリを Google Play にアップロードすることをおすすめします。App Bundle をアップロードすると、個々のユーザーのデバイス構成に合わせて最適化された APK が Google Play によって自動的に生成、配信されるため、ユーザーはアプリの実行に必要なコードとリソースをダウンロードするだけで済みます。これにより、デベロッパー側では、多様なデバイスをサポートするために複数の APK を生成、署名、管理する必要がなくなり、ユーザー側では、サイズの小さい最適化された APK をダウンロードできるようになります。
アプリを Google Play に公開しない場合は、画面サイズや GPU テクスチャのサポートなどの要因で区別された、複数の APK にアプリを分割できます。
ユーザーがアプリをダウンロードする場合は、デバイスに搭載されている機能や設定に基づいて適切な APK を受け取り、該当しない機能向けのアセットを受け取ることはありません。たとえば、ユーザーのデバイスが hdpi
の場合、より高密度のディスプレイを搭載したデバイス向けの xxxhdpi
リソースは必要ありません。
詳しくは、APK 分割の設定と複数の APK の維持をご覧ください。