Android Studio 3.0にアップデートして新しいプロジェクトを作成した後、build.gradle
ではcompile
の代わりにimplementation
の代わりにtestCompile
の代わりにtestImplementation
が新しい依存関係を追加する新しい方法があることに気付きました。
例:
implementation 'com.Android.support:appcompat-v7:25.0.0'
testImplementation 'junit:junit:4.12'
の代わりに
compile 'com.Android.support:appcompat-v7:25.0.0'
testCompile 'junit:junit:4.12'
それらの違いは何ですか?また何を使うべきですか?
tl; dr
ただ交換してください:
compile
とimplementation
推移性が必要ない場合)またはapi
(推移性が必要な場合)testCompile
とtestImplementation
debugCompile
とdebugImplementation
androidTestCompile
とandroidTestImplementation
compileOnly
はまだ有効です。提供されたものを置き換えてコンパイルしないために3.0で追加されました。 (provided
はGradleがそのユースケースの設定名を持っていなかった時に導入され、Mavenが提供したスコープに基づいて名前を付けました。)これはGradle 3.0に伴う重大な変更の1つです(GoogleはIO17 で発表しました)。
compile
の設定は 現在は非推奨です で、implementation
またはapi
に置き換えられます
Gradleドキュメント :から)
dependencies { api 'commons-httpclient:commons-httpclient:3.1' implementation 'org.Apache.commons:commons-lang3:3.5' }
api
設定に現れる依存関係は、ライブラリの消費者に推移的に公開され、そのため、消費者のコンパイルクラスパスに現れます。一方、
implementation
設定にある依存関係は、コンシューマには公開されないため、コンシューマのコンパイルクラスパスにリークすることはありません。これにはいくつかの利点があります。
- 依存関係がコンシューマのコンパイルクラスパスに漏れることはもうないので、誤って推移的な依存関係に依存することは決してありません。
- クラスパスサイズの縮小によるコンパイルの高速化
- 実装の依存関係が変わったときの再コンパイルの減少:コンシューマを再コンパイルする必要がない
- クリーンなパブリッシング:新しいmaven-publishプラグインと組み合わせて使用すると、Javaライブラリは、ライブラリに対してコンパイルするために必要なものと実行時にライブラリを使用するために必要なものを正確に区別するPOMファイルを生成しますライブラリ自体をコンパイルするために必要なものとライブラリに対してコンパイルするために必要なものを混在させる)。
コンパイル設定はまだ存在しますが、
api
とimplementation
設定が提供する保証を提供しないので使用しないでください。
注: アプリケーションモジュールでライブラリのみを使用している場合(一般的な場合)、違いはありません。
互いに依存するモジュールを含む複雑なプロジェクトがある場合、またはライブラリを作成している場合にのみ違いがわかります。
この答えは、プロジェクトのimplementation
、api
、およびcompile
の違いを示します。
3つのGradleモジュールを含むプロジェクトがあるとしましょう。
app
は依存関係としてmyandroidlibrary
を持っています。 myandroidlibrary
は依存関係としてmyjavalibrary
を持っています。
myjavalibrary
はMySecret
クラスを持っています
public class MySecret {
public static String getSecret() {
return "Money";
}
}
myandroidlibrary
はMyAndroidComponent
クラスの値を操作するMySecret
クラスを持ちます。
public class MyAndroidComponent {
private static String component = MySecret.getSecret();
public static String getComponent() {
return "My component: " + component;
}
}
最後に、app
はmyandroidlibrary
からの値にのみ関心があります。
TextView tvHelloWorld = findViewById(R.id.tv_hello_world);
tvHelloWorld.setText(MyAndroidComponent.getComponent());
それでは、依存関係について話しましょう...
app
は:myandroidlibrary
を消費する必要があるので、app
build.gradleではimplementation
を使用します。
(注:あなたもapi/compileを使うことができます。しかしその考えをちょっと待ってください。)
dependencies {
implementation project(':myandroidlibrary')
}
myandroidlibrary
build.gradleはどのように見えるべきですか?どの範囲を使うべきですか?
3つの選択肢があります。
dependencies {
// Option #1
implementation project(':myjavalibrary')
// Option #2
compile project(':myjavalibrary')
// Option #3
api project(':myjavalibrary')
}
それらの違いは何ですか?また何を使うべきですか?
compile
またはapi
を使用している場合私たちのAndroidアプリケーションはmyandroidcomponent
クラスであるMySecret
依存関係にアクセスできるようになりました。
TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());
実装(オプション#1)
implementation
設定を使用している場合、MySecret
は公開されません。
TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can NOT access MySecret
textView.setText(MySecret.getSecret()); // Won't even compile
それで、あなたはどの構成を選ぶべきですか?それは本当にあなたの要求次第です。
依存関係を公開したい場合 api
またはcompile
を使用してください。
依存関係を公開したくない場合は (内部モジュールを隠して)それからimplementation
を使用してください。
注意:
これは単なるGradle構成の要点です。 表49.1を参照してください。 Javaライブラリプラグイン - 依存関係の宣言に使用される設定 より詳細な説明。
この回答のサンプルプロジェクトは https://github.com/aldoKelvianto/ImplementationVsCompile にあります。
Compile
設定は推奨されなくなったので、implementation
またはapi
に置き換えてください。
このドキュメントは https://docs.gradle.org/current/userguide/Java_library_plugin.html#sec:Java_library_separation にあります。
短い部分は
標準のJavaプラグインとJavaライブラリプラグインの主な違いは、後者が消費者に公開されるAPIの概念を導入することです。ライブラリは、他のコンポーネントによって消費されることを意図したJavaコンポーネントです。これはマルチプロジェクトビルドでは非常に一般的なユースケースですが、外部の依存関係があるとすぐにも起こります。
プラグインは、依存関係を宣言するために使用できる2つの設定を公開しています:apiとimplementationです。 API構成は、ライブラリAPIによってエクスポートされる依存関係を宣言するために使用する必要がありますが、実装構成は、コンポーネントの内部にある依存関係を宣言するために使用する必要があります。
簡単な解決策:
より良い方法は、すべてのcompile
依存関係をimplementation
依存関係に置き換えることです。そして、あなたがモジュールのインターフェースをリークするところだけで、あなたはapi
を使うべきです。それははるかに少ない再コンパイルを引き起こすはずです。
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.Android.support:appcompat-v7:25.4.0'
implementation 'com.Android.support.constraint:constraint-layout:1.0.2'
// …
testImplementation 'junit:junit:4.12'
androidTestImplementation('com.Android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.Android.support', module: 'support-annotations'
})
}
さらに説明する:
Android Gradle plugin 3.0より前のバージョン: :1つのコードを変更するとすべてのモジュールが再コンパイルされるという大きな問題がありました。その根本的な原因は、Gradleが、モジュールのインターフェースを他のインターフェースを通してリークしているかどうかを知らないことです。
Android Gradleプラグイン3.0以降 :最新のAndroid Gradleプラグインでは、モジュールのインターフェースをリークするかどうかを明示的に定義する必要があります。それに基づいて、それは何を再コンパイルすべきかについて正しい選択をすることができます。
そのため、compile
依存関係は非推奨となり、2つの新しい依存関係に置き換えられました。
api
:あなたはあなた自身のインターフェースを通してこのモジュールのインターフェースをリークします。これは古いcompile
依存関係と全く同じ意味です。
implementation
:あなたはこのモジュールを内部的に使うだけで、あなたのインターフェースを通してそれをリークすることはありません
そのため、使用されているモジュールのインターフェースが変更されたかどうかにかかわらず、Gradleにモジュールを再コンパイルするように明示的に指示することができます。
提供: Jeroen Mols ブログ
素人の言葉の簡単な違いは、次のとおりです。
包括的な例として@aldokの答えを読んでください。
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| Name | Role | Consumable? | Resolveable? | Description |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| api | Declaring | no | no | This is where you should declare |
| | API | | | dependencies which are transitively |
| | dependencies | | | exported to consumers, for compile. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| implementation | Declaring | no | no | This is where you should |
| | implementation | | | declare dependencies which are |
| | dependencies | | | purely internal and not |
| | | | | meant to be exposed to consumers. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| compileOnly | Declaring compile | yes | yes | This is where you should |
| | only | | | declare dependencies |
| | dependencies | | | which are only required |
| | | | | at compile time, but should |
| | | | | not leak into the runtime. |
| | | | | This typically includes dependencies |
| | | | | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| runtimeOnly | Declaring | no | no | This is where you should |
| | runtime | | | declare dependencies which |
| | dependencies | | | are only required at runtime, |
| | | | | and not at compile time. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testImplementation | Test dependencies | no | no | This is where you |
| | | | | should declare dependencies |
| | | | | which are used to compile tests. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testCompileOnly | Declaring test | yes | yes | This is where you should |
| | compile only | | | declare dependencies |
| | dependencies | | | which are only required |
| | | | | at test compile time, |
| | | | | but should not leak into the runtime. |
| | | | | This typically includes dependencies |
| | | | | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testRuntimeOnly | Declaring test | no | no | This is where you should |
| | runtime dependencies | | | declare dependencies which |
| | | | | are only required at test |
| | | | | runtime, and not at test compile time. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+