Gradle eklentileri yazma

Android Gradle eklentisi (AGP), Android uygulamaları için resmi derleme sistemidir. Birçok farklı kaynak türünü derleme ve bunları fiziksel bir Android cihazda veya emülatörde çalıştırabileceğiniz bir uygulamaya bağlama desteği içerir.

AGP, eklentilerin derleme girişlerini kontrol etmesi ve standart derleme görevleriyle entegre edilebilecek yeni adımlar aracılığıyla işlevlerini genişletmesi için uzantı noktaları içerir. AGP'nin önceki sürümlerinde, resmi API'ler dahili uygulamalardan net bir şekilde ayrılmamıştı. 7.0 sürümünden itibaren AGP'de güvenebileceğiniz bir dizi resmi ve kararlı API bulunur.

AGP API yaşam döngüsü

AGP, API'lerinin durumunu belirlemek için Gradle özellik yaşam döngüsünü izler:

  • Dahili: Herkese açık kullanıma yönelik değildir.
  • Kuluçka: Herkese açık olarak kullanılabilir ancak nihai sürüm değildir. Bu nedenle, nihai sürümde geriye dönük uyumlu olmayabilir.
  • Herkese açık: Herkese açık ve kararlı
  • Desteği sonlandırıldı: Artık desteklenmiyor ve yeni API'lerle değiştirildi.

Kullanımdan kaldırma politikası

AGP, eski API'lerin kullanımdan kaldırılması ve bunların yerine yeni, kararlı API'lerin ve yeni bir alana özgü dilin (DSL) getirilmesiyle gelişiyor. Bu gelişim birden fazla AGP sürümünü kapsayacak ve bu konuda daha fazla bilgiyi AGP API/DSL taşıma zaman çizelgesinde bulabilirsiniz.

AGP API'leri bu taşıma işlemi için veya başka bir nedenle kullanımdan kaldırıldığında mevcut ana sürümde kullanılmaya devam edecek ancak uyarılar oluşturacaktır. Desteği sonlandırılan API'ler, bir sonraki ana sürümde AGP'den tamamen kaldırılacaktır. Örneğin, bir API AGP 7.0'da kullanımdan kaldırılırsa bu sürümde kullanılabilir ve uyarılar oluşturur. Bu API, AGP 8.0'da artık kullanılamayacak.

Yaygın derleme özelleştirmelerinde kullanılan yeni API'lerin örnekleri için Android Gradle eklentisi tarifleri'ne bakın. Yaygın derleme özelleştirmeleriyle ilgili örnekler sunarlar. Yeni API'lerle ilgili daha fazla bilgiyi referans belgelerimizde bulabilirsiniz.

AGP API yapısına göre derleme

AGP'yi genişleten özel bir Gradle eklentisi veya derleme mantığı (ör. buildSrc dizininde, kural eklenti modülünde veya bağımsız bir eklenti projesinde) yazmak için tam eklenti uygulama yapısı yerine AGP'nin gradle-api yapısına göre derleyin.

Neden gradle-api yapısına karşı derleme yapmalısınız?

AGP iki ana yapı yayınlar:

  • com.android.tools.build:gradle-api: Kararlı API'ler (ör. AndroidComponentsExtension, Variant ve herkese açık DSL arayüzleri), kuluçka aşamasındaki API'ler (@Incubating olarak işaretlenir) ve desteği sonlandırılmış API'ler (@Deprecated olarak işaretlenir) dahil olmak üzere resmi AGP API'lerini içerir.
  • com.android.tools.build:gradle: Dahili sınıflar, derleme görevleri ve derleyici entegrasyonları dahil olmak üzere AGP çalışma zamanı uygulamasının tamamını içerir.

gradle-api yapısına karşı derleme yapmanın birkaç önemli avantajı vardır:

  • Dahili API'lerden kaçınma: Eklenti kodunuzun yalnızca resmi API'lere erişmesini sağlar. Bu sayede, AGP sürümleri arasında uyarı yapılmadan değiştirilebilen veya kaldırılabilen dahili uygulama sınıflarına (com.android.build.gradle.internal.*) yanlışlıkla bağımlılık oluşturulması önlenir.
  • Daha hızlı derlemeler ve daha küçük ayak izi: gradle-api yapısı, tam gradle yapısına kıyasla çok daha küçük bir bağımlılık ağacına sahiptir. Bu sayede indirme boyutları küçülür, sınıf yolu kirliliği önlenir ve derleme mantığınızın derlenmesi hızlanır.
  • Çalışma zamanı izolasyonu: Özel eklentiler, yalnızca derleme sırasında API tanımları gerektirir. Çalışma zamanında, Android uygulaması veya kitaplık eklentisi uygulandığında Android derlemesi tarafından tam AGP uygulaması sağlanır.

Bağımlılığı ekleme

gradle-api yapısını, eklenti projenizin derleme dosyasına veya buildSrc dizinine bağımlılık olarak ekleyin. gradle-api yapısı, Google'ın Maven deposunda yayınlanır. Yapı sorununu çözmek için derlemenizin google() deposunu içerdiğinden emin olun. Örneğin, settings.gradle veya settings.gradle.kts dosyasının dependencyResolutionManagement.repositories bloğunda ya da eklentinizin derleme dosyasının repositories bloğunda veya buildSrc dizininin derleme dosyasında yapılandırın.

Sürüm kataloğu ile

Projeniz sürüm kataloğu kullanıyorsa gradle/libs.versions.toml dosyasında gradle-api bağımlılığını tanımlayın:

[versions]
androidGradlePlugin = "9.5.0"

[libraries]
android-gradle-plugin-api = { group = "com.android.tools.build", name = "gradle-api", version.ref = "androidGradlePlugin" }

android-gradle-plugin-api katalog takma adı, tür güvenli erişimciyi libs.android.gradle.plugin.api oluşturur.

Ardından, eklentinizin derleme dosyasının dependencies bloğuna libs.android.gradle.plugin.api öğesini ekleyin:

Kotlin

dependencies {
    compileOnly(libs.android.gradle.plugin.api)
}

Modern

dependencies {
    compileOnly libs.android.gradle.plugin.api
}

Sürüm kataloğu olmadan

Projeniz sürüm kataloğu kullanmıyorsa bağımlılığı doğrudan eklentinizin derleme dosyasında tanımlayın:

Kotlin

dependencies {
    compileOnly("com.android.tools.build:gradle-api:9.5.0")
}

Modern

dependencies {
    compileOnly 'com.android.tools.build:gradle-api:9.5.0'
}

Yayınlanması amaçlanan bağımsız eklentiler için varsayılan olarak compileOnly yapılandırma seçeneğini kullanın. Tüketen proje, AGP'yi uygular ve çalışma zamanı sınıflarını buildscript sınıf yolunda sağlar. compileOnly yapılandırmasını kullanmak, yayınlanan eklentinizin belirli bir AGP sürümüne çalışma zamanı bağımlılığı sızdırmasını önler ve tüketiciler için sürüm çakışmalarını engeller. buildSrc dizinindeki eklentiler veya bileşik derlemelerdeki kural eklentileri gibi dahili derleme mantığı geliştiriyorsanız bunun yerine implementation yapılandırma seçeneğini kullanın. Bu eklentiler derleme içinde çalışır ve çalışma zamanı sınıf yolunda AGP gerektirir.

Gradle derleme ile ilgili temel bilgiler

Bu kılavuz, Gradle derleme sisteminin tamamını kapsamaz. Ancak API'lerimizle entegrasyon yapmanıza yardımcı olacak minimum gerekli kavram grubunu kapsar ve daha fazla bilgi için ana Gradle belgelerine bağlantı verir.

Projeleri yapılandırma, derleme dosyalarını düzenleme, eklenti uygulama ve görevleri çalıştırma gibi Gradle'ın işleyiş şekliyle ilgili temel bilgilere sahip olduğunuzu varsayıyoruz. AGP ile ilgili olarak Gradle'ın temel özellikleri hakkında bilgi edinmek için Derlemenizi yapılandırma başlıklı makaleyi okumanızı öneririz. Özel Gradle eklentilerini özelleştirmeyle ilgili genel çerçeve hakkında bilgi edinmek için Özel Gradle Eklentileri Geliştirme başlıklı makaleyi inceleyin.

Gradle tembel türler sözlüğü

Gradle,"gecikmeli" davranan veya ağır hesaplamaları ya da Task oluşturma işlemini derlemenin sonraki aşamalarına ertelemeye yardımcı olan çeşitli türler sunar. Bu türler, birçok Gradle ve AGP API'sinin temelini oluşturur. Aşağıdaki listede, geç yürütme işleminde yer alan ana Gradle türleri ve bunların temel yöntemleri yer almaktadır.

Provider<T>

Yürütme aşamasında get() kullanılarak okunabilen veya map(), flatMap() ve zip() yöntemleri kullanılarak yeni bir Provider<S> ("S" başka bir türü ifade eder) değerine dönüştürülebilen T türünde ("T" herhangi bir türü ifade eder) bir değer sağlar. Yapılandırma aşamasında get() yönteminin hiçbir zaman çağrılmaması gerektiğini unutmayın.

  • map(): Bir lambda kabul eder ve S, Provider<S> türünde bir Provider oluşturur. map() için lambda bağımsız değişkeni T değerini alır ve S değerini üretir. Lambda hemen yürütülmez. Bunun yerine, yürütme işlemi sonuçta elde edilen Provider<S> üzerinde get() çağrıldığı ana ertelenir. Bu da tüm zinciri geçici hale getirir.
  • flatMap(): Ayrıca bir lambda kabul eder ve Provider<S> üretir ancak lambda, T değerini alır ve Provider<S> üretir (doğrudan S değerini üretmek yerine). S, yapılandırma sırasında belirlenemediğinde ve yalnızca Provider<S> değerini alabildiğinizde flatMap() kullanın. Pratik olarak, map() kullandıysanız ve Provider<Provider<S>> sonuç türü elde ettiyseniz bu, muhtemelen bunun yerine flatMap() kullanmanız gerektiği anlamına gelir.
  • zip(): İki Provider örneğini birleştirerek yeni bir Provider oluşturmanızı sağlar. Bu yeni örneğin değeri, iki giriş Provider örneğinin değerlerini birleştiren bir işlev kullanılarak hesaplanır.
Property<T>

Provider<T> öğesini uygular. Bu nedenle, T türünde bir değer de sağlar. Salt okunur olan Provider<T> parametresinin aksine, Property<T> parametresi için bir değer de ayarlayabilirsiniz. Bunu yapmanın iki yolu vardır:

  • Mümkün olduğunda, ertelenmiş hesaplamalara gerek kalmadan doğrudan T türünde bir değer ayarlayın.
  • Property<T> değerinin kaynağı olarak başka bir Provider<T> ayarlayın. Bu durumda, T değeri yalnızca Property.get() çağrıldığında somutlaştırılır.
TaskProvider
Uygulama Provider<Task>. TaskProvider oluşturmak için tasks.create() yerine tasks.register() kullanın. Böylece görevler yalnızca gerektiğinde örneklendirilir. flatMap() kullanarak bir Task oluşturulmadan önce çıkışlarına erişebilirsiniz. Bu, çıkışları diğer Task örneklerinin girişleri olarak kullanmak istediğinizde yararlı olabilir.Task

Sağlayıcılar ve bunların dönüştürme yöntemleri, görevlerin giriş ve çıkışlarını geç bir şekilde ayarlamak için gereklidir. Yani tüm görevleri önceden oluşturup değerleri çözmeye gerek yoktur.

Sağlayıcılar, görev bağımlılığı bilgilerini de taşır. Bir Task çıkışını dönüştürerek Provider oluşturduğunuzda, bu Task, Provider'nin dolaylı bir bağımlılığı haline gelir ve Provider'nin değeri çözümlendiğinde (ör. başka bir Task bunu gerektirdiğinde) oluşturulup çalıştırılır.

Aşağıda, GitVersionTask ve ManifestProducerTask adlı iki görevin kaydedilmesine ve Task örneklerinin oluşturulmasının gerçekten gerekli olana kadar ertelenmesine dair bir örnek verilmiştir. ManifestProducerTask giriş değeri, GitVersionTask çıkışından elde edilen bir Provider değerine ayarlanır. Bu nedenle ManifestProducerTask, dolaylı olarak GitVersionTask değerine bağlıdır.

// Register a task lazily to get its TaskProvider.
val gitVersionProvider: TaskProvider =
    project.tasks.register("gitVersionProvider", GitVersionTask::class.java) {
        it.gitVersionOutputFile.set(
            File(project.buildDir, "intermediates/gitVersionProvider/output")
        )
    }

...

/**
 * Register another task in the configuration block (also executed lazily,
 * only if the task is required).
 */
val manifestProducer =
    project.tasks.register(variant.name + "ManifestProducer", ManifestProducerTask::class.java) {
        /**
         * Connect this task's input (gitInfoFile) to the output of
         * gitVersionProvider.
         */
        it.gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile))
    }

Bu iki görev yalnızca açıkça istendiğinde yürütülür. Bu durum, Gradle çağrısının bir parçası olarak gerçekleşebilir. Örneğin, ./gradlew debugManifestProducer komutunu çalıştırırsanız veya ManifestProducerTask çıkışı başka bir göreve bağlanırsa ve değeri gerekli hale gelirse bu durum yaşanabilir.

Girişleri kullanan, çıkışlar üreten veya her ikisini birden yapan özel görevler yazacak olsanız da AGP, kendi görevlerine doğrudan herkese açık erişim sunmaz. Bunlar, sürümler arasında değişebilen bir uygulama ayrıntısıdır. Bunun yerine AGP, Variant API'yi ve okuyup dönüştürebileceğiniz görevlerinin çıktısına veya derleme yapılarına erişim imkanı sunar. Daha fazla bilgi için bu belgedeki Variant API, Artifacts, and Tasks (Variant API, Yapılar ve Görevler) bölümüne bakın.

Gradle derleme aşamaları

Proje oluşturmak doğası gereği karmaşık ve kaynak gerektiren bir süreçtir. Görev yapılandırmasından kaçınma, güncel kontroller ve yapılandırma önbelleğe alma özelliği gibi çeşitli özellikler, tekrarlanabilir veya gereksiz hesaplamalara harcanan süreyi en aza indirmeye yardımcı olur.

Bu optimizasyonlardan bazılarını uygulamak için Gradle komut dosyaları ve eklentileri, farklı Gradle derleme aşamalarının (başlatma, yapılandırma ve yürütme) her birinde katı kurallara uymalıdır. Bu kılavuzda, yapılandırma ve yürütme aşamalarına odaklanacağız. Tüm aşamalar hakkında daha fazla bilgiyi Gradle derleme yaşam döngüsü kılavuzunda bulabilirsiniz.

Yapılandırma aşaması

Yapılandırma aşamasında, derlemenin parçası olan tüm projelerin derleme komut dosyaları değerlendirilir, eklentiler uygulanır ve derleme bağımlılıkları çözümlenir. Bu aşama, derlemeyi DSL nesneleri kullanarak yapılandırmak ve görevleri ve girişlerini geç kaydetmek için kullanılmalıdır.

Yapılandırma aşaması, hangi görevin çalıştırılması istendiğine bakılmaksızın her zaman çalıştırılır. Bu nedenle, bu aşamayı yalın tutmak ve hesaplamaların derleme komut dosyaları dışındaki girişlere bağlı olmasını kısıtlamak özellikle önemlidir. Yani harici programları çalıştırmamalı, ağdan okuma yapmamalı veya uygun Task örnekleri olarak yürütme aşamasına ertelenebilecek uzun hesaplamalar yapmamalısınız.

Yürütme aşamasında

Yürütme aşamasında, istenen görevler ve bunlara bağlı görevler yürütülür. Özellikle, @TaskAction ile işaretlenmiş Task sınıf yöntemleri yürütülür. Görev yürütme sırasında girişlerden (ör. dosyalar) okuma yapabilir ve Provider<T>.get() yöntemini çağırarak geç yüklenen sağlayıcıları çözebilirsiniz. Yavaş sağlayıcıları bu şekilde çözmek, sağlayıcıda bulunan görev bağımlılığı bilgilerini izleyen bir dizi map() veya flatMap() çağrısı başlatır. Görevler, gerekli değerleri gerçekleştirmek için geç çalıştırılır.

Variant API, yapılar ve görevler

Variant API, Android Gradle eklentisindeki bir uzantı mekanizmasıdır. Bu mekanizma, normalde derleme yapılandırma dosyalarında DSL kullanılarak ayarlanan ve Android derlemesini etkileyen çeşitli seçenekleri değiştirmenize olanak tanır. Variant API, derleme tarafından oluşturulan ara ve nihai yapılara (ör. sınıf dosyaları, birleştirilmiş manifest veya APK/AAB dosyaları) erişmenizi de sağlar.

Android derleme akışı ve uzantı noktaları

AGP ile etkileşim kurarken tipik Gradle yaşam döngüsü geri çağırma yöntemlerini (ör. afterEvaluate()) kaydetmek veya açık Task bağımlılıkları ayarlamak yerine özel olarak oluşturulmuş uzantı noktalarını kullanın. AGP tarafından oluşturulan görevler, uygulama ayrıntıları olarak kabul edilir ve herkese açık bir API olarak gösterilmez. Task nesnelerinin örneklerini almaya çalışmaktan veya Task adlarını tahmin edip bu Task nesnelerine doğrudan geri çağırmalar ya da bağımlılıklar eklemekten kaçınmanız gerekir.

AGP, Task örneklerini oluşturup yürütmek için aşağıdaki adımları tamamlar. Bu örnekler de derleme yapılarını oluşturur. Variant nesnesi oluşturma işleminin ana adımlarından sonra, derleme kapsamında oluşturulan belirli nesnelerde değişiklik yapmanıza olanak tanıyan geri çağırmalar gelir. Tüm geri çağırmaların yapılandırma aşamasında (bu sayfada açıklanmıştır) gerçekleştiğini ve hızlı bir şekilde çalışması gerektiğini unutmayın. Karmaşık işler, yürütme aşamasında uygun Task örneklerine ertelenir.

  1. DSL ayrıştırma: Derleme komut dosyalarının değerlendirildiği ve android bloğundaki Android DSL nesnelerinin çeşitli özelliklerinin oluşturulup ayarlandığı aşamadır. Aşağıdaki bölümlerde açıklanan Variant API geri çağırmaları da bu aşamada kaydedilir.

    • finalizeDsl(): Bileşen (varyant) oluşturma için kilitlenmeden önce DSL nesnelerini değiştirmenize olanak tanıyan geri çağırma. VariantBuilder nesneleri, DSL nesnelerinde bulunan verilere göre oluşturulur.
  2. DSL kilitleme: DSL artık kilitlidir ve değişiklik yapılamaz.

    • beforeVariants(): Bu geri çağırma, VariantBuilder aracılığıyla hangi bileşenlerin oluşturulacağını ve bunların bazı özelliklerini etkileyebilir. Yine de derleme akışında ve üretilen yapılarda değişiklik yapılmasına izin verir.
  3. Varyant oluşturma: Oluşturulacak bileşenlerin ve yapıların listesi artık kesinleşmiştir ve değiştirilemez.

    • onVariants(): Bu geri çağırmada, oluşturulan Variant nesnelerine erişebilir ve içerdikleri Property değerleri için değerler veya sağlayıcılar ayarlayabilirsiniz. Bu değerler, gerektiğinde hesaplanır.
  4. Varyant kilitleme: Varyant nesneleri artık kilitlidir ve değişiklik yapılamaz.

  5. Oluşturulan görevler: Derleme işlemini gerçekleştirmek için gereken Task örneklerini oluşturmak üzere Variant nesneleri ve bunların Property değerleri kullanılır.

AGP, finalizeDsl(), beforeVariants() ve onVariants() için geri çağırmaları kaydetmenize olanak tanıyan bir AndroidComponentsExtension sunar. Uzantı, androidComponents bloğu aracılığıyla derleme komut dosyalarında kullanılabilir:

// This is used only for configuring the Android build through DSL.
android { ... }

// The androidComponents block is separate from the DSL.
androidComponents {
   finalizeDsl { extension ->
      ...
   }
}

Ancak derleme komut dosyalarını yalnızca android bloğunun DSL'sini kullanan açıklayıcı yapılandırma için tutmanızı ve tüm özel zorunlu mantığı buildSrc dizinine veya harici eklentilere taşımanızı öneririz. Projenizde nasıl eklenti oluşturacağınızı öğrenmek için Gradle tarifleri GitHub depomuzdaki buildSrc örneklerine de göz atabilirsiniz. Eklentinizin, derleme dosyanızdaki gradle-api yapısına göre derlendiğinden emin olun. Aşağıda, eklenti kodundan geri çağırmaları kaydetme örneği verilmiştir:

abstract class ExamplePlugin: Plugin<Project> {

    override fun apply(project: Project) {
        val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
        androidComponents.finalizeDsl { extension ->
            ...
        }
    }
}

Aşağıdaki bölümlerde, kullanılabilir geri çağırmalar ve eklentinizin her birinde destekleyebileceği kullanım alanı türleri açıklanmaktadır:

finalizeDsl(callback: (DslExtensionT) -> Unit)

Bu geri çağırmada, derleme dosyalarındaki android bloğundan bilgileri ayrıştırarak oluşturulan DSL nesnelerine erişebilir ve bunları değiştirebilirsiniz. Bu DSL nesneleri, derlemenin sonraki aşamalarında varyantları ilk kullanıma hazırlamak ve yapılandırmak için kullanılır. Örneğin, programatik olarak yeni yapılandırmalar oluşturabilir veya özellikleri geçersiz kılabilirsiniz. Ancak tüm değerlerin yapılandırma sırasında çözümlenmesi gerektiğinden, harici girişlere bağlı olmamaları gerektiğini unutmayın. Bu geri çağırma işlemi tamamlandıktan sonra DSL nesneleri artık kullanışlı olmaz ve bunlara referans vermemeniz veya değerlerini değiştirmemeniz gerekir.

abstract class ExamplePlugin: Plugin<Project> {

    override fun apply(project: Project) {
        val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
        androidComponents.finalizeDsl { extension ->
            extension.buildTypes.create("extra").let {
                it.isJniDebuggable = true
            }
        }
    }
}

beforeVariants()

Derlemenin bu aşamasında, oluşturulacak varyantları ve özelliklerini belirleyen VariantBuilder nesnelerine erişebilirsiniz. Örneğin, belirli varyantları ve testlerini programatik olarak devre dışı bırakabilir veya bir özelliğin değerini (ör. minSdk) yalnızca seçilen bir varyant için değiştirebilirsiniz. finalizeDsl() parametresine benzer şekilde, sağladığınız tüm değerlerin yapılandırma sırasında çözümlenmesi ve harici girişlere bağlı olmaması gerekir. beforeVariants() geri çağırma işlevinin yürütülmesi tamamlandıktan sonra VariantBuilder nesneleri değiştirilmemelidir.

androidComponents {
    beforeVariants { variantBuilder ->
        variantBuilder.minSdk = 23
    }
}

beforeVariants() geri çağırma işlevi, isteğe bağlı olarak androidComponentsExtension üzerindeki selector() yöntemiyle elde edebileceğiniz bir VariantSelector alır. Bu özelliği, geri çağırma çağrısına katılan bileşenleri adlarına, derleme türlerine veya ürün türlerine göre filtrelemek için kullanabilirsiniz.

androidComponents {
    beforeVariants(selector().withName("adfree")) { variantBuilder ->
        variantBuilder.minSdk = 23
    }
}

onVariants()

onVariants() çağrıldığında AGP tarafından oluşturulacak tüm yapılar zaten belirlenmiş olduğundan bunları artık devre dışı bırakamazsınız. Ancak görevler için kullanılan değerlerden bazılarını, Variant nesnelerindeki Property özellikleri için ayarlayarak değiştirebilirsiniz. Property değerleri yalnızca AGP'nin görevleri yürütüldüğünde çözümleneceğinden, bunları kendi özel görevlerinizdeki sağlayıcılara güvenle bağlayabilirsiniz. Bu görevler, dosya veya ağ gibi harici girişlerden okuma dahil olmak üzere gerekli tüm hesaplamaları gerçekleştirir.

// onVariants also supports VariantSelectors:
onVariants(selector().withBuildType("release")) { variant ->
    // Gather the output when we are in single mode (no multi-apk).
    val mainOutput = variant.outputs.single { it.outputType == OutputType.SINGLE }

    // Create version code generating task
    val versionCodeTask = project.tasks.register("computeVersionCodeFor${variant.name}", VersionCodeTask::class.java) {
        it.outputFile.set(project.layout.buildDirectory.file("${variant.name}/versionCode.txt"))
    }
    /**
     * Wire version code from the task output.
     * map() will create a lazy provider that:
     * 1. Runs just before the consumer(s), ensuring that the producer
     * (VersionCodeTask) has run and therefore the file is created.
     * 2. Contains task dependency information so that the consumer(s) run after
     * the producer.
     */
    mainOutput.versionCode.set(versionCodeTask.map { it.outputFile.get().asFile.readText().toInt() })
}

Oluşturulan kaynakları derlemeye ekleme

Eklentiniz, aşağıdaki gibi birkaç türde oluşturulmuş kaynak sağlayabilir:

Ekleyebileceğiniz kaynakların tam listesi için Sources API'ye bakın.

Bu kod snippet'i, addStaticSourceDirectory() işlevini kullanarak Java kaynak grubuna ${variant.name} adlı özel bir kaynak klasörünün nasıl ekleneceğini gösterir. Android araç zinciri daha sonra bu klasörü işler.

onVariants { variant ->
    variant.sources.java?.let { java ->
        java.addStaticSourceDirectory("custom/src/kotlin/${variant.name}")
    }
}

Daha fazla bilgi için addJavaSource tarifini inceleyin.

Bu kod snippet'i, özel bir görevden oluşturulan Android kaynaklarını içeren bir dizinin res kaynak grubuna nasıl ekleneceğini gösterir. Süreç diğer kaynak türleri için de benzerdir.

onVariants(selector().withBuildType("release")) { variant ->
    // Step 1. Register the task.
    val resCreationTask =
       project.tasks.register<ResCreatorTask>("create${variant.name}Res")

    // Step 2. Register the task output to the variant-generated source directory.
    variant.sources.res?.addGeneratedSourceDirectory(
       resCreationTask,
       ResCreatorTask::outputDirectory)
    }

...

// Step 3. Define the task.
abstract class ResCreatorTask: DefaultTask() {
   @get:OutputFiles
   abstract val outputDirectory: DirectoryProperty

   @TaskAction
   fun taskAction() {
      // Step 4. Generate your resources.
      ...
   }
}

Daha fazla bilgi için addCustomAsset tarifine bakın.

Yapılara erişme ve yapıları değiştirme

AGP, Variant nesnelerindeki temel özellikleri değiştirmenize olanak tanımanın yanı sıra derleme sırasında üretilen ara ve nihai yapıları okumanızı veya dönüştürmenizi sağlayan bir uzantı mekanizması da içerir. Örneğin, birleştirilmiş nihai AndroidManifest.xml dosya içeriklerini özel bir Task içinde okuyarak analiz edebilir veya içeriğini tamamen özel Task tarafından oluşturulan bir manifest dosyasının içeriğiyle değiştirebilirsiniz.

Şu anda desteklenen yapıların listesini Artifact sınıfının referans belgelerinde bulabilirsiniz. Her ürün türünün bilinmesi faydalı olan belirli özellikleri vardır:

Nicelik

Bir Artifact öğesinin kardinalitesi, FileSystemLocation örneklerinin sayısını veya yapı türünün dosya ya da dizin sayısını temsil eder. Bir yapının kardinalitesi hakkında bilgi edinmek için üst sınıfını kontrol edebilirsiniz: Tek bir FileSystemLocation içeren yapılar Artifact.Single'nin alt sınıfı, birden fazla FileSystemLocation örneği içeren yapılar ise Artifact.Multiple'nin alt sınıfı olur.

FileSystemLocation türü

Bir Artifact öğesinin dosyaları mı yoksa dizinleri mi temsil ettiğini, parametreleştirilmiş FileSystemLocation türüne bakarak kontrol edebilirsiniz. Bu tür, RegularFile veya Directory olabilir.

Desteklenen işlemler

Her Artifact sınıfı, desteklediği işlemleri belirtmek için aşağıdaki arayüzlerden herhangi birini uygulayabilir:

  • Transformable: Bir Artifact öğesinin, üzerinde rastgele dönüşümler gerçekleştiren ve Artifact öğesinin yeni bir sürümünü oluşturan bir Task öğesine giriş olarak kullanılmasına olanak tanır.
  • Appendable: Yalnızca Artifact.Multiple alt sınıfları olan yapılar için geçerlidir. Bu, Artifact öğesine ekleme yapılabileceği, yani özel bir Task öğesinin bu Artifact türünde yeni örnekler oluşturabileceği ve bu örneklerin mevcut listeye ekleneceği anlamına gelir.
  • Replaceable: Yalnızca Artifact.Single alt sınıfları olan yapılar için geçerlidir. Değiştirilebilir bir Artifact, Task sonucunda üretilen tamamen yeni bir örnekle değiştirilebilir.

Öğeyi değiştiren üç işleme ek olarak her öğe, öğenin son sürümünü (üzerindeki tüm işlemler tamamlandıktan sonra) içeren bir Provider döndüren get() (veya getAll()) işlemini destekler.

Birden fazla eklenti, onVariants() geri çağırma işlevinden ardışık düzene herhangi bir sayıda yapı işlemi ekleyebilir. AGP, tüm görevlerin doğru zamanda çalışması ve yapıların doğru şekilde üretilip güncellenmesi için bunların doğru şekilde zincirlenmesini sağlar. Bu, bir işlem herhangi bir çıkışı ekleyerek, değiştirerek veya dönüştürerek değiştirdiğinde, sonraki her işlemin bu yapıların güncellenmiş sürümünü giriş olarak göreceği anlamına gelir.

İşlemleri kaydetmenin giriş noktası Artifacts sınıfıdır. Aşağıdaki kod snippet'i, onVariants() geri çağırma işlevindeki Variant nesnesinin bir özelliğinden Artifacts örneğine nasıl erişebileceğinizi gösterir.

Ardından, özel TaskProvider değerinizi ileterek bir TaskBasedOperation nesnesi (1) alabilir ve wiredWith* yöntemlerinden birini (2) kullanarak giriş ve çıkışlarını bağlamak için bu nesneyi kullanabilirsiniz.

Seçmeniz gereken yöntem, dönüştürmek istediğiniz Artifact tarafından uygulanan kardinaliteye ve FileSystemLocation türüne bağlıdır.

Son olarak, Artifact türünü, karşılığında aldığınız *OperationRequest nesnesinde seçilen işlemi temsil eden bir yönteme (ör. toAppendTo(), toTransform() veya toCreate()) iletirsiniz (3).

androidComponents.onVariants { variant ->
    val manifestUpdater = // Custom task that will be used for the transform.
            project.tasks.register(variant.name + "ManifestUpdater", ManifestTransformerTask::class.java) {
                it.gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile))
            }
    // (1) Register the TaskProvider w.
    val variant.artifacts.use(manifestUpdater)
         // (2) Connect the input and output files.
        .wiredWithFiles(
            ManifestTransformerTask::mergedManifest,
            ManifestTransformerTask::updatedManifest)
        // (3) Indicate the artifact and operation type.
        .toTransform(SingleArtifact.MERGED_MANIFEST)
}

Bu örnekte MERGED_MANIFEST bir SingleArtifact ve RegularFile. Bu nedenle, giriş için tek bir RegularFileProperty referansı ve çıkış için tek bir RegularFileProperty kabul eden wiredWithFiles yöntemini kullanmamız gerekir. TaskBasedOperation sınıfında, diğer Artifact kardinalite ve FileSystemLocation türü kombinasyonları için kullanılabilecek başka wiredWith* yöntemleri de vardır.

AGP'yi genişletme hakkında daha fazla bilgi edinmek için Gradle derleme sistemi kılavuzundaki aşağıdaki bölümleri okumanızı öneririz: