ปลั๊กอิน Android Gradle (AGP) เป็นระบบบิลด์อย่างเป็นทางการสำหรับแอปพลิเคชัน Android รวมถึงรองรับการคอมไพล์แหล่งที่มาหลายประเภทและลิงก์เข้าด้วยกันเป็นแอปพลิเคชันที่คุณสามารถเรียกใช้ได้บนอุปกรณ์ Android จริงหรือโปรแกรมจำลอง
AGP มีจุดขยายสำหรับปลั๊กอินเพื่อควบคุมอินพุตการสร้างและขยายฟังก์ชันการทำงานผ่านขั้นตอนใหม่ที่ผสานรวมกับงานการสร้างมาตรฐานได้ AGP เวอร์ชันก่อนหน้าไม่มี API อย่างเป็นทางการที่แยกออกจากการใช้งานภายในอย่างชัดเจน ตั้งแต่เวอร์ชัน 7.0 AGP มีชุดAPI อย่างเป็นทางการที่เสถียรซึ่งคุณไว้วางใจได้
วงจรชีวิตของ AGP API
AGP เป็นไปตามวงจรของฟีเจอร์ Gradle เพื่อกำหนดสถานะของ API ดังนี้
- ภายใน: ไม่ได้มีไว้สำหรับการใช้งานสาธารณะ
- กำลังพัฒนา: พร้อมให้ใช้งานแบบสาธารณะแต่ยังไม่เป็นเวอร์ชันสุดท้าย ซึ่งหมายความว่าอาจใช้งานร่วมกับเวอร์ชันเก่าไม่ได้ในเวอร์ชันสุดท้าย
- สาธารณะ: พร้อมให้ใช้งานแบบสาธารณะและมีความเสถียร
- เลิกใช้งานแล้ว: ระบบไม่รองรับอีกต่อไปและมี API ใหม่เข้ามาแทนที่
นโยบายการเลิกใช้งาน
AGP กำลังพัฒนาไปพร้อมกับการเลิกใช้งาน API เก่าและแทนที่ด้วย API ใหม่ที่เสถียรและภาษาเฉพาะโดเมน (DSL) ใหม่ การพัฒนานี้จะครอบคลุม AGP หลายรุ่น และคุณสามารถดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ลำดับเวลาการย้ายข้อมูล AGP API/DSL
เมื่อเลิกใช้งาน AGP API ไม่ว่าจะสำหรับการย้ายข้อมูลครั้งนี้หรืออื่นๆ ก็ตาม API ดังกล่าวจะยังคงใช้งานได้ในรุ่นหลักปัจจุบัน แต่จะสร้างคำเตือน เราจะนํา API ที่เลิกใช้งานแล้วออกจาก AGP โดยสมบูรณ์ในรุ่นหลักถัดไป เช่น หากเลิกใช้งาน API ใน AGP 7.0 API ดังกล่าวจะใช้งานได้ในเวอร์ชันนั้นและสร้างคำเตือน API ดังกล่าวจะไม่มีให้บริการใน AGP 8.0 อีกต่อไป
หากต้องการดูตัวอย่าง API ใหม่ที่ใช้ในการปรับแต่งบิลด์ทั่วไป โปรดดูสูตรสำหรับปลั๊กอิน Gradle ของ Android ซึ่งแสดงตัวอย่างการปรับแต่งบิลด์ที่พบบ่อย นอกจากนี้ คุณยังดูรายละเอียดเพิ่มเติมเกี่ยวกับ API ใหม่ได้ในเอกสารอ้างอิง
ข้อมูลเบื้องต้นเกี่ยวกับการสร้าง Gradle
คำแนะนำนี้ไม่ได้ครอบคลุมระบบการสร้าง Gradle ทั้งหมด แต่เอกสารนี้ครอบคลุมชุดแนวคิดที่จําเป็นขั้นต่ำเพื่อช่วยให้คุณผสานรวมกับ API ของเราได้ และลิงก์ไปยังเอกสารประกอบหลักของ Gradle เพื่ออ่านเพิ่มเติม
เราถือว่าคุณมีความรู้พื้นฐานเกี่ยวกับวิธีการทำงานของ Gradle ซึ่งรวมถึงวิธีกำหนดค่าโปรเจ็กต์ แก้ไขไฟล์บิลด์ ใช้ปลั๊กอิน และเรียกใช้งาน หากต้องการดูข้อมูลเบื้องต้นเกี่ยวกับ Gradle ที่เกี่ยวข้องกับ AGP เราขอแนะนําให้ดูกําหนดค่าการสร้าง ดูข้อมูลเกี่ยวกับเฟรมเวิร์กทั่วไปสำหรับการปรับแต่งปลั๊กอิน Gradle ได้ที่หัวข้อการพัฒนาปลั๊กอิน Gradle ที่กําหนดเอง
อภิธานศัพท์เกี่ยวกับประเภทแบบ Lazy ของ Gradle
Gradle มีประเภทต่างๆ ที่ทำงานแบบ "ขี้เกียจ" หรือช่วยเลื่อนการคำนวณที่หนักหน่วงหรือการสร้าง Task
ไปไว้ในช่วงหลังของการสร้าง ประเภทเหล่านี้เป็นหัวใจสำคัญของ Gradle และ AGP API หลายรายการ รายการต่อไปนี้แสดงประเภท Gradle หลักที่เกี่ยวข้องกับการดําเนินการแบบเลื่อนเวลาและเมธอดหลัก
Provider<T>
- ให้ค่าประเภท
T
(โดยที่ "T" หมายถึงประเภทใดก็ได้) ซึ่งสามารถอ่านได้ในระหว่างระยะการดําเนินการโดยใช้get()
หรือเปลี่ยนรูปแบบเป็นProvider<S>
ใหม่ (โดยที่ "S" หมายถึงประเภทอื่น) โดยใช้เมธอดmap()
,flatMap()
และzip()
โปรดทราบว่าคุณไม่ควรเรียกget()
ในระหว่างระยะการกําหนดค่าmap()
: รับ lambda และสร้างProvider
ประเภทS
,Provider<S>
อาร์กิวเมนต์ lambda ของmap()
จะรับค่าT
และสร้างค่าS
ระบบจะไม่เรียกใช้ Lambda ทันที แต่จะใช้เมื่อมีการเรียกใช้get()
ในProvider<S>
ที่ได้flatMap()
: ยอมรับ LAMBDA และสร้างProvider<S>
ด้วย แต่ LAMBDA จะรับค่าT
และสร้างProvider<S>
(แทนที่จะสร้างค่าS
โดยตรง) ใช้ flatMap() เมื่อไม่สามารถระบุ S ได้ในเวลาที่กําหนดค่า และคุณได้รับได้เฉพาะProvider<S>
ในทางปฏิบัติแล้ว หากคุณใช้map()
และได้ผลลัพธ์ประเภทProvider<Provider<S>>
แสดงว่าคุณควรใช้flatMap()
แทนzip()
: ให้คุณรวมอินสแตนซ์Provider
2 รายการเข้าด้วยกันเพื่อสร้างProvider
ใหม่ โดยมีค่าที่คำนวณโดยใช้ฟังก์ชันที่รวมค่าจากอินสแตนซ์Providers
อินพุต 2 รายการ
Property<T>
- ใช้
Provider<T>
จึงให้ค่าประเภทT
ด้วย คุณตั้งค่าให้กับProperty<T>
ได้อีกด้วย ซึ่งต่างจากProvider<T>
ที่เป็นแบบอ่านอย่างเดียว ซึ่งทำได้ 2 วิธีดังนี้- ตั้งค่าประเภท
T
โดยตรงเมื่อพร้อมใช้งานโดยไม่ต้องใช้การคํานวณแบบเลื่อนเวลา - ตั้งค่า
Provider<T>
อื่นเป็นแหล่งที่มาของค่าProperty<T>
ในกรณีนี้ ค่าT
จะปรากฏขึ้นก็ต่อเมื่อมีการเรียกใช้Property.get()
เท่านั้น
- ตั้งค่าประเภท
TaskProvider
- ใช้งาน
Provider<Task>
หากต้องการสร้างTaskProvider
ให้ใช้tasks.register()
ไม่ใช่tasks.create()
เพื่อให้ระบบสร้างอินสแตนซ์งานแบบ Lazy เฉพาะเมื่อจําเป็นเท่านั้น คุณสามารถใช้flatMap()
เพื่อเข้าถึงเอาต์พุตของTask
ก่อนที่จะสร้างTask
ซึ่งจะมีประโยชน์หากคุณต้องการใช้เอาต์พุตเป็นอินพุตสำหรับอินสแตนซ์Task
อื่นๆ
ผู้ให้บริการและวิธีการเปลี่ยนรูปแบบของผู้ให้บริการมีความสําคัญในการตั้งค่าอินพุตและเอาต์พุตของงานในลักษณะที่ไม่ต้องสร้างงานทั้งหมดล่วงหน้าและแก้ไขค่า
ผู้ให้บริการยังมีข้อมูลเกี่ยวกับความเชื่อมโยงของงานด้วย เมื่อคุณสร้าง Provider
โดยการแปลงเอาต์พุต Task
Task
นั้นจะกลายเป็นข้อกำหนดโดยนัยของ Provider
และระบบจะสร้างและเรียกใช้ทุกครั้งที่ค่าของ Provider
ได้รับการแก้ไข เช่น เมื่อ Task
อื่นต้องใช้
ต่อไปนี้คือตัวอย่างการลงทะเบียนงาน 2 รายการ ได้แก่ GitVersionTask
และ ManifestProducerTask
พร้อมกับเลื่อนการสร้างอินสแตนซ์ Task
จนกว่าจะจําเป็นต้องใช้ ค่าอินพุต ManifestProducerTask
ได้รับการตั้งค่าเป็น Provider
ซึ่งได้มาจากเอาต์พุตของ GitVersionTask
ดังนั้น ManifestProducerTask
จึงขึ้นอยู่กับ GitVersionTask
โดยนัย
// 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))
}
งานทั้ง 2 รายการนี้จะทำงานก็ต่อเมื่อมีคำขออย่างชัดเจนเท่านั้น กรณีนี้อาจเกิดขึ้นเป็นส่วนหนึ่งของการเรียกใช้ Gradle เช่น หากคุณเรียกใช้ ./gradlew
debugManifestProducer
หรือหากเอาต์พุตของ ManifestProducerTask
เชื่อมต่อกับงานอื่นและค่าของ ManifestProducerTask
กลายเป็นค่าที่ต้องระบุ
แม้ว่าคุณจะเขียนงานที่กำหนดเองซึ่งใช้อินพุตและ/หรือสร้างเอาต์พุต แต่ AGP ไม่ได้ให้สิทธิ์เข้าถึงแบบสาธารณะสำหรับงานของตัวเองโดยตรง รายละเอียดเหล่านี้เป็นรายละเอียดการใช้งานที่อาจมีการเปลี่ยนแปลงในแต่ละเวอร์ชัน แต่ AGP จะเสนอ Variant API และสิทธิ์เข้าถึงเอาต์พุตของงาน หรืออาร์ติแฟกต์การสร้างที่คุณสามารถอ่านและเปลี่ยนรูปแบบได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับVariant API, อาร์ติแฟกต์ และ Tasks ในเอกสารนี้
ระยะการทำงานของ Gradle
การสร้างโปรเจ็กต์เป็นกระบวนการที่ซับซ้อนและต้องใช้ทรัพยากรโดยเนื้อแท้ และยังมีฟีเจอร์ต่างๆ เช่น การหลีกเลี่ยงการกำหนดค่างาน การตรวจสอบข้อมูลล่าสุด และฟีเจอร์การแคชการกำหนดค่า ซึ่งช่วยประหยัดเวลาในการคํานวณที่ซ้ำกันหรือไม่จําเป็น
หากต้องการใช้การเพิ่มประสิทธิภาพเหล่านี้ สคริปต์และปลั๊กอิน Gradle ต้องปฏิบัติตามกฎที่เข้มงวดในแต่ละระยะการสร้าง Gradle ซึ่งได้แก่ ระยะเริ่มต้น การกำหนดค่า และการดำเนินการ ในคู่มือนี้ เราจะมุ่งเน้นไปที่การกำหนดค่าและระยะการดําเนินการ ดูข้อมูลเพิ่มเติมเกี่ยวกับระยะต่างๆ ทั้งหมดได้ในคู่มือวงจรการสร้าง Gradle
ระยะการกําหนดค่า
ในระหว่างขั้นตอนการกําหนดค่า ระบบจะประเมินสคริปต์บิลด์สําหรับโปรเจ็กต์ทั้งหมดที่เป็นส่วนหนึ่งของบิลด์ ใช้ปลั๊กอิน และแก้ไขข้อกําหนดของบิลด์ ควรใช้ระยะนี้เพื่อกำหนดค่าบิลด์โดยใช้ออบเจ็กต์ DSL และเพื่อลงทะเบียนงานและอินพุตแบบล่าช้า
เนื่องจากเฟสการกําหนดค่าจะทํางานอยู่เสมอ ไม่ว่าระบบจะขอให้เรียกใช้งานใดก็ตาม จึงมีความสําคัญอย่างยิ่งที่จะต้องทําให้เฟสนี้ทำงานได้อย่างรวดเร็วและจำกัดการคำนวณไม่ให้ขึ้นอยู่กับอินพุตอื่นนอกเหนือจากสคริปต์บิลด์
กล่าวคือ คุณไม่ควรเรียกใช้โปรแกรมภายนอกหรืออ่านจากเครือข่าย หรือดำเนินการคํานวณที่ใช้เวลานานซึ่งสามารถเลื่อนไปไว้ในระยะการดําเนินการเป็นอินสแตนซ์Task
ที่เหมาะสม
ระยะการดําเนินการ
ในเฟสการดำเนินการ ระบบจะดำเนินการกับงานที่ขอและงานที่ขึ้นอยู่กับงานดังกล่าว กล่าวโดยละเอียดคือ ระบบจะเรียกใช้เมธอดของคลาส Task
ที่มีเครื่องหมาย @TaskAction
ในระหว่างการดำเนินการของงาน คุณจะได้รับอนุญาตให้อ่านจากอินพุต (เช่น ไฟล์) และแก้ไขผู้ให้บริการแบบ Lazy โดยเรียกใช้ Provider<T>.get()
การแก้ไขผู้ให้บริการแบบ Lazy ด้วยวิธีนี้จะเริ่มต้นการเรียก map()
หรือ flatMap()
ตามลำดับตามข้อมูลการพึ่งพางานที่อยู่ในผู้ให้บริการ ระบบจะเรียกใช้งานแบบ Lazy เพื่อแสดงค่าที่จำเป็น
Variant API, อาร์ติแฟกต์ และงาน
Variant API เป็นกลไกส่วนขยายในปลั๊กอิน Gradle ของ Android ที่ช่วยให้คุณจัดการตัวเลือกต่างๆ ซึ่งปกติจะตั้งค่าโดยใช้ DSL ในไฟล์การกําหนดค่าบิลด์ที่ส่งผลต่อบิลด์ Android ได้ Variant API ยังให้คุณเข้าถึงอาร์ติแฟกต์ขั้นกลางและขั้นสุดท้ายที่บิลด์สร้างขึ้น เช่น ไฟล์คลาส, ไฟล์ Manifest ที่ผสาน หรือไฟล์ APK/AAB
ขั้นตอนการบิลด์ Android และจุดขยาย
เมื่อโต้ตอบกับ AGP ให้ใช้จุดขยายที่สร้างขึ้นเป็นพิเศษแทนการลงทะเบียนการเรียกกลับวงจรชีวิตของ Gradle ทั่วไป (เช่น afterEvaluate()
) หรือการตั้งค่าการพึ่งพา Task
ที่ชัดเจน งานที่สร้างโดย AGP จะถือเป็นรายละเอียดการใช้งานและจะไม่แสดงเป็น API สาธารณะ คุณต้องหลีกเลี่ยงการพยายามรับอินสแตนซ์ของออบเจ็กต์ Task
หรือการคาดเดาชื่อ Task
และการเพิ่มการเรียกกลับหรือข้อมูลที่ต้องพึ่งพาไปยังออบเจ็กต์ Task
เหล่านั้นโดยตรง
AGP จะทําตามขั้นตอนต่อไปนี้เพื่อสร้างและเรียกใช้อินสแตนซ์ Task
ซึ่งจะสร้างอาร์ติแฟกต์การสร้าง ขั้นตอนหลักที่เกี่ยวข้องกับการสร้างออบเจ็กต์ Variant
ตามด้วยคอลแบ็กที่ช่วยให้คุณทำการเปลี่ยนแปลงออบเจ็กต์บางอย่างที่สร้างเป็นส่วนหนึ่งของบิลด์ได้ โปรดทราบว่าการเรียกกลับทั้งหมดจะเกิดขึ้นในระยะการกําหนดค่า (อธิบายไว้ในหน้านี้) และต้องทํางานอย่างรวดเร็ว โดยเลื่อนงานที่ซับซ้อนไปยังอินสแตนซ์ Task
ที่เหมาะสมในเฟสการดําเนินการแทน
- การแยกวิเคราะห์ DSL: ขั้นตอนนี้จะประเมินสคริปต์บิลด์ และสร้างและตั้งค่าพร็อพเพอร์ตี้ต่างๆ ของออบเจ็กต์ DSL ของ Android จากบล็อก
android
นอกจากนี้ ระบบจะลงทะเบียนการเรียกกลับ Variant API ที่อธิบายไว้ในส่วนต่อไปนี้ด้วย finalizeDsl()
: การเรียกกลับที่ช่วยให้คุณเปลี่ยนออบเจ็กต์ DSL ได้ก่อนที่จะมีการล็อกออบเจ็กต์ดังกล่าวไม่ให้สร้างคอมโพเนนต์ (ตัวแปร) ระบบจะสร้างออบเจ็กต์VariantBuilder
ตามข้อมูลที่อยู่ในออบเจ็กต์ DSLการล็อก DSL: DSL ล็อกอยู่และเปลี่ยนแปลงไม่ได้อีกต่อไป
beforeVariants()
: การคอลแบ็กนี้อาจส่งผลต่อคอมโพเนนต์ที่จะสร้างขึ้นและพร็อพเพอร์ตี้บางอย่างของคอมโพเนนต์ผ่านVariantBuilder
แต่ยังคงอนุญาตให้แก้ไขขั้นตอนการสร้างและอาร์ติแฟกต์ที่สร้างขึ้นการสร้างตัวแปร: รายการคอมโพเนนต์และอาร์ติแฟกต์ที่จะสร้างขึ้นจะได้รับการสรุปแล้วและไม่สามารถเปลี่ยนแปลงได้
onVariants()
: ในคอลแบ็กนี้ คุณจะได้รับสิทธิ์เข้าถึงออบเจ็กต์Variant
ที่สร้างขึ้น และสามารถตั้งค่าหรือผู้ให้บริการสำหรับค่าProperty
ที่อยู่ในออบเจ็กต์เพื่อที่จะได้คํานวณแบบล่าช้าการล็อกตัวแปร: ตอนนี้ออบเจ็กต์ตัวแปรจะล็อกอยู่และคุณจะเปลี่ยนแปลงไม่ได้อีกต่อไป
งานที่สร้างขึ้น: ระบบจะใช้ออบเจ็กต์
Variant
และค่าProperty
เพื่อสร้างอินสแตนซ์Task
ที่จําเป็นสําหรับการสร้าง
AGP เปิดตัว AndroidComponentsExtension
ที่ช่วยให้คุณลงทะเบียนการติดต่อกลับสําหรับ finalizeDsl()
, beforeVariants()
และ onVariants()
ได้
ส่วนขยายนี้พร้อมใช้งานในสคริปต์บิลด์ผ่านบล็อก androidComponents
ดังนี้
// This is used only for configuring the Android build through DSL.
android { ... }
// The androidComponents block is separate from the DSL.
androidComponents {
finalizeDsl { extension ->
...
}
}
อย่างไรก็ตาม เราขอแนะนำให้ใช้สคริปต์บิลด์สำหรับการกำหนดค่าแบบประกาศโดยใช้ DSL ของบล็อก android เท่านั้น และย้ายตรรกะคำสั่งที่กําหนดเองไปยัง buildSrc
หรือปลั๊กอินภายนอก นอกจากนี้ คุณยังดูbuildSrc
ตัวอย่างในที่เก็บ GitHub ของสูตร Gradle เพื่อดูวิธีสร้างปลั๊กอินในโปรเจ็กต์ได้ด้วย ตัวอย่างการลงทะเบียนการเรียกกลับจากโค้ดปลั๊กอินมีดังนี้
abstract class ExamplePlugin: Plugin<Project> {
override fun apply(project: Project) {
val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
androidComponents.finalizeDsl { extension ->
...
}
}
}
มาดูรายละเอียดของคอลแบ็กที่ใช้ได้และประเภทกรณีการใช้งานที่ปลั๊กอินรองรับในแต่ละรายการกัน
finalizeDsl(callback: (DslExtensionT) -> Unit)
ในการเรียกกลับนี้ คุณจะเข้าถึงและแก้ไขออบเจ็กต์ DSL ที่สร้างขึ้นโดยการแยกวิเคราะห์ข้อมูลจากบล็อก android
ในไฟล์บิลด์ได้
ระบบจะใช้ออบเจ็กต์ DSL เหล่านี้เพื่อเริ่มต้นและกำหนดค่าตัวแปรในระยะถัดไปของการสร้าง ตัวอย่างเช่น คุณสามารถสร้างการกำหนดค่าใหม่หรือลบล้างพร็อพเพอร์ตี้แบบเป็นโปรแกรมได้ แต่โปรดทราบว่าค่าทั้งหมดต้องได้รับการแก้ไข ณ เวลาการกําหนดค่า จึงต้องไม่ใช้อินพุตภายนอก
หลังจากการเรียกกลับนี้ดำเนินการเสร็จแล้ว ออบเจ็กต์ DSL จะใช้งานไม่ได้อีกต่อไป และคุณไม่ควรเก็บการอ้างอิงหรือแก้ไขค่าของออบเจ็กต์เหล่านั้นอีก
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()
ในขั้นตอนการสร้างนี้ คุณจะมีสิทธิ์เข้าถึงออบเจ็กต์ VariantBuilder
ซึ่งจะกําหนดตัวแปรที่จะสร้างและพร็อพเพอร์ตี้ของตัวแปร เช่น คุณสามารถปิดใช้ตัวแปรบางรายการ การทดสอบของตัวแปร หรือเปลี่ยนค่าของพร็อพเพอร์ตี้ (เช่น minSdk
) โดยใช้โปรแกรมได้เฉพาะกับตัวแปรที่เลือกเท่านั้น เช่นเดียวกับ finalizeDsl()
ค่าทั้งหมดที่คุณระบุต้องได้รับการแก้ไข ณ เวลาการกําหนดค่าและไม่ต้องอาศัยอินพุตภายนอก ออบเจ็กต์ VariantBuilder
ต้องไม่ได้รับการแก้ไขเมื่อการเรียกกลับ beforeVariants()
เสร็จสิ้น
androidComponents {
beforeVariants { variantBuilder ->
variantBuilder.minSdk = 23
}
}
ฟังก์ชัน Callback ของ beforeVariants()
จะรับ VariantSelector
(ไม่บังคับ) ซึ่งคุณรับได้จากเมธอด selector()
ใน androidComponentsExtension
คุณสามารถใช้ตัวกรองนี้เพื่อกรองคอมโพเนนต์ที่เข้าร่วมการเรียกใช้การเรียกกลับตามชื่อ ประเภทบิลด์ หรือตัวแปรผลิตภัณฑ์
androidComponents {
beforeVariants(selector().withName("adfree")) { variantBuilder ->
variantBuilder.minSdk = 23
}
}
onVariants()
เมื่อเรียกใช้ onVariants()
ระบบจะตัดสินใจเกี่ยวกับอาร์ติแฟกต์ทั้งหมดที่จะสร้างโดย AGPT ไว้แล้ว คุณจึงปิดใช้อาร์ติแฟกต์เหล่านั้นไม่ได้อีก อย่างไรก็ตาม คุณสามารถแก้ไขค่าบางอย่างที่ใช้สำหรับงานได้โดยกำหนดค่าสำหรับแอตทริบิวต์ Property
ในออบเจ็กต์ Variant
เนื่องจากค่า Property
จะได้รับการแก้ไขก็ต่อเมื่อมีการเรียกใช้งานของ AGP เท่านั้น คุณจึงเชื่อมต่อค่าเหล่านี้กับผู้ให้บริการจากงานที่กำหนดเองของคุณได้อย่างปลอดภัย ซึ่งจะทําการคํานวณที่จําเป็น รวมถึงการอ่านจากอินพุตภายนอก เช่น ไฟล์หรือเครือข่าย
// 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() })
}
เพิ่มแหล่งที่มาที่สร้างขึ้นลงในบิลด์
ปลั๊กอินของคุณสามารถส่งแหล่งที่มาที่สร้างขึ้นได้ 2-3 ประเภท เช่น
- โค้ดแอปพลิเคชันในไดเรกทอรี
java
- ทรัพยากร Android ในไดเรกทอรี
res
- ทรัพยากร Java
ในไดเรกทอรี
resources
- ชิ้นงาน Android ในไดเรกทอรี
assets
ดูรายการแหล่งที่มาทั้งหมดที่เพิ่มได้ได้ที่ Sources API
ข้อมูลโค้ดนี้แสดงวิธีเพิ่มโฟลเดอร์แหล่งที่มาที่กำหนดเองชื่อ ${variant.name}
ไปยังชุดแหล่งที่มาของ Java โดยใช้ฟังก์ชัน addStaticSourceDirectory()
จากนั้นเครื่องมือชุดค่าผสมของ Android จะประมวลผลโฟลเดอร์นี้
onVariants { variant ->
variant.sources.java?.let { java ->
java.addStaticSourceDirectory("custom/src/kotlin/${variant.name}")
}
}
ดูรายละเอียดเพิ่มเติมได้ในสูตร addJavaSource
ข้อมูลโค้ดนี้แสดงวิธีเพิ่มไดเรกทอรีที่มีทรัพยากร Android ที่สร้างขึ้นจากงานที่กำหนดเองไปยังชุดแหล่งที่มา res
กระบวนการนี้คล้ายกับแหล่งที่มาประเภทอื่นๆ
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.
...
}
}
ดูรายละเอียดเพิ่มเติมได้ที่สูตร addCustomAsset
เข้าถึงและแก้ไขอาร์ติแฟกต์
นอกจากจะช่วยให้คุณแก้ไขพร็อพเพอร์ตี้ง่ายๆ ในออบเจ็กต์ Variant
แล้ว AGP ยังมีกลไกส่วนขยายที่ช่วยให้คุณอ่านหรือเปลี่ยนรูปแบบอาร์ติแฟกต์ขั้นกลางและขั้นสุดท้ายที่สร้างขึ้นในระหว่างการบิลด์ได้ด้วย เช่น คุณสามารถอ่านเนื้อหาไฟล์ AndroidManifest.xml
ที่ผสานแล้วใน Task
ที่กําหนดเองเพื่อวิเคราะห์ หรือแทนที่เนื้อหาทั้งหมดด้วยเนื้อหาของไฟล์ Manifest ที่สร้างขึ้นโดย Task
ที่กําหนดเอง
คุณดูรายการอาร์ติแฟกต์ที่รองรับในปัจจุบันได้ในเอกสารอ้างอิงสำหรับคลาส Artifact
อาร์ติแฟกต์ทุกประเภทมีพร็อพเพอร์ตี้บางอย่างที่ควรทราบ ดังนี้
Cardinality
Cardinality ของ Artifact
แสดงจํานวนอินสแตนซ์ FileSystemLocation
หรือจํานวนไฟล์หรือไดเรกทอรีของประเภทอาร์ติแฟกต์ คุณสามารถรับข้อมูลเกี่ยวกับ Cardinality ของอาร์ติแฟกต์ได้โดยดูจากคลาสหลักของอาร์ติแฟกต์ อาร์ติแฟกต์ที่มี FileSystemLocation
รายการเดียวจะเป็นคลาสย่อยของ Artifact.Single
ส่วนอาร์ติแฟกต์ที่มีอินสแตนซ์ FileSystemLocation
หลายรายการจะเป็นคลาสย่อยของ Artifact.Multiple
FileSystemLocation
ประเภท
คุณสามารถตรวจสอบว่า Artifact
แสดงไฟล์หรือไดเรกทอรีหรือไม่โดยดูที่ประเภท FileSystemLocation
ที่มีพารามิเตอร์ ซึ่งอาจเป็น RegularFile
หรือ Directory
การดำเนินการที่รองรับ
คลาส Artifact
ทุกคลาสสามารถใช้อินเทอร์เฟซต่อไปนี้เพื่อระบุการดำเนินการที่รองรับ
Transformable
: อนุญาตให้ใช้Artifact
เป็นอินพุตของTask
ที่จะเปลี่ยนรูปแบบArtifact
นั้นตามต้องการและแสดงผลArtifact
เวอร์ชันใหม่Appendable
: ใช้กับอาร์ติแฟกต์ที่เป็นคลาสย่อยของArtifact.Multiple
เท่านั้น ซึ่งหมายความว่าสามารถต่อท้ายArtifact
ได้ กล่าวคือTask
ที่กําหนดเองสามารถสร้างอินสแตนซ์ใหม่ของArtifact
ประเภทนี้ซึ่งจะเพิ่มลงในรายการที่มีอยู่Replaceable
: ใช้กับอาร์ติแฟกต์ที่เป็นคลาสย่อยของArtifact.Single
เท่านั้นArtifact
ที่เปลี่ยนทดแทนได้สามารถแทนที่ด้วยอินสแตนซ์ใหม่ทั้งหมดที่สร้างขึ้นจากเอาต์พุตของTask
นอกเหนือจากการดำเนินการแก้ไขอาร์ติแฟกต์ 3 รายการแล้ว อาร์ติแฟกต์ทุกรายการยังรองรับการดำเนินการ get()
(หรือ getAll()
) ซึ่งจะแสดงผล Provider
ที่มีอาร์ติแฟกต์เวอร์ชันสุดท้าย (หลังจากการดำเนินการทั้งหมดเสร็จสิ้นแล้ว)
ปลั๊กอินหลายรายการสามารถเพิ่มการดำเนินการกับอาร์ติแฟกต์ลงในไปป์ไลน์ได้เท่าใดก็ได้จาก onVariants()
callback และ AGP จะตรวจสอบว่ามีการเชื่อมโยงอย่างถูกต้องเพื่อให้งานทั้งหมดทำงานในเวลาที่เหมาะสม และสร้างและอัปเดตอาร์ติแฟกต์อย่างถูกต้อง ซึ่งหมายความว่าเมื่อการดำเนินการหนึ่งๆ เปลี่ยนแปลงเอาต์พุตโดยการต่อท้าย แทนที่ หรือเปลี่ยนรูปแบบ เอาต์พุตนั้นๆ การดำเนินการถัดไปจะเห็นอาร์ติแฟกต์เหล่านี้เวอร์ชันที่อัปเดตแล้วเป็นอินพุต และการดำเนินการต่อๆ ไปก็จะเห็นอาร์ติแฟกต์เวอร์ชันที่อัปเดตแล้วเป็นอินพุตด้วยเช่นกัน
จุดแรกเข้าในการลงทะเบียนการดำเนินการคือคลาส Artifacts
ข้อมูลโค้ดต่อไปนี้แสดงวิธีเข้าถึงอินสแตนซ์ของ Artifacts
จากพร็อพเพอร์ตี้บนออบเจ็กต์ Variant
ใน onVariants()
callback
จากนั้นคุณสามารถส่ง TaskProvider
ที่กําหนดเองเพื่อรับออบเจ็กต์ TaskBasedOperation
(1) และใช้เพื่อเชื่อมต่ออินพุตและเอาต์พุตโดยใช้วิธีใดวิธีหนึ่งจาก wiredWith*
(2)
วิธีการที่แน่นอนซึ่งคุณต้องเลือกจะขึ้นอยู่กับ Cardinality และFileSystemLocation
ประเภทที่ Artifact
นำมาใช้ซึ่งคุณต้องการเปลี่ยนรูปแบบ
และสุดท้าย ให้ส่งประเภท Artifact
ไปยังเมธอดที่แสดงการดำเนินการที่เลือกในออบเจ็กต์ *OperationRequest
ที่คุณได้รับ เช่น toAppendTo()
, toTransform()
หรือ 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)
}
ในตัวอย่างนี้ MERGED_MANIFEST
เป็น SingleArtifact
และเป็น RegularFile
ด้วยเหตุนี้ เราจึงต้องใช้เมธอด wiredWithFiles
ซึ่งรับการอ้างอิง RegularFileProperty
รายการเดียวสำหรับอินพุต และ RegularFileProperty
รายการเดียวสำหรับเอาต์พุต มีเมธอด wiredWith*
อื่นๆ ในคลาส TaskBasedOperation
ที่จะทํางานกับชุดค่าผสมอื่นๆ ของ Cardinality Artifact
และประเภท FileSystemLocation
หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการขยาย AGP เราขอแนะนำให้อ่านส่วนต่อไปนี้จากคู่มือระบบการสร้าง Gradle
- การพัฒนาปลั๊กอิน Gradle ที่กําหนดเอง
- การใช้ปลั๊กอิน Gradle
- การพัฒนาประเภทงาน Gradle ที่กําหนดเอง
- การกำหนดค่าแบบ Lazy
- การหลีกเลี่ยงการกำหนดค่างาน