ライブラリ作成者は、エンドユーザーに質の高いエクスペリエンスを提供しながら、アプリ デベロッパーがライブラリをアプリに簡単に組み込むことができるようにする必要があります。ライブラリが追加の設定なしで Android の最適化と互換性があることを確認するか、ライブラリが Android での使用に適さない可能性があることを明記する必要があります。
このドキュメントは公開ライブラリのデベロッパーを対象としていますが、大規模なモジュラー化されたアプリの内部ライブラリ モジュールのデベロッパーにも役立つ場合があります。
アプリのデベロッパーで、Android アプリの最適化について詳しくは、アプリの最適化を有効にするをご覧ください。使用するライブラリの適切性については、ライブラリを賢く選択するをご覧ください。
リフレクションではなく codegen を使用する
可能であれば、リフレクションではなくコード生成(codegen)を使用します。Codegen とリフレクションはどちらも、プログラミング時にボイラープレート コードを回避するための一般的なアプローチですが、Codegen は R8 などのアプリ最適化ツールとの互換性が高くなります。
- codegen では、ビルドプロセス中にコードが分析され、変更されます。コンパイル時以降に大きな変更がないため、最終的に必要なコードと安全に削除できるコードをオプティマイザーが把握できます。
- リフレクションでは、コードが実行時に分析され、操作されます。コードは実行されるまで完全に確定しないため、どのコードを安全に削除できるかをオプティマイザーが把握できません。実行時にリフレクションによって動的に使用されるコードが削除され、ユーザーのアプリがクラッシュする可能性があります。
最新のライブラリの多くは、反射ではなく codegen を使用しています。Room、Dagger2 などで使用される共通のエントリポイントについては、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 がルールを正しくバンドルしていることを確認します。
AAR ライブラリのビルドを最適化する(上級者向け)
通常、ライブラリのビルド時に可能な最適化は非常に限られているため、ライブラリのビルドを直接最適化しないことをおすすめします。R8 がライブラリのすべてのメソッドの使用方法と渡されるパラメータを把握できるのは、ライブラリがアプリの一部として含まれているアプリビルド時のみです。ライブラリ デベロッパーは、ライブラリを最適化する前に、ライブラリとアプリのビルド時の両方で、最適化の複数のステージについて検討し、動作を維持する必要があります。
それでもビルド時にライブラリを最適化したい場合は、Android Gradle プラグインがサポートしています。
Kotlin
android { buildTypes { release { isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } configureEach { consumerProguardFiles("consumer-rules.pro") } } }
Groovy
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } configureEach { consumerProguardFiles "consumer-rules.pro" } } }
proguardFiles
の動作は consumerProguardFiles
とは大きく異なります。
proguardFiles
はビルド時に使用され、多くの場合getDefaultProguardFile("proguard-android-optimize.txt")
とともに、ライブラリのビルド中に保持するライブラリの部分を定義します。少なくとも、これは公開 API です。- 一方、
consumerProguardFiles
はライブラリにパッケージ化され、ライブラリを使用するアプリのビルド時に行われる最適化に影響します。
たとえば、ライブラリでリフレクションを使用して内部クラスを構築する場合は、proguardFiles
と consumerProguardFiles
の両方で保持ルールを定義する必要があります。
ライブラリのビルドで -repackageclasses
を使用する場合は、ライブラリのパッケージの内部にあるサブパッケージにクラスを再パッケージ化します。(たとえば、-repackageclasses 'internal'
ではなく -repackageclasses 'com.example.mylibrary.internal'
を使用しているなど)。
さまざまな R8 バージョンをサポートする(上級)
特定のバージョンの R8 をターゲットにするようにルールを調整できます。これにより、新しい R8 バージョンを使用するプロジェクトでライブラリを最適に動作させながら、古い R8 バージョンのプロジェクトで既存のルールを引き続き使用できます。
ターゲット R8 ルールを指定するには、AAR の classes.jar
内の META-INF/com.android.tools
ディレクトリまたは JAR の META-INF/com.android.tools
ディレクトリにルールを含める必要があります。
In an AAR library:
proguard.txt (legacy location, the file name must be "proguard.txt")
classes.jar
└── META-INF
└── com.android.tools (location of targeted R8 rules)
├── r8-from-<X>-upto-<Y>/<R8-rule-files>
└── ... (more directories with the same name format)
In a JAR library:
META-INF
├── proguard/<ProGuard-rule-files> (legacy location)
└── com.android.tools (location of targeted R8 rules)
├── r8-from-<X>-upto-<Y>/<R8-rule-files>
└── ... (more directories with the same name format)
META-INF/com.android.tools
ディレクトリには、ルールが記述されている R8 バージョンを示す r8-from-<X>-upto-<Y>
形式の名前を持つサブディレクトリを複数配置できます。各サブディレクトリには、任意のファイル名と拡張子を持つ R8 ルールを含む 1 つ以上のファイルを配置できます。
-from-<X>
部分と -upto-<Y>
部分は省略可能です。<Y>
バージョンは排他的です。バージョン範囲は通常連続していますが、重複する場合もあります。
たとえば、r8
、r8-upto-8.0.0
、r8-from-8.0.0-upto-8.2.0
、r8-from-8.2.0
は、ターゲットとなる R8 ルールのセットを示すディレクトリ名です。r8
ディレクトリのルールは、どの R8 バージョンでも使用できます。r8-from-8.0.0-upto-8.2.0
ディレクトリのルールは、バージョン 8.0.0 からバージョン 8.2.0 まで(8.2.0 は含まない)の R8 で使用できます。
Android Gradle プラグインは、その情報を使用して、現在の R8 バージョンで使用できるすべてのルールを選択します。ライブラリでターゲット R8 ルールが指定されていない場合、Android Gradle プラグインは以前の場所(AAR の場合は proguard.txt
、JAR の場合は META-INF/proguard/<ProGuard-rule-files>
)からルールを選択します。