Gradle実装とAPI構成


231

依存関係を構築しながら、apiimplementation構成の違いを理解しようとしています。
ドキュメンテーションでは、それはimplementationビルド時間がより良いと述べていますが、このコメントを同様の質問で見て、 それが本当かどうか疑問に思いました。
私はGradleの専門家ではないので、誰かが助けてくれることを願っています。ドキュメンテーションはもう読みましたが、わかりやすい説明に疑問を感じていました。


1
ここを読みましたか?
MatPag 2017年

実はそうでしたが、言ったように、そのコメントはそれについて不思議に思いました。だから私はちょっと迷ってしまいました
レイナルドモレイラ2017年

ライブラリの依存関係をからcompileに切り替えますapi。内部で使用するライブラリは、最終的なライブラリで公開されていないプライベート実装を使用している可能性があるため、ユーザーには透過的です。これらの「内部プライベート」依存関係に切り替えることができimplementation、Android Gradleプラグインがアプリをコンパイルすると、それらの依存関係のコンパイルがスキップされ、ビルド時間が短縮されます(ただし、これらの依存関係は実行時に使用可能になります)。ローカルモジュールライブラリがあれば、明らかに同じことができます
MatPag

1
「api」と「実装」の簡単なグラフィカルな説明は次のとおり
c braun

1
それは素晴らしい投稿です!あなたの@albertbraun感謝
reinaldomoreira

回答:


418

Gradle compileキーワードは、依存関係を構成するためのapiおよびimplementationキーワードを支持して廃止されました。

を使用することapiは、廃止されたを使用することと同じですcompile。そのため、すべてcompileapiすべてに置き換えると、通常どおり機能します。

implementationキーワードを理解するには、次の例を検討してください。

と呼ばれるMyLibrary別のライブラリを内部的に使用するというライブラリがあるとしInternalLibraryます。このようなもの:

    // 'InternalLibrary' module
    public class InternalLibrary {
        public static String giveMeAString(){
            return "hello";
        }
    }
    // 'MyLibrary' module
    public class MyLibrary {
        public String myString(){
            return InternalLibrary.giveMeAString();
        }
    }

次のようにMyLibrary build.gradle使用api設定を想定しますdependencies{}

dependencies {
    api project(':InternalLibrary')
}

MyLibraryコードで使用したいので、アプリでbuild.gradleこの依存関係を追加します。

dependencies {
    implementation project(':MyLibrary')
}

使用しapiた構成を(または非推奨compileあなたがアクセスすることができます)InternalLibraryアプリケーションコードで:

// Access 'MyLibrary' (granted)
MyLibrary myLib = new MyLibrary();
System.out.println(myLib.myString());

// Can ALSO access the internal library too (and you shouldn't)
System.out.println(InternalLibrary.giveMeAString());

このように、モジュールMyLibraryは何かの内部実装を潜在的に「漏らしています」。これは直接インポートされないため、使用しないでください。

implementation設定はこれを防ぐために導入されました。だから今は使用している場合implementationの代わりをapiしてMyLibrary

dependencies {
    implementation project(':InternalLibrary')
}

InternalLibrary.giveMeAString()アプリコードで呼び出すことができなくなります。

このようなボクシング戦略により、Android GradleプラグインはInternalLibrary、で何かを編集する場合、再コンパイルをトリガーするだけでMyLibraryありあなたがアクセス権を持っていないので、あなたのアプリケーション全体の再コンパイルをInternalLibrary

ネストされた依存関係が多数ある場合、このメカニズムはビルドを大幅に高速化できます。 (これを完全に理解するには、最後にリンクされているビデオをご覧ください)

結論

  • 新しいAndroid Gradleプラグイン3.XXに切り替える場合は、すべてcompileimplementationキーワードを(1 *)に置き換える必要があります。次に、アプリをコンパイルしてテストします。問題がなければ、依存関係に問題があるか、プライベートでアクセスしづらいものを使用した可能性があります。Android GradleプラグインエンジニアJerome Dochezからの提案(1)*

  • ライブラリの管理者である場合は、ライブラリapiのパブリックAPIに必要なすべての依存関係を使用しimplementation、テストの依存関係または最終ユーザーが使用してはならない依存関係を使用する必要があります。

実装APIの違いを示す便利な記事

参照 (これは時間節約のために分割された同じビデオです)

Google I / O 2017-Gradleビルドのスピードアップ方法(フルビデオ)

Google I / O 2017-Gradleビルドのスピードアップ方法(NEW GRADLE PLUGIN 3.0.0 PART ONLY)

Google I / O 2017-Gradleビルドの速度を上げる方法(1 *を参照)

Androidのドキュメント


4
ライブラリモジュールではapiがうまく機能していないようです。それを使用しても、アプリプロジェクトから依存関係にアクセスできません。そのライブラリ自体のコードにしかアクセスできません。
アランW

1
これは問題なく、デバッグビルドで機能しますが、ProGuard(リリースバージョン)を使用MyLibrary#myString()すると、ProGuardがInternalLibrary削除されるためクラッシュします。ProGuardのアプリで使用するandroid-libsのベストプラクティスは何ですか?
hardysim 2017

3
答えは正確ではないと思います。アプリケーションはMyLibraryに必要なスコープを使用できます。MyLibraryがapi /実装を使用するかどうかに応じて、InternalLibraryを表示するかどうかを確認します。
スニコラ2017

2
ありがとう。Androidの公式ドキュメントで提供されているものよりもはるかに優れた説明
Henry

2
それは美しい説明です。理論とコンクリートは見事に混ざっています。よくやった。それをありがとう
Peter Kahn

134

api依存関係をパブリック(他のモジュールから見た)と見なし、implementation依存関係をプライベート(このモジュールでのみ参照)と見なしたいと思います。

public/ private変数とメソッドとは異なり、api/ implementation依存関係はランタイムによって強制されないことに注意してください。これは単にビルド時の最適化でGradleあり、依存関係の1つがAPIを変更したときに再コンパイルする必要があるモジュールを知ることができます。


16
この回答のシンプルさが大好きです。ありがとうございました
Kevin Gilles

2
真の違い(AFAICT)は、生成されたpomファイルがapi依存関係を「コンパイル」スコープ(ライブラリの依存関係およびライブラリに依存するものとして含まれます)とimplementation「ランタイム」スコープの依存関係(それらはコードが実行されているときのクラスパスですが、ライブラリを使用する他のコードをコンパイルする必要はありません)。
シャドウマン

@ShadowManこれは、POMファイルの生成を担当するプラグインの実装の詳細であり、GradleスコープをMavenスコープにマップする方法です。
dev.bmax

1
あなたは使用する必要がありますimplementation実行します(とコンパイルにあなたのライブラリーのために)するために必要とされるすべての依存関係のために、それは自動的にあなたのライブラリーを使用するプロジェクトに引き込ますべきではありません。例としては、jax-rsがあります。ライブラリはRESTeasyを使用する可能性がありますが、ライブラリを使用するプロジェクトにそれらのライブラリをプルしないでください。代わりに、Jerseyを使用する場合があります。
シャドウマン

1
これは、誰かがそのものを手に入れるのを知る方法です:Dシンプルで明確な答えをありがとう
エリアス・ファゼル

12

あなたが持って考えてみましょうapp使用するモジュールlib1のライブラリとしてlib1の用途lib2図書館などを。このような何か:app -> lib1 -> lib2

使用している場合今api lib2ではlib1、それからapp 見ることができます lib2使用する場合のコードを:api lib1またはimplementation lib1appモジュール。

しかし、implementation lib2in を使用するlib1と、コードapp が表示されませんlib2


5

@matpag@ dev-bmaxからの回答は、実装とAPIの間のさまざまな使用法を人々に理解させるのに十分明確です。私は別の角度から追加の説明をしたいだけです、同じ質問を持つ人々のために助けたいと思います。

テスト用に2つのプロジェクトを作成しました。

  • 「frameworks-web-gradle-plugin」という名前のJavaライブラリプロジェクトとしてのプロジェクトAは、「org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE」に依存しています
  • プロジェクトBは、実装 'com.example.frameworks.gradle:frameworks-web-gradle-plugin:0.0.1-SNAPSHOT'によってプロジェクトAに依存しています

上記の依存関係の階層は次のようになります。

[project-b]-> [project-a]-> [spring-boot-gradle-plugin]

次に、以下のシナリオをテストしました。

  1. プロジェクトAが実装によって「org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE」に依存するようにします

    gradle dependenciesターミナルでプロジェクトBルートディレクトリのコマンドを実行します。次の出力のスクリーンショットを見ると、「spring-boot-gradle-plugin」がruntimeClasspathの依存関係ツリーには表示されますが、compileClasspathには表示されないことがわかります。実装を使用して宣言されたライブラリを使用する場合、コンパイルは行われません。

    ここに画像の説明を入力してください

  2. プロジェクトAがAPIによって「org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE」に依存するようにする

    gradle dependenciesターミナルでコマンドB root dirを再度実行します。これで、「spring-boot-gradle-plugin」がcompileClasspathとruntimeClasspathの依存関係ツリーの両方に表示されます。

    ここに画像の説明を入力してください

私が気付いた大きな違いは、実装方法で宣言されたプロデューサー/ライブラリプロジェクトの依存関係がコンシューマープロジェクトのcompileClasspathに表示されないため、コンシューマープロジェクトで対応するlibを使用できないことです。


2

Gradleのドキュメントから:

JVMベースのプロジェクトの非常に単純なビルドスクリプトを見てみましょう。

plugins {
    id 'java-library'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.hibernate:hibernate-core:3.6.7.Final'
    api 'com.google.guava:guava:23.0'
    testImplementation 'junit:junit:4.+'
}

実装

プロジェクトによって公開されたAPIの一部ではない、プロジェクトの本番ソースをコンパイルするために必要な依存関係。たとえば、プロジェクトでは、内部永続層の実装にHibernateを使用しています。

api

プロジェクトによって公開されたAPIの一部であるプロジェクトの本番ソースをコンパイルするために必要な依存関係。たとえば、プロジェクトはGuavaを使用し、メソッドシグネチャでGuavaクラスとのパブリックインターフェイスを公開します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.