Gradleでの実装とコンパイルの違いは何ですか?


1029

Androidのメーカー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'

それらの違いは何ですか?何を使うべきですか?

回答:


1282

tl; dr

置き換えるだけです:

  • compileimplementation(あなたが推移性を必要としない場合)、またはapi(あなたが推移性を必要とする場合)
  • testCompiletestImplementation
  • debugCompiledebugImplementation
  • androidTestCompileandroidTestImplementation
  • compileOnlyまだ有効です。3.0で追加され、コンパイルではなく提供されたものを置き換えます。(providedGradleがそのユースケースの設定名を持っていなかったときに導入され、Mavenが提供したスコープにちなんで名前を付けました。)

これは、Google がIO17で発表したGradle 3.0 に伴う重大な変更の1つです。

compile設定がされて廃止とで交換する必要がありますimplementationapi

Gradleのドキュメントから:

dependencies {
    api 'commons-httpclient:commons-httpclient:3.1'
    implementation 'org.apache.commons:commons-lang3:3.5'
}

api構成に表示される依存関係は、ライブラリのコンシューマに推移的に公開され、コンシューマのコンパイルクラスパスに表示されます。

implementation一方、設定で見つかった依存関係はコンシューマに公開されないため、コンシューマのコンパイルクラスパスにリークしません。これにはいくつかの利点があります。

  • 依存関係がコンシューマのコンパイルクラスパスにリークしないため、推移的な依存関係に誤って依存することはありません。
  • クラスパスのサイズを小さくすることでコンパイルを高速化
  • 実装の依存関係が変更された場合の再コンパイルの減少:コンシューマーを再コンパイルする必要がない
  • よりクリーンなパブリッシング:新しいmaven-publishプラグインと組み合わせて使用​​すると、Javaライブラリーは、ライブラリーに対してコンパイルするために必要なものと実行時にライブラリーを使用するために必要なものを正確に区別するPOMファイルを生成します(つまり、ライブラリ自体をコンパイルするために必要なものと、ライブラリに対してコンパイルするために必要なものを混ぜます)。

コンパイル構成はまだ存在apiimplementationますが、and 構成が提供する保証を提供しないため、使用しないでください。


注:アプリモジュールでライブラリのみを使用している場合-一般的なケース-違いに気付かないでしょう。
相互に依存するモジュールを持つ複雑なプロジェクトがある場合、またはライブラリを作成する場合にのみ、違いがわかります。


137
「消費者」は誰ですか?
Suragch 2017

34
コンシューマはライブラリを使用するモジュールです。Androidの場合は、Androidアプリケーションです。これは明らかだと思いますが、これがあなたが求めているものかどうかはわかりません。
ヒューマライズされた

21
それも私にはそのように聞こえました。ただし、ライブラリを作成している場合は、もちろん、そのAPIをアプリに公開する必要があります。それ以外の場合、アプリ開発者は私のライブラリをどのように使用しますか?そのためimplementation、依存関係を非表示にする意味がありません。私の質問は意味がありますか?
Suragch 2017

235
はい、アプリがy、zに依存するライブラリxに依存している場合、これは理にかなっています。implementationxのみを使用する場合、apiが公開されますが、apiy、z を使用する場合も公開されます。
ヒューマライズ

36
とった!今ではもっと理にかなっています。この説明を回答に追加できます。引用されたドキュメントよりも明確です。
Suragch 2017

380

この答えは、違いを実証するimplementationapicompileのプロジェクトに。


3つのGradleモジュールを含むプロジェクトがあるとします。

  • アプリ(Androidアプリ)
  • myandroidlibrary(Androidライブラリ)
  • myjavalibrary(Javaライブラリ)

app持っているmyandroidlibrary依存関係として。myandroidlibrary持っているmyjavalibrary 依存関係として。

依存関係1

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ので、appbuild.gradleで使用しますimplementation

:api / compileも使用できます。ただし、しばらく考えてみてください。)

dependencies {
    implementation project(':myandroidlibrary')      
}

依存関係2

myandroidlibrarybuild.gradleはどのように見えると思いますか?どのスコープを使用する必要がありますか?

3つのオプションがあります。

dependencies {
    // Option #1
    implementation project(':myjavalibrary') 
    // Option #2
    compile project(':myjavalibrary')      
    // Option #3
    api project(':myjavalibrary')           
}

依存関係3

それらの違いは何ですか?何を使うべきですか?

コンパイルまたはAPI(オプション#2または#3) 依存関係4

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)

依存関係5

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 Libraryプラグイン-より詳細な説明のために依存関係を宣言するために使用される構成

この回答のサンプルプロジェクトはhttps://github.com/aldoKelvianto/ImplementationVsCompileにあります


1
実装を使用して1つのjarファイルに依存関係を追加しましたが、それへのアクセスが公開されていない場合、なぜ取得でき、コードが正常に機能していますか?
smkrn110

@ smkrn110実装は、jarライブラリを公開しますが、jar依存ライブラリは公開しません。
アルドク

2
@WijaySharma受け入れられた回答は、compile保証するものと同じものをapi保証しないことを述べています。
サブ6リソース

9
これは受け入れられる答えだと思います。よく説明されました!
Shashank Kapsime

9
@ StevenW.Klassenは、私が聞いたことのない最も不当な投票です。情報の順序が最適ではないと思われる場合は、不満を言う代わりに編集を提案してください
Tim

65

Compile構成は非推奨であり、implementationまたはに置き換える必要がありますapi

ドキュメントはhttps://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separationで読むことができます

簡単な部分は

標準JavaプラグインとJavaライブラリプラグインの主な違いは、後者がコンシューマに公開されるAPIの概念を導入することです。ライブラリは、他のコンポーネントによって消費されることを意図したJavaコンポーネントです。これは、マルチプロジェクトビルドの非常に一般的な使用例ですが、外部依存関係があるとすぐに発生します。

プラグインは、依存関係を宣言するために使用できる2つの構成、APIと実装を公開します。API構成は、ライブラリAPIによってエクスポートされる依存関係を宣言するために使用する必要がありますが、実装構成は、コンポーネントの内部にある依存関係を宣言するために使用する必要があります。

詳細については、この画像を参照してください。 簡単な説明


46

簡単な解決策:

より良いアプローチは、すべての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プラグイン3.0以前:大きな問題が1つありました。これは、1つのコード変更ですべてのモジュールが再コンパイルされることです。これの根本的な原因は、Gradleがモジュールのインターフェースを別のモジュールを介してリークするかどうかを知らないことです。

Android Gradleプラグイン3.0以降:最新のAndroid Gradleプラグインでは、モジュールのインターフェースをリークするかどうかを明示的に定義する必要があります。これに基づいて、何を再コンパイルするかについて正しい選択を行うことができます。

そのため、compile依存関係は廃止され、2つの新しい依存関係に置き換えられました。

  • api:あなたはあなた自身のインターフェースを通してこのモジュールのインターフェースを漏らします、それは古いcompile依存関係と全く同じ意味です

  • implementation:このモジュールは内部でのみ使用し、インターフェースからリークしません

そのため、使用されているモジュールのインターフェースが変更されたかどうかにかかわらず、モジュールを再コンパイルするようにGradleに明示的に指示できます。

Jeroen Molsブログ提供


2
クリーンで簡潔な説明。ありがとう!
レオン

20
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| 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.  |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+

質問に直接回答しません
skryvets

1
また、developmentOnlyもあります
Hohenheimsenberg

ランタイムとコンパイル時間の両方が必要な場合、何を使用すればよいですか?現在、私はimplementation続いていruntimeます。
Maroun

8

素人の用語の簡単な違いは:

  • 宣言された依存関係のメンバーを公開することによって他のモジュールにサポートを提供するインターフェースまたはモジュールで作業している場合は、「api」を使用する必要があります。
  • 上記の依存関係を内部で実装または使用するアプリケーションまたはモジュールを作成する場合は、「実装」を使用します。
  • 'compile'は 'api'と同じように機能しましたが、ライブラリのみを実装または使用している場合は、 'implementation'がより適切に機能し、リソースを節約できます。

包括的な例については、@ aldokの回答を読んでください。


しかし、問題は、これらの質問への答えを探して故意にここに来た人は、結局のところ素人ではないということです。
リシャフ

6

バージョン5.6.3以来のGradleドキュメント古いかどうかを識別するために親指の簡単なルールを提供しcompile、依存関係(または新しいものが)に置き換えてくださいimplementationまたはapi依存関係:

  • 可能な場合よりもimplementation構成を優先するapi

これにより、コンシューマのコンパイルクラスパスから依存関係がなくなります。さらに、いずれかの実装タイプが誤ってパブリックAPIにリークすると、コンシューマーはすぐにコンパイルに失敗します。

それでは、いつapi構成を使用する必要がありますか?APIの依存関係は、ライブラリのバイナリインターフェイスで公開される少なくとも1つのタイプを含む依存関係であり、多くの場合、そのABI(アプリケーションバイナリインターフェイス)と呼ばれます。これには以下が含まれますが、これらに限定されません。

  • スーパークラスまたはインターフェースで使用される型
  • ジェネリックパラメータータイプを含むパブリックメソッドパラメーターで使用されるタイプ(パブリックはコンパイラーから見えるものです。つまり、Javaの世界では、パブリック、プロテクト、およびパッケージのプライベートメンバーです)
  • パブリックフィールドで使用されるタイプ
  • パブリックアノテーションタイプ

対照的に、次のリストで使用されているタイプはABIとは無関係であるため、implementation依存関係として宣言する必要があります。

  • メソッド本体でのみ使用されるタイプ
  • プライベートメンバー専用のタイプ
  • 内部クラスでのみ使用される型(Gradleの将来のバージョンでは、どのパッケージがパブリックAPIに属するかを宣言できるようになります)

6

Gradle 3.0 次の変更が導入されました:

  • compile -> api

    api キーワードは廃止予定と同じです compile

  • compile -> implementation

    ある好適ないくつかの利点を持っているための方法。ビルド時に1レベル上のimplementation依存関係のみを公開します(依存関係は実行時に使用可能です)。その結果、ビルドが高速になります(1レベル以上のコンシューマーを再コンパイルする必要はありません)。

  • provided -> compileOnly

    この依存関係はコンパイル時にのみ使用できます(依存関係は実行時には使用できません)。この依存関係は、推移的であり続けることはできません.aar。コンパイル時の注釈プロセッサで使用でき、最終的な出力ファイルを減らすことができます

  • compile -> annotationProcessor

    に非常に似てcompileOnlyいますが、推移的な依存関係が消費者に表示されないことも保証します

  • apk -> runtimeOnly

    依存関係はコンパイル時には利用できませんが、実行時には利用できます。


だから、他の言葉でapi = publicimplementation = internalそしてcompileOnly = private-私は彼らがスーパー混乱しているように、これらの機能のために、このようなエイリアスを作成する必要があります。
t3chb0t
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.