ライブラリ作成者向けの最適化

ライブラリ作成者は、エンドユーザーに質の高いエクスペリエンスを提供しながら、アプリ デベロッパーがライブラリをアプリに簡単に組み込むことができるようにする必要があります。ライブラリが追加の設定なしで Android の最適化と互換性があることを確認するか、ライブラリが Android での使用に適さない可能性があることを明記する必要があります。

このドキュメントは公開ライブラリのデベロッパーを対象としていますが、大規模なモジュラー化されたアプリの内部ライブラリ モジュールのデベロッパーにも役立つ場合があります。

アプリのデベロッパーで、Android アプリの最適化について詳しくは、アプリの最適化を有効にするをご覧ください。使用するライブラリの適切性については、ライブラリを賢く選択するをご覧ください。

リフレクションではなく codegen を使用する

可能であれば、リフレクションではなくコード生成(codegenを使用します。Codegen とリフレクションはどちらも、プログラミング時にボイラープレート コードを回避するための一般的なアプローチですが、Codegen は R8 などのアプリ最適化ツールとの互換性が高くなります。

  • codegen では、ビルドプロセス中にコードが分析され、変更されます。コンパイル時以降に大きな変更がないため、最終的に必要なコードと安全に削除できるコードをオプティマイザーが把握できます。
  • リフレクションでは、コードが実行時に分析され、操作されます。コードは実行されるまで完全に確定しないため、どのコードを安全に削除できるかをオプティマイザーが把握できません。実行時にリフレクションによって動的に使用されるコードが削除され、ユーザーのアプリがクラッシュする可能性があります。

最新のライブラリの多くは、反射ではなく codegen を使用しています。RoomDagger2 などで使用される共通のエントリポイントについては、KSP をご覧ください。

リフレクションが許可される場合

リフレクションを使用する必要がある場合は、次のいずれかにのみリフレクションする必要があります。

  • 特定のターゲット タイプ(特定のインターフェース実装者またはサブクラス)
  • 特定のランタイム アノテーションを使用するコード

このようにリフレクションを使用すると、ランタイム コストを抑え、ターゲット コンシューマ保持ルールを記述できます。

この特定のターゲット型の反射は、Android フレームワーク(アクティビティ、ビュー、ドローアブルのインフレート時など)と AndroidX ライブラリ(WorkManager ListenableWorkers や RoomDatabase の作成時など)の両方で見られるパターンです。一方、Gson のオープンエンドのリフレクションは、Android アプリでの使用には適していません

コンシューマの保持ルールを作成する

ライブラリは、「コンシューマ」保持ルールをパッケージ化する必要があります。このルールは、アプリ保持ルールと同じ形式を使用します。これらのルールはライブラリ アーティファクト(AAR または JAR)にバンドルされ、ライブラリが使用されるときに Android アプリの最適化中に自動的に使用されます。

AAR ライブラリ

AAR ライブラリの使用ルールを追加するには、Android ライブラリ モジュールのビルド スクリプトで consumerProguardFiles オプションを使用します。詳細については、ライブラリ モジュールの作成に関するガイダンスをご覧ください。

Kotlin

android {
    defaultConfig {
        consumerProguardFiles("consumer-proguard-rules.pro")
    }
    ...
}

Groovy

android {
    defaultConfig {
        consumerProguardFiles 'consumer-proguard-rules.pro'
    }
    ...
}

JAR ライブラリ

JAR として出荷される Kotlin/Java ライブラリにルールをバンドルするには、ルールファイルを任意のファイル名で最終的な JAR の META-INF/proguard/ ディレクトリに配置します。たとえば、コードが <libraryroot>/src/main/kotlin にある場合は、コンシューマ ルール ファイルを <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro に配置します。ルールは、出力 JAR の適切な場所にバンドルされます。

ルールが META-INF/proguard ディレクトリにあることを確認して、最終的な JAR がルールを正しくバンドルしていることを確認します。

さまざまな圧縮ツールをサポートする(上級)

特定の圧縮ツール(R8 または ProGuard)や特定の圧縮ツールのバージョンをターゲットにしてルールを調整できます。これにより、新しい圧縮ツールのバージョンを使用するプロジェクトでライブラリを最適に動作させながら、古い圧縮ツールのバージョンを使用するプロジェクトで既存のルールを引き続き使用できます。

ターゲット 圧縮ルールを指定するには、次のように AAR または JAR ライブラリ内の特定の場所に含める必要があります。

In an AAR library:
    consumer-proguard-rules.pro (legacy location)
    classes.jar
    └── META-INF
        └── com.android.tools (targeted shrink rules location)
            ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
            └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

In a JAR library:
    META-INF
    ├── proguard/<ProGuard-rules-file> (legacy location)
    └── com.android.tools (targeted shrink rules location)
        ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
        └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

つまり、ターゲット 圧縮ルールは、JAR の META-INF/com.android.tools ディレクトリまたは AAR の classes.jar 内の META-INF/com.android.tools ディレクトリに保存されます。

このディレクトリには、r8-from-<X>-upto-<Y> または proguard-from-<X>-upto-<Y> の形式の名前を持つ複数のディレクトリを含めることができます。これは、ディレクトリ内のルールがどの圧縮ツールのどのバージョン用に記述されているかを示します。-from-<X> と -upto-<Y> の部分は省略可能です。<Y> バージョンは排他的であり、バージョン範囲は連続している必要があります。

たとえば、r8-upto-8.0.0, r8-from-8.0.0-upto-8.2.0r8-from-8.2.0 は、ターゲット サイズ変更ルールの有効なセットを形成します。r8-from-8.0.0-upto-8.2.0 ディレクトリのルールは、バージョン 8.0.0 からバージョン 8.2.0 までの R8 で使用されます。

Android Gradle プラグインは、この情報に基づいて、一致する R8 ディレクトリからルールを選択します。ライブラリでターゲット 圧縮ルールが指定されていない場合、Android Gradle プラグインは以前の場所(AAR の場合は proguard.txt、JAR の場合は META-INF/proguard/<ProGuard-rules-file>)からルールを選択します。