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 uygulamada birbirine bağlama desteği içerir.

AGP, eklentilerin derleme girişlerini kontrol etmesi ve standart derleme görevleriyle entegre edilebilen yeni adımlar aracılığıyla işlevselliğini 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ı. AGP, 7.0 sürümünden itibaren güvenebileceğiniz bir dizi resmi ve kararlı API'ye sahiptir.

AGP API yaşam döngüsü

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

  • Dahili: Herkese açık kullanım için tasarlanmamıştır.
  • Geliştirme aşamasında: Herkese açık olarak kullanılabilir ancak son sürüm değildir. Bu nedenle, son sürümde geriye dönük uyumlu olmayabilir.
  • Herkese açık: Herkesin kullanımına 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 desteğinin sonlandırılması ve bunların yeni, kararlı API'ler ve yeni bir alana özgü dil (DSL) ile değiştirilmesiyle gelişiyor. Bu evrim, birden fazla AGP sürümünü kapsayacak. Bu konu hakkında daha fazla bilgiyi AGP API/DSL taşıma zaman çizelgesinde bulabilirsiniz.

AGP API'lerinin desteği sonlandırıldığında (bu taşıma işlemi veya başka bir nedenle), bu API'ler mevcut ana sürümde kullanılmaya devam edecek ancak uyarılar oluşturacak. Desteği sonlandırılan API'ler, sonraki ana sürümde AGP'den tamamen kaldırılacak. Örneğin, bir API AGP 7.0'da kullanımdan kaldırıldıysa 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 örneklerini görmek için Android Gradle eklentisi tariflerine göz atın. Sık karşılaşılan derleme özelleştirmeleriyle ilgili örnekler sunar. Yeni API'ler hakkında daha fazla bilgiyi referans belgelerimizde bulabilirsiniz.

AGP API yapıtına göre derleme

AGP'yi genişleten özel bir Gradle eklentisi veya derleme mantığı (ör. buildSrc dizininde, bir kural eklentisi 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 derleme yapın.

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

AGP iki temel yapıyı yayınlar:

  • com.android.tools.build:gradle-api: Kararlı API'ler (ör. AndroidComponentsExtension, Variant ve herkese açık DSL arayüzleri), geliştirme aşamasındaki API'ler (@Incubating ile işaretlenir) ve desteği sonlandırılan API'ler (@Deprecated ile 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ının tam uygulamasını içerir.

gradle-api yapıtına göre derleme yapmanın başlıca avantajları şunlardır:

  • Dahili API'lerden kaçının: Bu sayede eklenti kodunuzun yalnızca resmi API'lere erişmesi sağlanır. Bu sayede, AGP sürümlerinde 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ı olunması önlenir.
  • Daha hızlı derleme 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ıtını, eklenti projenizin derleme dosyasına veya buildSrc dizinine bağımlılık olarak ekleyin. gradle-api yapısı, Google'ın Maven deposunda yayınlanmıştır. Yapıyı çö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 veya buildSrc dizininin derleme dosyasının repositories bloğunda yapılandırın.

Sürüm kataloğuyla

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

[versions]
androidGradlePlugin = "9.4.0"

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

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

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

Projenizde sürüm kataloğu kullanılmıyorsa bağımlılığı doğrudan eklentinizin derleme dosyasında bildirin:

Kotlin

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

Modern

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

Yayınlanmak üzere tasarlanan 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ı, yayınlanan eklentinizin belirli bir AGP sürümünde ç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 derlemesiyle ilgili temel bilgiler

Bu kılavuzda Gradle derleme sisteminin tamamı ele alınmamaktadır. Ancak, API'lerimize entegre olmanıza yardımcı olacak minimum gerekli kavramlar kümesini kapsar ve daha fazla bilgi için ana Gradle dokümanlarına bağlantılar içerir.

Gradle'ın işleyişiyle ilgili temel bilgilere (ör. projeleri yapılandırma, derleme dosyalarını düzenleme, eklentileri uygulama ve görevleri çalıştırma) sahip olduğunuzu varsayıyoruz. AGP ile ilgili olarak Gradle'ın temelleri hakkında bilgi edinmek için Derlemenizi yapılandırma başlıklı makaleyi incelemenizi öneririz. Gradle eklentilerini özelleştirme ile ilgili genel çerçeve hakkında bilgi edinmek için Özel Gradle Eklentileri Geliştirme başlıklı makaleyi inceleyin.

Gradle tembel türleri sözlüğü

Gradle,"tembel" davranan veya ağır hesaplamaları ya da Task oluşturmayı 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 temel Gradle türleri ve bunların temel yöntemleri yer almaktadır.

Provider<T>
T türünde bir değer sağlar (burada "T" herhangi bir tür anlamına gelir). Bu değer, yürütme aşamasında get() kullanılarak okunabilir veya map(), flatMap() ve zip() yöntemleri kullanılarak yeni bir Provider<S> türüne (burada "S" başka bir tür anlamına gelir) dönüştürülebilir. get()'nın yapılandırma aşamasında asla çağrılmaması gerektiğini unutmayın.
  • map(): Provider türünde S, Provider<S> lambda kabul eder ve üretir. map() işlevinin 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ütülmesi sonuçtaki Provider<S> üzerinde get() çağrıldığında ertelenir ve bu da tüm zinciri tembel yapar.
  • flatMap(): Lambda işlevini de kabul eder ve Provider<S> değerini üretir ancak lambda işlevi T değerini alır ve Provider<S> değerini üretir (doğrudan S değerini üretmek yerine). S yapılandırma sırasında belirlenemediğinde ve yalnızca Provider<S> elde edebildiğinizde flatMap() işlevini kullanın. Pratik olarak konuşmak gerekirse map() kullandığınızda Provider<Provider<S>> sonuç türü elde ettiyseniz bunun nedeni muhtemelen flatMap() kullanmanız gerektiğidir.
  • zip(): İki giriş Providers örneğindeki değerleri birleştiren bir işlev kullanılarak hesaplanan bir değerle yeni bir Provider oluşturmak için iki Provider örneğini birleştirmenize olanak tanır.
Property<T>
, Provider<T> öğesini uyguladığından T türünde bir değer de sağlar. Yalnızca okunabilen Provider<T> politikasının aksine Property<T> için de bir değer ayarlayabilirsiniz. Bunu yapmanın iki yolu vardır:
  • Kullanılabilir olduğunda T türünde bir değeri doğrudan ayarlayın. Bu işlem için ertelenmiş hesaplamalar gerekmez.
  • 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 oluşturulur.
TaskProvider
UygulamaProvider<Task> TaskProvider oluşturmak için tasks.register() kullanın. Görevlerin yalnızca gerektiğinde geç başlatıldığından emin olmak için tasks.create() kullanmayın. flatMap() kullanarak Task oluşturulmadan önce Task çıkışlarına erişebilirsiniz. Bu, çıkışları diğer Task örneklerine giriş olarak kullanmak istediğinizde faydalı olabilir.

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

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'nın örtülü bağımlılığı haline gelir ve Provider'nın değeri çözümlendiğinde (ör. başka bir Task tarafından gerektiğinde) oluşturulup çalıştırılır.

Aşağıda, GitVersionTask ve ManifestProducerTask olmak üzere iki görevin kaydedilip 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, GitVersionTask değerine dolaylı olarak 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 istenirse yürütülür. Bu durum, örneğin ./gradlew debugManifestProducer komutunu çalıştırdığınızda veya ManifestProducerTask komutunun çıkışı başka bir göreve bağlanıp değeri gerekli hale geldiğinde Gradle çağrısı kapsamında gerçekleşebilir.

Girişleri kullanan ve/veya çıkışlar üreten özel görevler yazsanı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, okuyup dönüştürebileceğiniz Variant API'yi ve görevlerinin çıkışına (derleme yapıları) erişimi sunar. Daha fazla bilgi için bu belgedeki Varyant API'si, 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, her bir farklı Gradle derleme aşamasında (başlatma, yapılandırma ve yürütme) 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ü rehberinde 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ülür. Bu aşama, DSL nesnelerini kullanarak derlemeyi yapılandırmak ve görevleri ile girişlerini geç kaydetmek için kullanılmalıdır.

Yapılandırma aşaması, hangi görevin çalıştırılması istendiğinden bağımsız olarak her zaman çalıştığından bu aşamayı yalın tutmak ve hesaplamaların, derleme komut dosyalarının kendisi 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ı

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 yapmanıza ve Provider<T>.get() çağırarak geç sağlayıcıları çözmenize izin verilir. Lazy 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ını başlatır. Görevler, gerekli değerleri oluşturmak için geç çalıştırılır.

Varyant API'si, Yapılar ve Görevler

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

Android derleme akışı ve uzantı noktaları

AGP ile etkileşimde bulunurken normal Gradle yaşam döngüsü geri çağırmalarını (ö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 genel API olarak sunulmaz. Task nesnelerinin örneklerini almaya çalışmaktan veya Task adlarını tahmin etmekten ve bu Task nesnelerine doğrudan geri çağırma veya bağımlılık eklemekten kaçınmanız gerekir.

AGP, Task örneklerini oluşturmak ve yürütmek için aşağıdaki adımları tamamlar. Bu örnekler de derleme yapılarını oluşturur. Variant Nesne oluşturma ile ilgili temel adımları, derleme kapsamında oluşturulan belirli nesnelerde değişiklik yapmanıza olanak tanıyan geri çağırmalar izler. 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ı çalışması gerektiğini, karmaşık işlemlerin ise yürütme aşamasında uygun Task örneklerine ertelenmesi gerektiğini unutmayın.

  1. DSL ayrıştırma: Bu aşamada derleme komut dosyaları değerlendirilir ve android bloğundaki Android DSL nesnelerinin çeşitli özellikleri oluşturulup ayarlanır. Aşağıdaki bölümlerde açıklanan Variant API geri çağırmaları da bu aşamada kaydedilir.
  2. finalizeDsl(): DSL nesnelerini bileşen (varyant) oluşturma için kilitlenmeden önce değiştirmenize olanak tanıyan geri çağırma. VariantBuilder nesneleri, DSL nesnelerinde bulunan verilere göre oluşturulur.

  3. DSL kilitleme: DSL artık kilitli ve değişiklik yapılamıyor.

  4. beforeVariants(): Bu geri çağırma, VariantBuilder aracılığıyla hangi bileşenlerin oluşturulacağını ve bazı özelliklerini etkileyebilir. Derleme akışında ve üretilen yapıtlar üzerinde değişiklik yapmaya devam edebilirsiniz.

  5. Varyant oluşturma: Oluşturulacak bileşen ve yapay nesne listesi artık kesinleşti ve değiştirilemez.

  6. 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 geç hesaplanır.

  7. Varyant kilitleme: Varyant nesneleri artık kilitli ve değişiklik yapılamıyor.

  8. Oluşturulan görevler: Variant nesneleri ve bunların Property değerleri, derleme işlemini gerçekleştirmek için gerekli olan Task örneklerini oluşturmak üzere 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 kullanarak bildirimli yapılandırma için tutmanızı ve özel zorunlu mantığı buildSrc dizinine taşımanızı veya harici eklentiler kullanmanızı öneririz. Projenizde eklenti oluşturmayı öğrenmek için Gradle tarifleri GitHub deposundaki buildSrc örneklerine de göz atabilirsiniz. Eklentinizin, derleme dosyanızdaki gradle-api yapıtına göre derlendiğinden emin olun. Aşağıda, geri çağırma işlevlerini eklenti kodundan 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 ->
            ...
        }
    }
}

Kullanılabilir geri çağırmalara ve eklentinizin her birinde destekleyebileceği kullanım alanlarına daha yakından bakalım:

finalizeDsl(callback: (DslExtensionT) -> Unit)

Bu geri çağırmada, derleme dosyalarındaki android bloğundan alınan bilgilerin ayrıştırılmasıyla oluşturulan DSL nesnelerine erişebilir ve bunları değiştirebilirsiniz. Bu DSL nesneleri, derlemenin sonraki aşamalarında varyantları başlatmak 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ğini ve bu nedenle herhangi bir harici girişe dayanmaması gerektiğini unutmayın. Bu geri çağırma işlemi yürütmeyi tamamladıktan sonra DSL nesneleri artık kullanılamaz ve bunlara yönelik referansları tutmamalı ya da değerlerini değiştirmemelisiniz.

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()

Oluşturma işleminin bu aşamasında, oluşturulacak varyantları ve bunların özelliklerini belirleyen VariantBuilder nesnelerine erişebilirsiniz. Örneğin, belirli varyantları ve bunların 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()'ya benzer şekilde, sağladığınız tüm değerler yapılandırma sırasında çözülmeli ve harici girişlere bağlı olmamalıdır. VariantBuilder nesneleri, beforeVariants() geri çağırma işlevi yürütülmeyi tamamladıktan sonra değiştirilmemelidir.

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

beforeVariants() geri çağırması isteğe bağlı olarak VariantSelector alır. Bu değeri androidComponentsExtension üzerindeki selector() yöntemiyle elde edebilirsiniz. Geri çağırma işlemine 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ı dosyalar veya ağ gibi harici girişlerden okuma da dahil olmak üzere gerekli tüm hesaplamaları yapacak kendi özel görevlerinizdeki sağlayıcılara güvenli bir şekilde bağlayabilirsiniz.

// 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 Kaynaklar API'si bölümüne 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 tarifine bakın.

Bu kod snippet'inde, özel bir görevden oluşturulan Android kaynaklarını içeren bir dizinin res kaynak grubuna nasıl ekleneceği gösterilmektedir. Diğer kaynak türleri için de benzer bir süreç uygulanır.

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 bunları değiştirme

AGP, Variant nesnelerindeki basit özellikleri değiştirmenize olanak tanımanın yanı sıra derleme sırasında oluşturulan ara ve nihai yapıtları okumanıza veya dönüştürmenize olanak tanıyan bir uzantı mekanizması da içerir. Örneğin, son birleştirilmiş AndroidManifest.xml dosya içeriklerini özel bir Task içinde okuyarak analiz edebilir veya içeriklerini tamamen özel Task'niz tarafından oluşturulan bir manifest dosyasıyla değiştirebilirsiniz.

Şu anda desteklenen yapay nesnelerin listesini Artifact sınıfının referans belgelerinde bulabilirsiniz. Her yapay nesne türünün bilinmesi gereken belirli özellikleri vardır:

Nicelik

Bir Artifact öğesinin kardinalitesi, FileSystemLocation örneklerinin sayısını veya yapıt türündeki dosya ya da dizinlerin sayısını gösterir. 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'ın alt sınıfı, birden fazla FileSystemLocation örneği içeren yapılar ise Artifact.Multiple'ın alt sınıfı olur.

FileSystemLocation türü

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

Desteklenen işlemler

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

  • Transformable: Artifact öğesinin, üzerinde rastgele dönüşümler gerçekleştiren ve Artifact öğesinin yeni bir sürümünü çıkış olarak veren bir Task öğesine giriş olarak kullanılmasına olanak tanır.
  • Appendable: Yalnızca Artifact.Multiple alt sınıfları olan yapay nesneler için geçerlidir. Bu, Artifact öğesine ekleme yapılabileceği anlamına gelir. Yani özel bir Task, bu Artifact türünün yeni örneklerini oluşturabilir ve bu örnekler mevcut listeye eklenir.
  • Replaceable: Yalnızca Artifact.Single alt sınıfları olan yapay nesneler için geçerlidir. Değiştirilebilir bir Artifact, tamamen yeni bir örnekle değiştirilebilir. Bu örnek, Task çıkışı olarak üretilir.

Üç öğe değiştirme işlemine ek olarak her öğe, öğenin son sürümünü (üzerindeki tüm işlemler tamamlandıktan sonra) içeren Provider bir get() (veya getAll()) işlemini destekler.

Birden fazla eklenti, onVariants() geri çağırmasından itibaren ardışık düzene herhangi bir sayıda işlem 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 uygun şekilde zincirlenmesini sağlar. Yani bir işlem, çıktıları ekleyerek, değiştirerek veya dönüştürerek değiştirdiğinde sonraki işlem, bu yapıtların güncellenmiş sürümünü giriş olarak görür.

Kayıt işlemlerine giriş noktası Artifacts sınıfıdır. Aşağıdaki kod snippet'inde, onVariants() geri çağırmasındaki Variant nesnesinde bulunan bir özellikten Artifacts örneğine nasıl erişebileceğiniz gösterilmektedir.

Daha sonra, TaskBasedOperation nesnesi (1) almak için özel TaskProvider değerinizi iletebilir ve wiredWith* yöntemlerinden (2) birini kullanarak giriş ve çıkışlarını bağlamak için 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, döndürülen *OperationRequest nesnesinde seçilen işlemi temsil eden bir yönteme Artifact türünü iletirsiniz. Örneğin, toAppendTo(), toTransform() veya toCreate() (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'dir. Bu nedenle, giriş için tek bir wiredWithFiles referansını, çıkış için ise tek bir RegularFileProperty referansını kabul eden RegularFileProperty yöntemini kullanmamız gerekir. wiredWith* sınıfında, Artifact kardinalite ve FileSystemLocation türlerinin diğer kombinasyonları için çalışacak başka TaskBasedOperation yöntemler 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: