Gradle動的依存関係を使用する正しい方法



Gradle 非常に人気のある柔軟なビルドシステムです.とりわけ、依存関係管理に対処することができます.アプリケーションが使用するすべての依存関係(外部フレームワークとライブラリ)を定義できます.
dependencies {
    implementation 'com.nexmo.android:client-sdk:2.7.0'
}
上記のコードは、ダウンロードされますNexmo Client SDK . 動的依存性に移行する前に、意味的バージョン管理を簡単に見てみましょう.

意味的バージョン管理


最近のほとんどの図書館はSemantic versioning specification , また、semverとして知られている.メジャー推進.マイナー.依存性バージョン管理のためのパッチ( 2.7.0 )形式.各番号は、特定の基準が満たされたときにインクリメントされます.
major 部分は、後方互換性のないAPI変更がなされるとき、増加します.新しいバージョンを引っ張ると、ほとんどの場合、メソッドのシグネチャの変更やメソッドの削除などのビルドが中断されます.
minor 機能は、後方互換性の方法で追加されたときに増加するか、またはプライベートコード内での改善が導入されます.
patch 部分は後方互換性のあるバグ修正が行われたときにインクリメントされます.これはリリースの最も一般的なタイプです、そして、通常、我々はいろいろなバグ修正のために最新のパス・バージョンを持ちたいです.

動的依存


また、Gradleは依存関係の動的なバージョンを定義することができます+ 依存定義の文字.
dependencies {
    implementation 'com.nexmo.android:client-sdk:2.7.+'
}
上の例では、Gradleは最新のクライアントSDKをダウンロードしますpath バージョン2.7.1 , 2.7.2 , 2.7.3などGradleは複数の方法で動的なバージョンの検索を定義することができます.いくつかの例を見てみましょう.
-実装' com.ネクサスクライアントSDK:2.7 .+'新しいライブラリをダウンロードpath バージョンが変更
-実装' com.ネクサスアンドロイド:クライアントSDK新しいライブラリをダウンロードminor or path バージョンが変更
-実装' com.ネクサスクライアントのSDK :+ -常に-ライブラリの最新バージョンをダウンロードします
このメカニズムは、すべてのパフォーマンス改善、パッチ、およびバグ修正を最新の状態でライブラリバージョンを使用していることを保証する良い方法です.しかし、実際には、動的依存性の使用は、複数の問題につながる可能性があります.いくつかの現実的なシナリオを考慮しましょう.

問題シナリオ1


最も簡単なシナリオから始めましょう.我々のアプリケーションは、サードパーティのライブラリの動的な依存関係を使用しています.我々は、我々のアプリケーションのバグを発見し、それは1ヶ月前に罰金働いていた知っている.私たちは過去から1つ以上のビルドを使用して、バグがコードベースで導入されたかを判断します.我々は1ヶ月前からのリポジトリからコードをチェックアウト、アプリケーションがうまく働いていた時間の瞬間、そして我々はアプリを構築したが、アプリケーションはまだ予想通りに動作しません-問題はまだそこにあります.何が起こったのですか.バグが外部ライブラリにあったことがわかります.私たちのSRCコードは30日前からでしたが、Gradle Dynamic Dependency機構は最初のビルドが作成された(バグなしで)1ヶ月前に存在しなかった最新バージョンの依存関係をダウンロードしました.

Lesson 1: It is hard to make the same build of the application when dynamic dependencies are used because the build depends on external library versions that most likely change over time.


問題シナリオ2


私たちは図書館のクリエイターです.我々のライブラリのユーザに、このダイナミックな依存関係を明示的に使うように頼みました.
dependencies {
    implementation 'com.nexmo.android:client-sdk:2.7.+’
}
これらのコードは、上記のコードをコピーするだけで、プロジェクトに依存しています.いくつかの時点で、バグを導入するライブラリの新しいバージョンをリリースしました.今、ユーザーは“数日前に、彼らのアプリケーションは、期待通りに動作を停止報告している.”開発者は、ライブラリの新しいバージョンがバグを引き起こすことを知りません.代わりにすぐにライブラリのバージョンを反転して問題を修正すると、バグレポートを送信し、修正プログラムを待ちます.

Lesson 2: Do not advise your library users to use dynamic dependency versions because when you break the library, they will most likely not know the exact cause of the problem.


解決策


Intellijのアイデアのような現代のIDEでは、動的依存関係の使用法について警告します.

予測不可能性を避けるために、依存性のバージョンを明示的に指定し、必要性が発生すると手動で更新します.これは、バージョンの更新を完全に制御することができますし、依存関係のchangelogを詳しく見て、変更を確認します.IDEは時代遅れの依存関係に関する警告も表示します.

この戦略は細かいプロジェクトのためにうまく動作しますが、手動での更新は時間がかかります.私たちはgradle-versions-plugin 依存性を更新する必要があるかどうかを確認するには、次の手順に従います.
./gradlew dependencyUpdates.
上記のコマンドは、すべての古い依存関係を報告するレポートを生成します.
また、決定論的ビルドと動的依存関係をバランスさせるためにさらに一歩を踏み出すことができます.Gradle Dependency Lock Plugin Gradle build configで動的な依存関係の構文を使用することができます.同時に、これらの依存関係を特定のバージョンに対してロックします.これは依存関係が更新されるときの完全な制御を与えます.依存関係を更新するには、一つのコマンドを実行しなければなりません.
./gradlew --refresh-dependencies generateLock saveLock
上記のコマンドはdependencies.lock 依存関係のバージョンを含むファイル.このファイルはバージョン管理に含まれていて、チーム内のすべての開発者が同じバージョンの依存関係を使用することを保証します.チームとして、すべての開発サイクルの開始など、依存関係を更新するときに決めることができます.

概要


Gradleの動的依存性を使用すると、アプリケーションの新しいバグが発生する可能性があります.あなたが幸運なら、これらのバグは、テストによってキャッチされる可能性がありますが、これは保証されていません.その上、バグの原因は明らかではない.我々のアプリケーションを構築するときは、可動部分の数を減らす必要があります.理想的には、ビルドは決定的でなければならず、同じソースコードを構築するのとまったく同じアプリケーションを生成する必要があります.動的依存関係のバージョンを使用する場合は、Gradle Dependency Lock Plugin ; それ以外の場合は、依存関係のバージョンを明示的に指定する必要があります.
郵便The Right Way of Using Gradle Dynamic Dependencies 最初に現れたVonage Developer Blog .