アプリのサイズ最適化#
Android App Bundle を使用してアプリをアップロードする#
Google Play に公開する際にアプリのサイズを即座に削減する最も簡単な方法は、アプリをAndroid APP Bundleとして公開することです。これは、アプリのすべてのコンパイル済みコードとリソースを含む新しいアップロード形式であり、APK の生成と署名は Google Play ストアで行われます。
Google Play の新しいアプリ提供モデルは「Dynamic Delivery」と呼ばれ、このメカニズムはあなたの App Bundle を使用して、各ユーザーのデバイス構成に基づいて最適化された APK を生成して提供します。これにより、ユーザーはアプリを実行するために必要なコードとリソースのみをダウンロードすれば済みます。異なるデバイスをサポートするために複数の APK を再コンパイル、署名、管理する必要がなくなり、ユーザーはより小さく、最適化されたダウンロードファイルを得ることができます。
なお、Google Play は App Bundle を使用して公開されたアプリに対して 150MB を超えない圧縮ダウンロードサイズ制限を強制しているため、可能な限りアプリのダウンロードサイズを小さくするために、このページで紹介するガイドラインに従うことをお勧めします。
署名された APK を Google Play にアップロードして公開するアプリの圧縮ダウンロードサイズ制限は100MB を超えないです。
APK の構造を理解する#
アプリのサイズを削減する方法を議論する前に、アプリ APK の構造を理解することが役立ちます。APK ファイルは、アプリを構成するすべてのファイルを含む 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 つは、含まれるリソースの数とサイズを減らすことです。具体的には、アプリがもはや使用していないリソースを削除し、画像ファイルをスケーラブルな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 { // 他の設定 buildTypes
{
release
{
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
shrinkResources
を使用するには、コード圧縮機能を有効にする必要があります。コンパイル中に、最初にProGuardが未使用のコードを削除しますが、未使用のリソースは保持されます。その後、Gradle が未使用のリソースを削除します。
ProGuard や Android Studio が APK サイズを小さくするための他の方法について詳しくは、コードとリソースの圧縮を参照してください。
Android Gradle Plugin 0.7 以降では、アプリがサポートする構成を宣言できます。Gradle はresConfig
およびresConfigs
スタイルとdefaultConfig
オプションを使用して、これらの情報をコンパイルシステムに渡します。その後、コンパイルシステムは、サポートされていない構成からのリソースが APK に表示されるのを防ぎ、APK のサイズを小さくします。この機能の詳細については、未使用の代替リソースを削除するを参照してください。
ライブラリ内のリソース使用を最小限に抑える#
Android アプリを開発する際、アプリの使いやすさや多機能性を向上させるために外部ライブラリを使用することがよくあります。たとえば、Android サポートライブラリを参照して古いデバイスでのユーザー体験を向上させたり、Google Play サービスを使用してアプリ内のテキストの自動翻訳を取得したりできます。
ライブラリがサーバーやデスクトップデバイス向けに設計されている場合、アプリに必要のない多くのオブジェクトやメソッドが含まれている可能性があります。アプリに必要なライブラリ部分のみを含めるには、ライブラリのファイルを編集することができます(ライブラリを変更することが許可されている場合)。また、アプリに特定の機能を追加するために、モバイルデバイスに適した他のライブラリを使用することもできます。
注意:ProGuardは、ライブラリのインポートに伴う不要なコードをクリーンアップできますが、ライブラリの大規模な内部依存関係を削除することはできません。
特定の密度のみをサポートする#
Android は非常に幅広いデバイス(さまざまな画面密度を含む)をサポートしています。Android 4.4(API レベル 19)以降、フレームワークはさまざまな密度をサポートしています:ldpi
、mdpi
、tvdpi
、hdpi
、xhdpi
、xxhdpi
、およびxxxhdpi
。Android はこれらすべての密度をサポートしていますが、ラスター化リソースを各密度にエクスポートする必要はありません。
特定の密度のデバイスを持つユーザーが少数であることがわかっている場合は、これらの密度をアプリにバンドルする必要があるかどうかを検討してください。特定の画面密度用のリソースを追加しない場合、Android は他の画面密度用に設計された既存のリソースを自動的に拡大または縮小します。
アプリが拡大縮小された画像のみを必要とする場合は、drawable-nodpi/
内に画像の単一のバリアントを使用することで、さらに多くのスペースを節約できます。各アプリには少なくとも 1 つのxxhdpi
画像バリアントを含めることをお勧めします。
画面密度の詳細については、画面サイズと密度を参照してください。
Drawable オブジェクトを使用する#
特定の画像は静的な画像リソースを必要としません。フレームワークは、実行時に画像を動的に描画することができます。Drawableオブジェクト(XML では<shape>
)は、APK 内で少量のスペースを占有します。さらに、XML Drawableオブジェクトは、Material Design ガイドラインに準拠した単色画像を生成します。
リソースの再利用#
画像のバリアントに対して個別のリソースを追加することができます。たとえば、同じ画像の色調調整、影設定、または回転されたバージョンです。ただし、同じリソースセットを再利用し、実行時に必要に応じてカスタマイズすることをお勧めします。
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 ファイルを増加させる可能性があります。このような事態を避けるために、Gradle 内で PNG ファイルに対してこのプロセスを無効にするcruncherEnabled
マークを使用できます:aaptOptions { cruncherEnabled = 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 と比較してより良い圧縮効果を提供します。
Android Studio を使用して、既存の BMP、JPG、PNG、または静的 GIF 画像を WebP 形式に変換できます。詳細については、Android Studio を使用して WebP 画像を作成するを参照してください。
注意:Google Play は、ランチャーアイコンが PNG 形式である場合にのみ APK を受け入れます。
ベクターグラフィックスを使用する#
ベクターグラフィックスを使用して、解像度に依存しないアイコンやその他のスケーラブルなメディアを作成できます。これらのグラフィックスを使用すると、APK が占有するスペースを大幅に削減できます。ベクター画像は、Android でVectorDrawableオブジェクトとして表されます。VectorDrawableオブジェクトを使用すると、100 バイトのファイルから画面サイズに一致する鮮明な画像を生成できます。
ただし、システムが各VectorDrawableオブジェクトをレンダリングするには多くの時間がかかり、大きな画像は画面に表示されるまでにさらに長い時間がかかります。そのため、小さな画像を表示する場合にのみこれらのベクターグラフィックスを使用することを検討してください。
VectorDrawableオブジェクトの使用に関する詳細は、Drawable リソースの使用を参照してください。
アニメーション画像にベクターグラフィックスを使用する
AnimationDrawableを使用してフレームごとのアニメーションを作成しないでください。なぜなら、アニメーションの各フレームに対して個別のビットマップファイルを追加する必要があり、これにより APK のサイズが大幅に増加するからです。
代わりに、AnimatedVectorDrawableCompatを使用してアニメーションベクター Drawable リソースを作成してください。
ネイティブおよび Java コードの削減#
アプリ内の Java およびネイティブコードライブラリのサイズを小さくするために、さまざまな方法を使用できます。
- 不要な生成コードを削除する
自動生成されたコードが占めるスペースを理解していることを確認してください。たとえば、多くのプロトコルバッファツールは過剰なメソッドやクラスを生成し、アプリのサイズを 1 倍または 2 倍に増加させる可能性があります。
- 列挙型の使用を避ける
単一の列挙型は、アプリのclasses.dex
ファイルを約 1.0〜1.4KB 増加させます。これらの増加したサイズは急速に蓄積し、複雑なシステムや共有ライブラリを生成します。可能であれば、@IntDef
注釈を使用し、ProGuardを使用して列挙型を削除し、整数に変換することを検討してください。この型変換は、列挙型のさまざまな安全性の利点を保持します。
- ネイティブバイナリファイルのサイズを小さくする
アプリがネイティブコードと Android NDK を使用している場合、コードを最適化することでリリース版アプリのサイズを小さくすることもできます。デバッグシンボルを削除し、ネイティブライブラリを抽出しないことは、非常に実用的な技術です。
- デバッグシンボルを削除する
アプリが開発中であり、デバッグが必要な場合、デバッグシンボルを使用するのは非常に適切です。Android NDK に付属する **arm-eabi-strip
** ツールを使用して、ネイティブライブラリから不要なデバッグシンボルを削除できます。その後、リリース版をコンパイルできます。
- ネイティブライブラリの解凍を避ける
アプリのリリース版をコンパイルする際、アプリマニフェストの要素内で **android:extractNativeLibs="false"
を設定することで、APK 内に未圧縮の.so
** ファイルをパッケージ化できます。このマークを無効にすると、PackageManagerがインストール中に.so
ファイルを APK からファイルシステムにコピーするのを防ぎ、アプリの更新を小さくする追加の利点があります。
複数のスリム APK を維持する#
APK には、ユーザーがダウンロードするが決して使用しないコンテンツが含まれている可能性があります。たとえば、他の言語や画面密度に対するリソースです。ユーザーに最小のダウンロードファイルを提供するために、アプリをAndroid App Bundleを使用して Google Play にアップロードする必要があります。App Bundle をアップロードすることで、Google Play は各ユーザーのデバイス構成に基づいて最適化された APK を生成して提供できるため、ユーザーはアプリを実行するために必要なコードとリソースのみをダウンロードすれば済みます。異なるデバイスをサポートするために複数の APK を再コンパイル、署名、管理する必要がなくなり、ユーザーはより小さく、最適化されたダウンロードファイルを得ることができます。
アプリを Google Play に公開する予定がない場合は、アプリを複数の APK に分割し、画面サイズや GPU テクスチャサポートなどの要因に基づいて区別できます。
ユーザーがアプリをダウンロードすると、デバイスはデバイスの機能や設定に基づいて正しい APK を受け取ります。これにより、デバイスはデバイスに存在しない機能用のリソースを受け取ることがありません。たとえば、ユーザーがhdpi
デバイスを持っている場合、より高い密度のディスプレイを持つデバイス用に提供されるxxxhdpi
リソースは必要ありません。
詳細については、APK スプリットの構成および複数の APK を維持するを参照してください。
ネイティブサイズを減らす#
android {
...
defaultConfig {
...
// defaultConfigノードの下にexternalNativeBuildブロックを構成
externalNativeBuild {
// ndk-buildの代わりにndkBuild {}を使用
cmake { // cmakeのコンパイルオプションを指定
// Cコンパイラのオプションフラグを設定します。
cFlags "-fvisibility=hidden -ffunction-sections -fdata-sections"
// C++コンパイラのオプションフラグを設定します。
cppFlags "-fvisibility=hidden -ffunction-sections -fdata-sections -std=c++11"
arguments "-DANDROID_TOOLCHAIN=gcc"// gccコンパイルを設定、cmakeはデフォルトでclangを使用
}
}
}
buildTypes {...}
}