ปลั๊กอิน 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 ที่เลิกใช้งานแล้วออกจาก 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
ไปไว้ในช่วงหลังของการสร้าง ซึ่งเป็นแกนหลักของ API ของ Gradle และ AGP จำนวนมาก รายการต่อไปนี้มีประเภท Gradle หลักๆ ที่เกี่ยวข้องกับการดำเนินการแบบ Lazy รวมถึงเมธอดคีย์ของประเภทนั้นๆ
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 Loading เมื่อจำเป็นเท่านั้น คุณใช้flatMap()
เพื่อเข้าถึงเอาต์พุตของTask
ก่อนสร้างTask
ได้ ซึ่งอาจเป็นประโยชน์หากคุณต้องการใช้เอาต์พุตเป็นอินพุตไปยังอินสแตนซ์Task
อื่นๆ
ผู้ให้บริการและวิธีการเปลี่ยนรูปแบบมีความสําคัญอย่างยิ่งสําหรับการตั้งค่าอินพุตและเอาต์พุตของงานในลักษณะ Lazy Loading กล่าวคือ ไม่จำเป็นต้องสร้างงานทั้งหมดล่วงหน้าและแก้ไขค่า
นอกจากนี้ ผู้ให้บริการยังมีข้อมูลการอ้างอิงของงานด้วย เมื่อคุณสร้าง Provider
ด้วยการแปลงเอาต์พุต Task
นั้น Task
จะกลายเป็นทรัพยากร Dependency แบบโดยนัยของ 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 Loading ได้โดยการเรียกใช้ Provider<T>.get()
การแก้ไขผู้ให้บริการแบบ Lazy ด้วยวิธีนี้จะเริ่มต้นการเรียก map()
หรือ flatMap()
ตามลำดับตามข้อมูลการพึ่งพางานที่อยู่ในผู้ให้บริการ ระบบจะเรียกใช้งานแบบ Lazy เพื่อแสดงค่าที่จำเป็น
API, อาร์ติแฟกต์ และ Tasks ของตัวแปร
Variant API เป็นกลไกส่วนขยายในปลั๊กอิน Android Gradle ที่ให้คุณจัดการตัวเลือกต่างๆ ที่ปกติตั้งค่าโดยใช้ DSL ในไฟล์การกำหนดค่าบิลด์ ที่ส่งผลต่อบิลด์ของ Android Variant API ยังให้คุณเข้าถึงอาร์ติแฟกต์ขั้นกลางและขั้นสุดท้ายที่บิลด์สร้างขึ้น เช่น ไฟล์คลาส, ไฟล์ Manifest ที่ผสาน หรือไฟล์ APK/AAB
ขั้นตอนของบิลด์และส่วนขยายของ Android
เมื่อโต้ตอบกับ AGP ให้ใช้จุดขยายที่สร้างขึ้นเป็นพิเศษแทนการลงทะเบียน Callback วงจรของ Gradle ทั่วไป (เช่น afterEvaluate()
) หรือการตั้งค่าทรัพยากร Dependency ของ Task
ที่ชัดเจน งานที่สร้างโดย AGP จะถือเป็นรายละเอียดการใช้งานและจะไม่แสดงเป็น API สาธารณะ คุณต้องหลีกเลี่ยงการพยายามรับอินสแตนซ์ของออบเจ็กต์ Task
หรือการคาดเดาชื่อ Task
และการเพิ่มการเรียกกลับหรือข้อมูลที่ต้องพึ่งพาไปยังออบเจ็กต์ Task
เหล่านั้นโดยตรง
AGP จะทําตามขั้นตอนต่อไปนี้เพื่อสร้างและเรียกใช้อินสแตนซ์ Task
ซึ่งจะสร้างอาร์ติแฟกต์การสร้าง ขั้นตอนหลักที่เกี่ยวข้องกับการสร้างออบเจ็กต์ Variant
ตามด้วย Callback ที่ช่วยให้คุณเปลี่ยนแปลงออบเจ็กต์บางรายการที่สร้างขึ้นเป็นส่วนหนึ่งของบิลด์ได้ โปรดทราบว่าการเรียกกลับทั้งหมดจะเกิดขึ้นในระยะการกําหนดค่า (อธิบายไว้ในหน้านี้) และต้องทํางานอย่างรวดเร็ว โดยเลื่อนงานที่ซับซ้อนไปยังอินสแตนซ์ Task
ที่เหมาะสมในเฟสการดําเนินการแทน
- การแยกวิเคราะห์ DSL: ขั้นตอนนี้จะประเมินสคริปต์บิลด์ และสร้างและตั้งค่าพร็อพเพอร์ตี้ต่างๆ ของออบเจ็กต์ DSL ของ Android จากบล็อก
android
ระบบจะลงทะเบียน Callback ของ Variant API ที่อธิบายไว้ในส่วนต่อไปนี้ด้วยในระหว่างขั้นตอนนี้ finalizeDsl()
: Callback ที่ช่วยให้คุณเปลี่ยนออบเจ็กต์ DSL ได้ก่อนที่ออบเจ็กต์เหล่านั้นจะถูกล็อกสำหรับการสร้างคอมโพเนนต์ (ตัวแปร) ระบบจะสร้างออบเจ็กต์VariantBuilder
ตามข้อมูลที่อยู่ในออบเจ็กต์ DSLการล็อก DSL: ขณะนี้ระบบล็อก DSL และไม่สามารถเปลี่ยนแปลงได้
beforeVariants()
: Callback นี้อาจส่งผลต่อการสร้างคอมโพเนนต์และพร็อพเพอร์ตี้บางรายการผ่านVariantBuilder
แต่ยังทำให้แก้ไขโฟลว์ของบิลด์และอาร์ติแฟกต์ที่สร้างขึ้นได้การสร้างตัวแปร: รายการคอมโพเนนต์และอาร์ติแฟกต์ที่จะสร้างขึ้นได้รับการสรุปแล้วและไม่สามารถเปลี่ยนแปลงได้
onVariants()
: ใน Callback นี้ คุณจะเข้าถึงออบเจ็กต์Variant
ที่สร้างขึ้นและกําหนดค่าหรือผู้ให้บริการสําหรับค่าProperty
ที่มีเพื่อคํานวณแบบ Lazy Loading ได้การล็อกตัวแปร: ตอนนี้ออบเจ็กต์ตัวแปรจะล็อกอยู่และคุณจะเปลี่ยนแปลงไม่ได้อีกต่อไป
งานที่สร้างขึ้น: ระบบจะใช้ออบเจ็กต์
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 เพื่อดูวิธีสร้างปลั๊กอินในโปรเจ็กต์ได้ด้วย ต่อไปนี้คือตัวอย่างของการลงทะเบียน Callback จากโค้ดปลั๊กอิน
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 เหล่านี้เพื่อเริ่มต้นและกำหนดค่าตัวแปรในระยะถัดไปของการสร้าง เช่น คุณอาจสร้างการกำหนดค่าใหม่หรือลบล้างพร็อพเพอร์ตี้โดยใช้โปรแกรม แต่โปรดทราบว่าค่าทั้งหมดต้องได้รับการแก้ไข ณ เวลาที่กำหนดค่า ค่าดังกล่าวต้องไม่พึ่งอินพุตภายนอกใดๆ
หลังจาก Callback นี้ดำเนินการเสร็จสิ้นแล้ว ออบเจ็กต์ 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
เมื่อการเรียกใช้ Callback beforeVariants()
เสร็จสิ้น
androidComponents {
beforeVariants { variantBuilder ->
variantBuilder.minSdk = 23
}
}
ฟังก์ชัน Callback ของ beforeVariants()
จะรับ VariantSelector
(ไม่บังคับ) ซึ่งคุณรับได้จากเมธอด selector()
ใน androidComponentsExtension
ซึ่งคุณสามารถใช้เพื่อกรองคอมโพเนนต์ที่เข้าร่วมการเรียกใช้ Callback ตามชื่อ ประเภทบิลด์ หรือรสชาติของผลิตภัณฑ์ได้
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()
จากนั้น Toolchain ของ 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 ของ Artifact
แสดงจํานวนอินสแตนซ์ FileSystemLocation
หรือจํานวนไฟล์หรือไดเรกทอรีของประเภทอาร์ติแฟกต์ คุณสามารถรับข้อมูลเกี่ยวกับ Cardinality ของอาร์ติแฟกต์ได้โดยตรวจสอบคลาสหลักของอาร์ติแฟกต์ อาร์ติแฟกต์ที่มี FileSystemLocation
รายการเดียวจะเป็นคลาสย่อยของ Artifact.Single
ส่วนอาร์ติแฟกต์ที่มีอินสแตนซ์ FileSystemLocation
หลายรายการจะเป็นคลาสย่อยของ Artifact.Multiple
FileSystemLocation
ประเภท
คุณตรวจสอบได้ว่า Artifact
แสดงถึงไฟล์หรือไดเรกทอรีหรือไม่โดยดูจากประเภท FileSystemLocation
ที่ทำเป็นพารามิเตอร์ ซึ่งอาจเป็น RegularFile
หรือ Directory
ก็ได้
การดำเนินการที่รองรับ
คลาส Artifact
ทุกคลาสสามารถใช้อินเทอร์เฟซต่อไปนี้เพื่อระบุการดำเนินการที่รองรับ
Transformable
: อนุญาตให้ใช้Artifact
เป็นอินพุตของTask
ที่มีการเปลี่ยนรูปแบบที่กําหนดเองและเอาต์พุต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
ที่จะใช้งานได้กับชุดค่าผสมอื่นๆ ของประเภท Artifact
Cardinality และ FileSystemLocation
หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการขยาย AGP ขอแนะนำให้อ่านส่วนต่อไปนี้จากคู่มือระบบบิลด์ Gradle
- การพัฒนาปลั๊กอิน Gradle ที่กำหนดเอง
- การใช้ปลั๊กอิน Gradle
- การพัฒนาประเภทงาน Gradle ที่กําหนดเอง
- การกำหนดค่าแบบ Lazy Loading
- การหลีกเลี่ยงการกำหนดค่างาน