APK Analyzer でのビルドの分析

Android Studio に付属している APK Analyzer では、ビルドプロセスの完了後に APK または Android App Bundle の構成をすぐに分析できます。APK Analyzer を使用すると、DEX ファイルやアプリ内のリソースに関する問題のデバッグにかかる時間を短縮できるほか、APK のサイズを縮小することもできます。APK Analyzer は、コマンドラインから apkanalyzer で実行することもできます。

APK Analyzer では以下を行うことができます。

  • アプリ内のファイル(DEX ファイルや Android リソース ファイルなど)の絶対サイズと相対サイズを表示する。
  • DEX ファイルの構成を把握する。
  • アプリ内のファイル(AndroidManifest.xml ファイルなど)の最終版をすぐに表示する。
  • 2 つの APK または App Bundle を対照比較する。

プロジェクトが開いているときに APK Analyzer にアクセスする方法には次の 3 つがあります。

  • APK または App Bundle を Android Studio の [Editor] ウィンドウにドラッグします。
  • [Project] ウィンドウを [Project] 表示に切り替えて、デフォルトの build/output/apks/ ディレクトリにある APK をダブルクリックします。
  • メニューバーから [Build] > [Analyze APK] を選択し、APK または App Bundle を選択します。

ファイルとサイズに関する情報の表示

APK は ZIP ファイル形式のファイルです。APK Analyzer は、各ファイルまたはフォルダを、フォルダへの移動に使用できる拡張機能を備えたエンティティとして表示します。エンティティの階層は、APK ファイル内でのファイルとフォルダの構造を反映したものです。

図 1 に示すように、APK Analyzer には、各エンティティの未加工のファイルサイズとダウンロード ファイルサイズの値が表示されます。[Raw File Size] にはディスク上でのエンティティの解凍サイズが表示されるのに対し、[Download Size] には Google Play から配信される際のエンティティの推定圧縮サイズが表示されます。[% of Total Download Size] は、APK の総ダウンロード サイズにおいてエンティティが占める割合を示します。

図 1. APK Analyzer に表示されるファイルサイズ

AndroidManifest.xml の表示

プロジェクトに複数の AndroidManifest.xml ファイル(プロダクト フレーバー用など)が含まれている場合、または、マニフェスト ファイルを提供するライブラリが含まれている場合、それらがアプリ内の 1 つのファイルに統合されます。このマニフェスト ファイルは、通常は APK または App Bundle 内のバイナリ ファイルですが、APK Analyzer で選択されると、このエンティティが XML 形式で再構築されて表示されます。このビューアを使用すると、ビルド中にアプリに対して行われた変更をすべて把握できます。たとえば、アプリが依存するライブラリの AndroidManifest.xml ファイルが最終的な AndroidManifest.xml ファイルにどのように統合されたかを確認できます。

また、このビューアには lint 機能がいくつか搭載されており、右上隅に警告やエラーが表示されます。図 2 に、選択されたマニフェスト ファイルにエラーがあることを示します。

図 2. 選択されたマニフェスト ファイルに対するエラーアイコンが右端に表示される

DEX ファイルの表示

APK Analyzer の DEX ファイル ビューアを使用すると、アプリの DEX ファイルに関する基本情報に直接アクセスできます。ビューア内にクラス数、パッケージ数、総参照数、宣言数が表示され、これらを基にして、multidex を使用すべきかどうかの判断や、依存関係を削除して 64K の DEX の制限を超えないようにする方法を決定できます。

図 3 に、64K の DEX の制限を下回る中規模のアプリを示します。DEX ファイル内の各パッケージ、クラス、メソッドの数が、[Defined Methods] 列と [Referenced Methods] 列に表示されます。[Referenced Methods] 列は、DEX ファイルによって参照されるメソッドの総数です。これには通常、コード、依存関係ライブラリで定義されたメソッドと、コードで使用される標準の Java および Android パッケージで定義されたメソッドが含まれます。これらのメソッドは、各 DEX ファイルの 64K のメソッドの制限にカウントされます。[Defined Methods] 列は、DEX ファイルのいずれかで定義されたメソッドのみの数です。つまりこの数は、[Referenced Methods] の部分集合です。依存関係をアプリにパッケージ化すると、依存関係で定義されたメソッドが両方のメソッド数に加算されます。また、軽量化やコード圧縮により、ソースコードのコンパイル後に DEX ファイルの内容が大幅に変更されることがあります。

図 3. 中くらいのサイズのアプリ

DEX ファイル ツリービューのフィルタ

APK Analyzer で [Class] リストのすぐ上にあるフィルタを、選択した DEX ファイルの内容の表示に適用できます。

図 4. BuildConfig のフィールドとメソッドを表示するように設定した DEX フィルタ

フィルタを使用してクラス内のすべてのメソッドとフィールドを表示する手順は次のとおりです。

  1. [File] リストで classes.dex ファイルを選択します。
  2. [Class] リストで、特定のクラスに移動して選択します。
  3. 選択したクラスを展開します。
  4. フィールドを表示アイコン で、クラス フィールドの表示と非表示を切り替えます。
  5. メソッドを表示アイコン で、クラスメソッドの表示と非表示を切り替えます。
  6. 参照されているメソッドやフィールドをすべて表示アイコン で、参照されているパッケージ、クラス、メソッド、フィールドの表示と非表示を切り替えます。ツリービュー内に斜体で示されるノードは、選択した DEX ファイルで定義されていない参照です。

    ある DEX ファイルから、別のファイルで定義されているメソッドとフィールドを参照できます。たとえば System.out.println() は、Android フレームワークの println() への参照です。

ProGuard マッピングの読み込み

フィルタ アイコンの横には ProGuard マッピング アイコンがあります。これらのアイコンは、名前の難読化の解除(mapping.txt)、削除されたノードの表示(usage.txt)、削除できないノードの指定(seeds.txt)など、DEX ビューアに機能を追加する一連の ProGuard マッピング ファイルを読み込むまでグレー表示されています。インポートする ProGuard マッピング ファイルは、コード圧縮を有効にして DEX ファイルを生成したビルドからのものである必要があります。詳細については、アプリの圧縮、難読化、最適化をご覧ください。

図 5. ProGuard マッピングの読み込み

ProGuard マッピング ファイルを読み込む手順は次のとおりです。

  1. [Load Proguard mappings] をクリックします。
  2. マッピング ファイルが格納されているプロジェクト フォルダに移動し、すべてのファイル、ファイルの組み合わせ、またはファイルが格納されているフォルダを読み込みます。

    通常、マッピング ファイルは project/app/build/outputs/mappings/release/ にあります。ファイル選択ツールによりこのプロジェクト構造が検出されると、デフォルトで release フォルダが表示されます。ファイル選択ツールは、まず mapping.txtseeds.txtusage.txt と完全に一致する名前のファイルをチェックします。次に、mappingusageseeds のようなテキストを含む名前や、.txt で終わる名前のファイルをチェックします。たとえば、release-seeds-1.10.15.txt は一致します。

以下は、各マッピング ファイルの説明です。

  • seeds.txt: ProGuard の設定により圧縮時に削除されないノードが太字で表示されます。
  • mapping.txt: 名前の難読化の解除アイコン が有効になり、R8 によって難読化されたノードの元の名前を復元できるようになります。たとえば、abc のように難読化されたノード名を MyClassMainActivitymyMethod() に復元できます。
  • usage.txt: 削除されたノードの表示アイコン が有効になり、圧縮時に R8 によって削除されたクラス、メソッド、フィールドを表示できるようになります。復元されたノードは取り消し線付きで表示されます。

    R8 を使用してコードの難読化や圧縮を行う方法について詳しくは、アプリの圧縮、難読化、最適化をご覧ください。

バイトコードの表示、使用箇所の検索、保持ルールの生成

[Class] リストに表示されるノードのコンテキスト メニューには、下記のオプションがあります。このメニューからは、バイトコードの表示、使用箇所の検索、ProGuard ルール(選択したノードにコピーと貼り付けが可能)を表示するダイアログの表示が可能です。[Class] リスト表示で任意のノードを右クリックすると、そのコンテキスト メニューを表示できます。

Show Bytecode: 選択したクラス、メソッド、フィールドを逆コンパイルし、ダイアログに次のように(Java コードではなく)、smali バイトコード表現で表示します。

図 6: init メソッドの DEX バイトコード

Find Usages: 選択したクラスまたはメソッドが、他のどの部分の DEX コードから参照されているかを表示します(図 7)。seeds.txt を読み込んだ際に太字で表示されるノードは、ProGuard の設定により圧縮時に削除されないことを示します。

図 7. MyClass への参照

Generate Proguard keep rule: ProGuard ルールを表示して、プロジェクトの ProGuard 構成ファイルにコピー、貼り付けができます。そうすることで、コード圧縮フェーズ中に特定のパッケージ、クラス、メソッド、またはフィールドが削除されないよう保護できます(図 8)。詳しくは、保持するコードのカスタマイズをご覧ください。

図 8. ダイアログから ProGuard 構成ファイルにコピーできる ProGuard ルール

コードおよびリソース エンティティの表示

アプリ内の最終エンティティはさまざまなビルドタスクによって変更されます。たとえば、ProGuard 圧縮ルールによって最終的なコードが変更されることがあります。また、画像リソースがプロダクト フレーバーのリソースによって上書きされることもあります。 APK Analyzer を使用すると、ファイルの最終版を簡単に表示できます。エンティティをクリックすると、図 9 に示すように、テキストまたは画像のエンティティのプレビューが表示されます。

図 9. 最終的な画像リソースのプレビュー

APK Analyzer でさまざまなテキスト ファイルやバイナリ ファイルを表示することもできます。たとえば、resources.arsc エンティティ ビューアを使用すると、文字列リソースの言語翻訳など、その設定固有の値を表示できます。図 10 に、各文字列リソースの翻訳を示します。

図 10. 翻訳された文字列リソースのプレビュー

ファイルの比較

APK Analyzer では、2 つの APK ファイルまたは App Bundle ファイル内のエンティティのサイズを比較できます。この機能は、以前のリリースに比べてアプリのサイズが大きくなった理由を把握する必要がある場合に便利です。更新されたアプリを公開する前に、以下の操作を行います。

  1. 公開しようとしているアプリのバージョンを APK Analyzer に読み込みます。
  2. APK Analyzer の右上にある [Compare With] をクリックします。
  3. 選択ダイアログで、ユーザーに前回公開したアーティファクトを選択して [OK] をクリックします。

    図 11 のようなダイアログが表示され、アップデートがユーザーに与える影響を評価できます。

図 11 に、特定のアプリのデバッグビルドとリリースビルドの違いを示します。これらのビルドタイプ間で異なるビルド オプションが使用されていると、基盤となるエンティティが別々に変更されます。

図 11. デバッグ APK とリリース APK の違い