[Gradle-4] Gradle ライフサイクル

1. Gradleのライフサイクル

Gradleのライフサイクルも非常に重要な概念で、理解するといろいろなことが分かりますし、ライフサイクルの各段階での対面処理の「ブラックテクノロジー」もできます。

1.1、3段階

Gradle は、とInitialization (初始化)3 つのフェーズでビルドを評価して実行し、ビルド タスクはこれら 3 つのフェーズを実行します。Configuration (配置)Execution (执行)

  • 初期化フェーズ中に、Gradle はビルドにどのプロジェクトが含まれるかを決定し、プロジェクトごとに Project インスタンスを作成します。どのプロジェクトをビルドに含めるかを決定するために、Gradle はまず settings.gradle を探して、これが単一プロジェクトのビルドであるか複数プロジェクトのビルドであるかを判断します。単一プロジェクトはモジュールであり、複数プロジェクトはモジュールです。プロジェクト+アプリ+モジュール(1+n)。
  • 構成 (構成) フェーズでは、Gradle はビルド プロジェクトに含まれるすべてのビルド スクリプトを評価し、プラグインを適用し、DSL を使用してビルドを構成し、最後にタスクを登録します。入力は必ずしも実行されるわけではないため、遅延登録されます。
  • 最後に、Execution (実行) フェーズでは、Gradle はビルドに必要な一連のタスクを実行します。

1.2. ライフサイクルの本質

ライフサイクルの本質は、各段階のタスク(Task)を組み合わせて、意図に沿ってプロジェクトを構築することです。
Taskこれは Gradle の構築の中核です。そのモデルは有向非巡回グラフ (DAG) です。タスク間には依存関係、つまり依存関係グラフがあります。Gradle は構築期間中にタスク グラフを使用して一連のタスクを形成します。は一連のタスクです。
このタスク収集の起源は、構築にどのプロジェクトが関与しているかを明確にする必要がある初期化段階と、構築に参加するすべてのプロジェクトの構成を分析する構成段階の、上記の 3 つの段階から構成されます。これには、タスクの登録が含まれます。プロジェクトの構成によって、タスクの実行順序が決まります。たとえば、特定のことを実行するために組み込みタスクに依存するサブプロジェクトにカスタム タスクがある場合、このカスタム タスクはタスクもコレクションに追加する必要があります。最後に実行段階となり、順番に実行されます。コレクション内のタスクは、apk のビルドに使用されます。
つまり、逆に、apk は多くのファイルで構成されており、それらのファイルはタスクによって実行される入出力によって結合されてマージされ、具体的にどのタスクを実行するか、つまりどのようなパッケージを印刷するかは 3 つのライフによって決定されます。ステージごとに周期が決められています。
DAG の凡例:
タスク日の例.png

2. 初期化

初期化フェーズ中に、Gradle はビルドにどのプロジェクトが含まれるかを決定し、プロジェクトごとに Project インスタンスを作成します。どのプロジェクトがビルドに含まれるかを決定するために、Gradle はまず、settings.gradleこれが単一プロジェクトのビルドであるか、複数プロジェクトのビルドであるかを判断します。

2.1、設定.gradle

2.1.1、設定

前回の記事では、build.gradle の構成とメソッド呼び出しがProjectオブジェクトに委任されることを紹介しましたが、ビルド スクリプトの settings.gradle の構成とメソッド呼び出しもSettingsオブジェクトに委任されます。
Gradle のビルド時に設定インスタンスが作成され、それに基づいて設定ファイルが実行されます。Settings インスタンスと settings.gradle ファイルの間には 1 対 1 の対応関係があります。

設定: プロジェクト インスタンスの構築に参加する階層をインスタンス化して構成するために必要な構成を宣言します。

2.1.2. プロジェクト管理

Gradle は、単一プロジェクトまたは複数プロジェクトのビルドをサポートします。

  • 単一プロジェクトのビルド、settings.gradle ファイルはオプションです。
  • マルチプロジェクトの構築には、settings.gradle ファイルが必要であり、プロジェクトのルート ディレクトリに配置する必要があります。

マルチプロジェクトビルド用のファイルsettings.gradle:

pluginManagement {
    
    
    repositories {
    
    
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}
dependencyResolutionManagement {
    
    
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
    
    
        google()
        mavenCentral()
    }
}
rootProject.name = "GradleX"
include ':app'
include ':lib'

目次:

.
├── app
│   ...
│   └── build.gradle
├── lib
│   ...
│   └── build.gradle
└── settings.gradle

コアは、include指定されたプロジェクトをビルドに追加することを意味します。これは、プロジェクトに含まれるモジュール パスを指すことも、ハードディスク内のサブプロジェクトの絶対パスを指すこともできます。これは、次の場合に非常に便利です。プロジェクト aar とソースコードを切り替えてコンパイルを高速化する重要な手段の 1 つです。

2.1.3. プラグインの管理

settings.gradle でプロジェクトを管理することに加えて、もう 1 つ重要なことは、プラグイン (Plugin) を管理することですpluginManagement

2.1.3.1、プラグイン ウェアハウス

pluginManagement {
    
    
    repositories {
    
    
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}

pluginManagementでは、repositoriesプラグインが必要とするダウンロードウェアハウスのアドレスを指定します。カスタム プラグインがプライベート ウェアハウスで公開されている場合は、プラグインを見つけるためにここにプライベート ウェアハウスのアドレスを追加する必要があります。

2.1.3.2、プラグインの置き換え

pluginManagement 設定は、PluginManagementSpec次の 5 つのメソッドを持つインターフェイス クラスによって解析されます。
プラグイン管理仕様.png

includeBuild メソッドはバージョン 7.0 以降で使用できる必要があります。

私たちは主に以下を使用しますresolutionStrategy:

@HasInternalProtocol
public interface PluginResolutionStrategy {
    
    

    /**
     * Adds an action that is executed for each plugin that is resolved.
     * The {@link PluginResolveDetails} parameter contains information about
     * the plugin that was requested and allows the rule to modify which plugin
     * will actually be resolved.
     */
    void eachPlugin(Action<? super PluginResolveDetails> rule);

}

PluginResolutionStrategy を使用すると、PluginRequest の前に変更でき、独自のコールバック eachPlugin があり、 eachPlugin のパラメータ タイプは PluginResolveDetails です。
プラグイン解決の詳細:

  • getRequested: 要求されたプラグインを取得し、ID、バージョン、モジュール情報を含む PluginRequest オブジェクトを返します。
  • useModule: プラグインのモジュールを設定します。
  • useVersion: プラグインのバージョンを設定します。
  • getTarget: 要求されたターゲット プラグイン。

プラグインの置き換えには主に次のuseModule方法が使用されます。

pluginManagement {
    
    
    resolutionStrategy {
    
    
        eachPlugin {
    
    
            if (requested.id.id == "org.gradle.sample") {
    
    
                useModule("com.yechaoa.plugin:gradlex:1.0")
            }
        }
    }
}

2.1.3.3、プラグインバージョン

プラグイン版では主に以下のuseVersion方法を使用します。

pluginManagement {
    
    
    resolutionStrategy {
    
    
        eachPlugin {
    
    
            if (requested.id.id == "com.yechaoa.plugin") {
    
    
                useVersion("2.0")
            }
        }
    }
}

バージョンを設定した後、すべてのビルド スクリプトでプラグイン { } を介してプラグインがインポートされる場合は、バージョンを再度指定する必要はありません。

2.2、settings.gradleを見つける方法

settings.gradle の重要性については以前に紹介しましたが、Gradle はビルド時にどのようにして settings.gradle ファイルを見つけるのでしょうか?

  1. まず、プロジェクトのルートディレクトリに settings.gradle ファイルが見つかりますが、見つからない場合は、単一のプロジェクトとしてビルドされます。
  2. 見つかった場合は、インクルード設定の正当性を再度チェックし、正当でない場合は単一プロジェクトとしてビルドを継続し、正当である場合はマルチプロジェクトとしてビルドします。

3. 構成

構成 (構成) フェーズでは、Gradle はビルド プロジェクトに含まれるすべてのビルド スクリプトを評価し、プラグインを適用し、DSL を使用してビルドを構成し、最後にタスクを登録します。入力は必ずしも実行されるわけではないため、遅延登録されます。

注: どのタスクの実行が要求されても、構成フェーズは実行されます。したがって、構築をシンプルかつ効率的に保つためには、Android の onDraw メソッドと同様に、構成フェーズで時間のかかる操作を避ける必要があります。

簡単に言えば、構成フェーズでは、Project オブジェクトを作成し、build.gradle ファイルを実行し、コードに基づいて対応するタスクの依存関係グラフを作成します。

3.1、プロジェクト

Gradle がビルドされると、Settings オブジェクトから解析されたプロジェクト構造に基づいてプロジェクトごとにオブジェクトが作成されますProject。Project オブジェクトと build.gradle ファイルの間には 1 対 1 の関係があります。
Gradle がタスク依存関係グラフを生成する前に、Project オブジェクトはいくつかのことを行います。

  • インポートプラグイン
  • 構成プロパティ
  • 依存関係をコンパイルする

3.1.1. プラグインのインポート

plugins {
    
    
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

plugins は Project オブジェクトのメソッドであり、現在のモジュールで使用されるプラグインを設定するために使用されます。

3.1.2、設定プロパティ

android {
    
    
    namespace 'com.yechaoa.gradlex'
    compileSdk 32

    defaultConfig {
    
    
        applicationId "com.yechaoa.gradlex"
        minSdk 23
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    // ...
}

前回の記事では、android { } 設定のソースコードを分析しましたが、android { } 設定は実際にはid 'com.android.application' プラグDSLインの設定です。つまり、build.gradle 内のすべての設定が実際にはプラグインの設定です。 DSL を介した -in。これらの設定はプラグインの実行に影響を与え、ビルド プロセス全体に影響します。

3.1.3. コンパイルの依存関係

dependencies {
    
    

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    
    // ...
}

依存関係 { } 公式ライブラリに加えて、okhttp、glide などの必要なサードパーティ ライブラリを追加することがよくあります。
モジュール自体の 3 者間の依存関係により、ウェアハウスのダウンロード アドレスを build.gradle に直接追加できます。

repositories {
    
    
    mavenCentral()
    // other url
}

7.0 より前のサブプロジェクト { } と同等、settings.gradle の dependencyResolutionManagement>repositories は 7.0 より前のすべてのプロジェクト { } と同等です。

前の[Gradle-2] の記事では、 Gradle 設定に少しの dependencyResolutionManagement repositoriesMode、つまりすべてのプロジェクト { } とサブプロジェクト { } に対する Gradle の依存関係解決戦略が欠落していることを理解しています。

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

リポジトリモード:

  • PREFER_PROJECT: デフォルト値。最初に build.gradle のリポジトリ { } を使用し、settings.gradle のリポジトリ { } を無視します。
  • PREFER_SETTINGS: settings.gradle のリポジトリ { } を優先し、build.gradle のリポジトリ { } を無視します。
  • FAIL_ON_PROJECT_REPOS: これは素晴らしいことです。build.gradle で宣言されたリポジトリ { } がコンパイル エラーを引き起こすことを示しています。

アプリモジュールのみの場合は、dependencyResolutionManagement>repositories にウェアハウスのアドレスを記述できますが、複数のモジュールがあり、依存関係が大きく異なる場合は、個別に記述することをお勧めします。コンパイルの問題ではありませんが、消費しています... (無視できます)

もちろん、Project オブジェクトは一般的にこれらのことを行うだけでなく、公開などの追加の構成も行うことができます。

4. 実行

Execution (実行) フェーズでは、Gradle はビルドに必要な Task コレクションを実行します。
実際、この段階は実際のコンパイルとパッケージ化であり、Android の場合は、一般的なcompileDebugJavaWithJavac、mergeDebugNativeLibsなどです。
画像.png

5. フックのライフサイクル

Gradle は、ライフサイクルのさまざまな段階で豊富なコールバックを提供します。これは、アスペクト処理を行うときに非常に役立ちます。
画像.png

5.1、初期化フック

初期化フェーズのフックは、フック設定オブジェクトです。settings.gradle が評価される (evaluate) とき、初期化された設定オブジェクトがすでに存在します。たとえば settings.gradle などのメソッドによってフックを追加
できます。gradle.settingsEvaluated

println("---Gradle:开始初始化了")
gradle.settingsEvaluated {
    println("---Gradle:settingsEvaluated Settings对象评估完毕")
}

この時点で、Settings オブジェクトを取得できます。Settings オブジェクトは主にプロジェクトとプラグインの管理に使用されることを上で紹介しました。この時点で、特定のプラグインをすべてのプラグインに追加するなど、いくつかのグローバルな操作を実行できます。プロジェクト。
gradle.settingsEvaluated が実行されますgradle.projectsLoaded

gradle.projectsLoaded {
    println("---Gradle:projectsLoaded 准备加载Project对象了")
}

projectLoaded がコールバックされると、各モジュールの Project オブジェクトが settings.gradle に従って作成されており、Project オブジェクトを参照していくつかのフックを設定できます。

gradle.allprojects{
    beforeEvaluate {
        println("---Gradle:Projec beforeEvaluate Project开始评估,对象是 = "+project.name)
    }
    afterEvaluate {
        println("---Gradle:Projec afterEvaluate Project评估完毕,对象是 = "+project.name)
    }
}

ただし、この時点ではまだ Initialization (初期化) 段階に属し、Configuration (構成) 段階に到達していないため、Project オブジェクトにはプロジェクトの基本情報のみが含まれており、build.gradle 内の構成情報は含めることができません。が取得されるため、この段階で使用可能なオブジェクトは設定ですが、Gradle オブジェクトはどの段階でも使用できます。

5.2、設定フック

初期化が実行されると、構成フェーズに入ります。構成フェーズでは、構築に関与するすべてのプロジェクトの構成を取得できます。最初に、ルート プロジェクト配下の build.gradle が実行され、次に、ルート プロジェクト配下の build.gradle が実行されます。モジュールプロジェクト。
このとき、Project オブジェクトは実行前と実行後にフックできますが、Project オブジェクトなので settings.gradle には記述できませんが、build.gradle に記述できます。

project.beforeEvaluate {
    println("---project:beforeEvaluate Project开始评估,对象是 = " + project.name)
}

project.afterEvaluate {
    println("---project:afterEvaluate Project评估完毕,对象是 = " + project.name)
}

実行ログから、フックポイントが build.gradle の内容を通過しているため、project.beforeEvaluate メソッドが実行されていないことがわかり、有効になりません。

project.afterEvaluateコールバックの実行は、Project オブジェクトの評価が完了したことを意味し、この時点で Project オブジェクト内の構成情報を取得できるようになります。この段階ではプロジェクト オブジェクトが構成されたばかりであるため、この段階では多くの動的タスクがビルドに追加されます。

すべての Project オブジェクトが評価された後、コールバックされますgradle.projectsEvaluated

gradle.projectsEvaluated {
    println("---Gradle:projectsEvaluated 所有Project对象评估完毕")
}

ここまでで、全体を制御する Gradle オブジェクト、参加モジュールを調整する Settings オブジェクト、各サブモジュールの Project オブジェクトなど、ビルドのすべてのオブジェクトが作成されました。

5.3、実行フック

Gradle は実行 (実行) フェーズでタスクを実行します。TaskExecutionListenerフック タスクの実行を追加できます。

gradle.addBuildListener(new TaskExecutionListener(){

    @Override
    void beforeExecute(Task task) {
        println("---Gradle:Task beforeExecute---")

    }

    @Override
    void afterExecute(Task task, TaskState state) {
        println("---Gradle:Task afterExecute---")
    }
})

7.3 より前では利用できましたが、7.3 以降は廃止されました。コンパイル エラーが発生します。これは、構成キャッシュの場合、構成キャッシュが有効かどうかに関係なく API の一貫性を確保するには、構成キャッシュを強制終了する必要があるためです。 ..

Gradle はコンパイルを高速化するために多くの犠牲を払っており、開発と適応には間違いなく再び苦情が来るでしょう...

タスクは Gradle の最小の構築単位であり、アクションは最小の実行単位です。フック タスク アクションの実行に
追加できます。TaskActionListener

gradle.addBuildListener(new TaskActionListener(){

    @Override
    void beforeActions(Task task) {
        println("---Gradle:Task beforeActions---")
    }

    @Override
    void afterActions(Task task) {
        println("---Gradle:Task afterActions---")
    }
})

TaskExecutionListener と同様に、これも強制終了され、コンパイル時にエラーが報告されました。

@deprecated このタイプは、構成キャッシュが有効な場合にはサポートされません。

5.4、工事終了

すべてのタスクが実行されると、構築が終了したことを意味し、コールバックが呼び出されますgradle.buildFinished

gradle.buildFinished {
    println("---Gradle:buildFinished 构建结束了")
}

これも放棄され、理由は上記と同じですが、コンパイルではエラーが報告されません...

gradle.xxx の方法でフックポイントを追加する以外に、 を使用することもできgradle.addListener()、効果は同じです。

gradle.addListener(new BuildListener() {
    @Override
    void settingsEvaluated(Settings settings) {

    }

    @Override
    void projectsLoaded(Gradle gradle) {

    }

    @Override
    void projectsEvaluated(Gradle gradle) {

    }

    @Override
    void buildFinished(BuildResult result) {

    }
})

5.4.1. 全体的な出力

全体的な出力を見て、Gradle のライフ サイクルとビルド プロセスをさらに体験してください。

Executing tasks: [:app:assembleDebug] in project /Users/yechao/AndroidStudioProjects/GradleX

---Gradle:开始初始化了
---Gradle:settingsEvaluated Settings对象评估完毕
---Gradle:projectsLoaded 准备加载Project对象了

> Configure project :
---Gradle:Projec beforeEvaluate Project开始评估,对象是 = GradleX
---Gradle:Projec afterEvaluate Project评估完毕,对象是 = GradleX

> Configure project :app
---Gradle:Projec beforeEvaluate Project开始评估,对象是 = app
---Gradle:Projec afterEvaluate Project评估完毕,对象是 = app
---project:afterEvaluate Project评估完毕,对象是 = app
---Gradle:projectsEvaluated 所有Project对象评估完毕

> Task :app:createDebugVariantModel UP-TO-DATE
> Task :app:preBuild UP-TO-DATE
...
> Task :app:assembleDebug
---Gradle:buildFinished 构建结束了

BUILD SUCCESSFUL in 3s
33 actionable tasks: 12 executed, 21 up-to-date

Build Analyzer results available

5.4.2、適応方法

TaskActionListener と buildFinished が破棄された後、何を置き換えますか? Gradle は、Build Serviceそれらを置き換える方法を提供します。

ビルド サービスを使用すると、タスクの実行中にイベントを受信できます。これを行うには、OperationCompletionListener を実装するビルド サービスを作成して登録します。その後、サービスの BuildEventsListenerRegistry メソッドを使用してイベントの受信を開始できます。

もっと複雑に思えます...
これは何を意味するのでしょうか? BuildEventsListenerRegistry とは何ですか? 「メソッド」はどのように使用すればよいですか?
例:

// build.gradle.kts

abstract class BuildListenerService :
    BuildService<BuildListenerService.Params>,
    org.gradle.tooling.events.OperationCompletionListener {

    interface Params : BuildServiceParameters

    override fun onFinish(event: org.gradle.tooling.events.FinishEvent) {
        println("BuildListenerService got event $event")
    }
}

val buildServiceListener = gradle.sharedServices.registerIfAbsent("buildServiceListener", BuildListenerService::class.java) { }

abstract class Services @Inject constructor(
    val buildEventsListenerRegistry: BuildEventsListenerRegistry
)

val services = objects.newInstance(Services::class)

services.buildEventsListenerRegistry.onTaskCompletion(buildServiceListener)

出力:

> Task :service:vp:assemble UP-TO-DATE
> Task :assemble UP-TO-DATE
> Task :service:arc:processResources NO-SOURCE
> Task :service:ar:processResources UP-TO-DATE
> Task :service:ara:processResources UP-TO-DATE
BuildListenerService got event Task :service:vp:assemble UP-TO-DATE
BuildListenerService got event Task :assemble UP-TO-DATE
BuildListenerService got event Task :service:arc:processResources skipped
BuildListenerService got event Task :service:ar:processResources UP-TO-DATE
BuildListenerService got event Task :service:ara:processResources UP-TO-DATE
> Task :service:ti:kaptGenerateStubsKotlin UP-TO-DATE
BuildListenerService got event Task :service:ti:kaptGenerateStubsKotlin UP-TO-DATE
> Task :service:ac:kaptGenerateStubsKotlin UP-TO-DATE
BuildListenerService got event Task :service:ac:kaptGenerateStubsKotlin UP-TO-DATE
> Task :service:ti:kaptKotlin UP-TO-DATE
BuildListenerService got event Task :service:ti:kaptKotlin UP-TO-DATE
> Task :service:ti:compileKotlin NO-SOURCE
BuildListenerService got event Task :service:ti:compileKotlin skipped
> Task :service:ti:compileJava NO-SOURCE
BuildListenerService got event Task :service:ti:compileJava skipped
> Task :service:ti:processResources NO-SOURCE

外国人の友人からのサンプルもあります: BuildService + ProjectsEvaluated コールバックの例

TaskExecutionListener > BuildEventsListenerRegistry:

@Incubating
public interface BuildEventsListenerRegistry {
    /**
     * Subscribes the given listener to the finish events for tasks, if not already subscribed. The listener receives a {@link org.gradle.tooling.events.task.TaskFinishEvent} as each task completes.
     *
     * <p>The events are delivered to the listener one at a time, so the implementation does not need to be thread-safe. Also, events are delivered to the listener concurrently with
     * task execution and other work, so event handling does not block task execution. This means that a task finish event is delivered to the listener some time "soon" after the task
     * has completed. The events contain timestamps to allow you collect timing information.
     * </p>
     *
     * <p>The listener is automatically unsubscribed when the build finishes.</p>
     *
     * @param listener The listener to receive events. This must be a {@link org.gradle.api.services.BuildService} instance, see {@link org.gradle.api.services.BuildServiceRegistry}.
     */
    void onTaskCompletion(Provider<? extends OperationCompletionListener> listener);
}

buildFinished > OperationCompletionListener:

public interface OperationCompletionListener {
    /**
     * Called when an operation completes.
     */
    void onFinish(FinishEvent event);
}

6. 最後に

この記事では、まず Gradle ライフ サイクルの 3 つの段階と、これら 3 つの段階が何を行うかを紹介します。中心となるのは 3 つのオブジェクト (Gradle、Settings、Project) であり、最後に、これら 3 つの段階に対応するフック ポイントを紹介します。この記事を読み終えると、Gradle のライフサイクルと構築プロセスについてよりよく理解できるようになります。役に立った場合は、忘れずに 3 倍にしてください~

7、ギットハブ

https://github.com/yechaoa/GradleX

8. 関連資料

おすすめ

転載: blog.csdn.net/yechaoa/article/details/130277978