ปลั๊กอิน Android Gradle (AGP) คือระบบบิลด์อย่างเป็นทางการสำหรับแอปพลิเคชัน Android ซึ่งรวมถึงการรองรับการคอมไพล์แหล่งที่มาหลายประเภท และการลิงก์แหล่งที่มาเหล่านั้นเข้าด้วยกันเป็นแอปพลิเคชันที่คุณเรียกใช้ในอุปกรณ์ Android จริง หรือโปรแกรมจำลองได้
AGP มีจุดขยายสำหรับปลั๊กอินเพื่อควบคุมอินพุตการสร้างและขยายฟังก์ชันการทำงานผ่านขั้นตอนใหม่ๆ ที่สามารถผสานรวมกับงานการสร้างมาตรฐานได้ AGP เวอร์ชันก่อนหน้าไม่มี API อย่างเป็นทางการที่แยกออกจาก การใช้งานภายในอย่างชัดเจน ตั้งแต่เวอร์ชัน 7.0 เป็นต้นไป AGP มีชุด API ที่เสถียรและเป็นทางการที่คุณใช้ได้
วงจร API ของ AGP
AGP ทำตามวงจรฟีเจอร์ของ Gradle เพื่อกำหนดสถานะของ API
- ภายใน: ไม่ได้มีไว้สำหรับการใช้งานสาธารณะ
- ระยะฟักตัว: พร้อมให้ใช้งานแบบสาธารณะแต่ยังไม่เสร็จสมบูรณ์ ซึ่งหมายความว่าฟีเจอร์เหล่านี้ อาจไม่สามารถใช้งานร่วมกับเวอร์ชันก่อนหน้าในเวอร์ชันสุดท้ายได้
- สาธารณะ: พร้อมใช้งานแบบสาธารณะและมีความเสถียร
- เลิกใช้งานแล้ว: ไม่รองรับอีกต่อไป และแทนที่ด้วย API ใหม่
นโยบายการเลิกใช้งาน
AGP กำลังพัฒนาไปพร้อมกับการเลิกใช้งาน API เก่าและ การแทนที่ด้วย API ใหม่ที่เสถียรและ Domain Specific Language (DSL) ใหม่ การเปลี่ยนแปลงนี้จะครอบคลุม AGP หลายรุ่น และคุณสามารถดูข้อมูลเพิ่มเติมได้ ที่ไทม์ไลน์การย้ายข้อมูล AGP API/DSL
เมื่อเลิกใช้งาน AGP API สำหรับการย้ายข้อมูลนี้หรืออื่นๆ API เหล่านี้จะยังคงใช้งานได้ในรุ่นหลักปัจจุบัน แต่จะสร้างคำเตือน เราจะนำ API ที่เลิกใช้งานแล้วออกจาก AGP อย่างสมบูรณ์ในรุ่นหลัก ถัดไป เช่น หากเลิกใช้งาน API ใน AGP 7.0 API นั้นจะยังคงใช้งานได้ ในเวอร์ชันดังกล่าวและสร้างคำเตือน API นั้นจะใช้งานไม่ได้อีกต่อไปใน AGP 8.0
หากต้องการดูตัวอย่าง API ใหม่ที่ใช้ในการปรับแต่งการสร้างทั่วไป โปรดดูสูตรปลั๊กอิน Android Gradle โดยจะแสดงตัวอย่างการปรับแต่งบิลด์ที่พบบ่อย นอกจากนี้ คุณยังดูรายละเอียดเพิ่มเติมเกี่ยวกับ API ใหม่ได้ในเอกสารอ้างอิง
ข้อมูลพื้นฐานเกี่ยวกับการสร้าง Gradle
คู่มือนี้ไม่ได้ครอบคลุมระบบบิลด์ Gradle ทั้งหมด อย่างไรก็ตาม เอกสารนี้จะครอบคลุม ชุดแนวคิดที่จำเป็นขั้นต่ำเพื่อช่วยให้คุณผสานรวมกับ API ของเราได้ และ ลิงก์ไปยังเอกสารประกอบหลักของ Gradle เพื่ออ่านเพิ่มเติม
เราถือว่าคุณมีความรู้พื้นฐานเกี่ยวกับวิธีการทำงานของ Gradle รวมถึงวิธีกำหนดค่า โปรเจ็กต์ แก้ไขไฟล์บิลด์ ใช้ปลั๊กอิน และเรียกใช้ทาสก์ หากต้องการดูข้อมูลพื้นฐานเกี่ยวกับ Gradle ที่เกี่ยวข้องกับ AGP เราขอแนะนำให้ดูกำหนดค่าบิลด์ ดูข้อมูลเกี่ยวกับเฟรมเวิร์กทั่วไปสำหรับการปรับแต่ง ปลั๊กอิน Gradle ได้ที่ การพัฒนาปลั๊กอิน Gradle ที่กำหนดเอง
อภิธานศัพท์ประเภท Lazy ของ Gradle
Gradle มีหลายประเภทที่ทำงานแบบ "เลซี่" หรือช่วยเลื่อนการคำนวณที่ซับซ้อนหรือTask
การสร้างไปยังระยะต่อๆ ไปของการบิลด์ ประเภทเหล่านี้เป็นหัวใจสำคัญของ API ของ Gradle และ AGP หลายรายการ
รายการต่อไปนี้ประกอบด้วยประเภท 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>
ที่ได้ ทำให้ทั้งเชนเป็นแบบ LazyflatMap()
: รับ 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()
เพื่อให้มั่นใจว่าระบบจะสร้างอินสแตนซ์ของงานแบบเลื่อนเวลาเมื่อจำเป็นเท่านั้น คุณใช้flatMap()
เพื่อเข้าถึงเอาต์พุตของTask
ก่อนที่จะสร้างTask
ได้ ซึ่งอาจเป็นประโยชน์หากคุณต้องการใช้ เอาต์พุตเป็นอินพุตไปยังอินสแตนซ์Task
อื่นๆ
ผู้ให้บริการและวิธีการแปลงข้อมูลเป็นสิ่งจำเป็นสำหรับการตั้งค่าอินพุต และเอาต์พุตของงานในลักษณะที่เลื่อนการประมวลผลออกไป นั่นคือโดยไม่จำเป็นต้อง สร้างงานทั้งหมดล่วงหน้าและแก้ไขค่า
ผู้ให้บริการยังระบุข้อมูลการขึ้นต่อกันของงานด้วย เมื่อสร้าง Provider
โดย
การแปลงเอาต์พุต Task
Task
จะกลายเป็นทรัพยากร Dependency โดยนัยของ
Provider
และจะได้รับการสร้างและเรียกใช้เมื่อใดก็ตามที่มีการแก้ไขค่าของ Provider
เช่น เมื่อ Task
อื่นต้องการใช้
ต่อไปนี้เป็นตัวอย่างการลงทะเบียนงาน 2 รายการ ได้แก่ GitVersionTask
และ ManifestProducerTask
ขณะที่เลื่อนการสร้างอินสแตนซ์ Task
จนกว่าจะจำเป็นจริงๆ ระบบจะตั้งค่าอินพุต ManifestProducerTask
เป็น a
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
เชื่อมต่อกับงานอื่นและค่าของเอาต์พุตนั้นกลายเป็นค่าที่จำเป็น
แม้ว่าคุณจะเขียนงานที่กำหนดเองซึ่งใช้ข้อมูลและ/หรือสร้างเอาต์พุต แต่ AGP ก็ไม่ได้ให้สิทธิ์เข้าถึงงานของตัวเองแบบสาธารณะโดยตรง ซึ่งเป็นรายละเอียดการใช้งานที่อาจมีการเปลี่ยนแปลงจากเวอร์ชันหนึ่งไปยังอีกเวอร์ชันหนึ่ง แต่ AGP มี Variant API และสิทธิ์เข้าถึงเอาต์พุตของงาน หรืออาร์ติแฟกต์การสร้างที่คุณอ่านและแปลงได้ ดูข้อมูลเพิ่มเติมได้ที่API ของตัวแปร อาร์ติแฟกต์ และงานในเอกสารนี้
เฟสการบิลด์ Gradle
การสร้างโปรเจ็กต์เป็นกระบวนการที่ซับซ้อนและต้องใช้ทรัพยากรจำนวนมาก และมีฟีเจอร์ต่างๆ เช่น การหลีกเลี่ยงการกำหนดค่าของงาน การตรวจสอบข้อมูลล่าสุด และฟีเจอร์การแคชการกำหนดค่า ซึ่งช่วยลดเวลาที่ใช้ ในการคำนวณที่ทำซ้ำได้หรือไม่จำเป็น
หากต้องการใช้การเพิ่มประสิทธิภาพบางอย่างเหล่านี้ สคริปต์และปลั๊กอิน Gradle ต้อง ปฏิบัติตามกฎที่เข้มงวดในแต่ละขั้นตอนการสร้าง Gradle ที่แตกต่างกัน ได้แก่ การเริ่มต้น การกำหนดค่า และการดำเนินการ ในคู่มือนี้ เราจะมุ่งเน้นไปที่ ขั้นตอนการกำหนดค่าและการดำเนินการ ดูข้อมูลเพิ่มเติมเกี่ยวกับทุกระยะได้ในคู่มือวงจรการสร้าง Gradle
ระยะการกำหนดค่า
ในระหว่างขั้นตอนการกำหนดค่า ระบบจะประเมินสคริปต์บิลด์สำหรับโปรเจ็กต์ทั้งหมดที่เป็นส่วนหนึ่งของบิลด์ ใช้ปลั๊กอิน และแก้ไขการขึ้นต่อกันของบิลด์ ควรใช้เฟสนี้เพื่อกำหนดค่าบิลด์โดยใช้ออบเจ็กต์ DSL และ เพื่อลงทะเบียนงานและอินพุตของงานแบบเลซี
เนื่องจากระยะการกำหนดค่าจะทำงานเสมอ ไม่ว่าระบบจะขอให้รันงานใดก็ตาม จึงเป็นเรื่องสำคัญอย่างยิ่งที่จะต้องทำให้ระยะการกำหนดค่ามีประสิทธิภาพและจำกัดการคำนวณไม่ให้ขึ้นอยู่กับอินพุตอื่นนอกเหนือจากสคริปต์บิลด์เอง
กล่าวคือ คุณไม่ควรเรียกใช้โปรแกรมภายนอกหรืออ่านจากเครือข่าย หรือ
ทำการคำนวณที่ใช้เวลานานซึ่งสามารถเลื่อนไปยังระยะการดำเนินการได้ตามความเหมาะสม
Task
อินสแตนซ์
ระยะการดำเนินการ
ในระยะการดำเนินการ ระบบจะดำเนินการกับงานที่ขอและงานที่ขึ้นอยู่กับงานนั้น
กล่าวโดยละเอียดคือ ระบบจะเรียกใช้เมธอดของคลาส Task
ที่ทำเครื่องหมายด้วย @TaskAction
ในระหว่างการดำเนินการงาน คุณจะได้รับอนุญาตให้อ่านจากอินพุต (เช่น ไฟล์) และแก้ไขผู้ให้บริการแบบเลซีโดยการเรียก Provider<T>.get()
การแก้ไข Lazy
Provider ด้วยวิธีนี้จะเริ่มลำดับการเรียก map()
หรือ flatMap()
ที่เป็นไปตาม
ข้อมูลการขึ้นต่อกันของงานที่อยู่ใน Provider ระบบจะเรียกใช้งาน
งานแบบเลื่อนเวลาเพื่อสร้างค่าที่จำเป็น
API ของตัวแปร อาร์ติแฟกต์ และงาน
Variant API เป็นกลไกการขยายในปลั๊กอิน Android Gradle ที่ช่วยให้คุณจัดการตัวเลือกต่างๆ ซึ่งโดยปกติจะตั้งค่าโดยใช้ DSL ในไฟล์การกำหนดค่าบิลด์ที่มีผลต่อบิลด์ Android นอกจากนี้ Variant API ยัง ให้สิทธิ์เข้าถึงอาร์ติแฟกต์ขั้นกลางและขั้นสุดท้ายที่สร้างขึ้นโดย บิลด์ เช่น ไฟล์คลาส, Manifest ที่ผสาน หรือไฟล์ APK/AAB
ขั้นตอนการสร้าง Android และจุดขยาย
เมื่อโต้ตอบกับ AGP ให้ใช้จุดขยายที่สร้างขึ้นมาเป็นพิเศษแทน
การลงทะเบียนการเรียกกลับวงจรการทำงานของ Gradle ทั่วไป (เช่น afterEvaluate()
) หรือ
การตั้งค่าการขึ้นต่อกันของ Task
อย่างชัดเจน งานที่ AGP สร้างขึ้นถือเป็นรายละเอียดการติดตั้งใช้งานและไม่ได้เปิดเผยเป็น API สาธารณะ คุณต้องหลีกเลี่ยง
การพยายามรับอินสแตนซ์ของออบเจ็กต์ Task
หรือการคาดเดาชื่อ Task
และ
การเพิ่มการเรียกกลับหรือการอ้างอิงไปยังออบเจ็กต์ Task
เหล่านั้นโดยตรง
AGP จะทำตามขั้นตอนต่อไปนี้เพื่อสร้างและเรียกใช้อินสแตนซ์ Task
ซึ่งจะสร้างอาร์ติแฟกต์การสร้าง ขั้นตอนหลักที่เกี่ยวข้องกับการสร้างออบเจ็กต์
Variant
จะตามด้วยการเรียกกลับที่ช่วยให้คุณทำการเปลี่ยนแปลงออบเจ็กต์บางอย่าง
ที่สร้างขึ้นเป็นส่วนหนึ่งของการสร้างได้ โปรดทราบว่าการเรียกกลับทั้งหมดจะเกิดขึ้นในระยะการกำหนดค่า
(อธิบายไว้ในหน้านี้) และต้องทำงานอย่างรวดเร็ว โดยเลื่อนงานที่ซับซ้อน
ไปยังอินสแตนซ์ Task
ที่เหมาะสมในระยะการดำเนินการแทน
- การแยกวิเคราะห์ DSL: ขั้นตอนนี้จะเกิดขึ้นเมื่อมีการประเมินสคริปต์บิลด์ และเมื่อมีการสร้าง
และตั้งค่าพร็อพเพอร์ตี้ต่างๆ ของออบเจ็กต์ Android DSL จากบล็อก
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
}
}
beforeVariants()
Callback จะรับ VariantSelector
โดยไม่บังคับ ซึ่งคุณจะ
รับได้ผ่านเมธอด selector()
ใน androidComponentsExtension
คุณสามารถ
ใช้เพื่อกรองคอมโพเนนต์ที่เข้าร่วมในการเรียกใช้การเรียกกลับตาม
ชื่อ ประเภทบิลด์ หรือรสชาติของผลิตภัณฑ์
androidComponents {
beforeVariants(selector().withName("adfree")) { variantBuilder ->
variantBuilder.minSdk = 23
}
}
onVariants()
เมื่อมีการเรียกใช้ onVariants()
ระบบจะตัดสินใจเกี่ยวกับอาร์ติแฟกต์ทั้งหมดที่จะสร้างโดย
AGP แล้ว คุณจึงปิดใช้ไม่ได้อีก อย่างไรก็ตาม คุณสามารถ
แก้ไขค่าบางค่าที่ใช้สำหรับงานได้โดยการตั้งค่าสำหรับ
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() })
}
มีส่วนร่วมในแหล่งข้อมูลที่สร้างขึ้นในการสร้าง
ปลั๊กอินของคุณสามารถมีส่วนร่วมกับแหล่งที่มาที่สร้างขึ้นได้หลายประเภท เช่น
- โค้ดของแอปพลิเคชันในไดเรกทอรี
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.
...
}
}
ดูรายละเอียดเพิ่มเติมได้ที่สูตรการเพิ่มชิ้นงานที่กำหนดเอง
เข้าถึงและแก้ไขอาร์ติแฟกต์
นอกจากจะช่วยให้คุณแก้ไขพร็อพเพอร์ตี้อย่างง่ายในออบเจ็กต์ Variant
แล้ว AGP
ยังมีกลไกส่วนขยายที่ช่วยให้คุณอ่านหรือเปลี่ยนรูปแบบ
อาร์ติแฟกต์ขั้นกลางและขั้นสุดท้ายที่สร้างขึ้นระหว่างการบิลด์ได้ด้วย เช่น คุณสามารถ
อ่านเนื้อหาของAndroidManifest.xml
ไฟล์ที่ผสานแล้วขั้นสุดท้ายในTask
ที่กำหนดเองเพื่อ
วิเคราะห์ หรือจะแทนที่เนื้อหาทั้งหมดด้วยเนื้อหาของไฟล์ Manifest ที่
สร้างโดยTask
ที่กำหนดเองก็ได้
ดูรายการอาร์ติแฟกต์ที่รองรับในปัจจุบันได้ในเอกสารอ้างอิง
สำหรับคลาส Artifact
อาร์ติแฟกต์ทุกประเภทมีคุณสมบัติบางอย่างที่ควรทราบ ดังนี้
Cardinality
Cardinality ของ Artifact
แสดงจำนวนFileSystemLocation
อินสแตนซ์ หรือจำนวนไฟล์หรือไดเรกทอรีของประเภทอาร์ติแฟกต์ คุณสามารถ
ดูข้อมูลเกี่ยวกับจำนวนคาร์ดินัลลิตีของอาร์ติแฟกต์ได้โดยตรวจสอบคลาส
หลักของอาร์ติแฟกต์นั้น อาร์ติแฟกต์ที่มี 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()
การเรียกกลับ และ AGP จะตรวจสอบว่ามีการเชื่อมโยงอย่างถูกต้อง
เพื่อให้งานทั้งหมดทำงานในเวลาที่เหมาะสม และมีการสร้างและ
อัปเดตอาร์ติแฟกต์อย่างถูกต้อง ซึ่งหมายความว่าเมื่อการดำเนินการเปลี่ยนเอาต์พุตโดยการต่อท้าย
แทนที่ หรือแปลง การดำเนินการถัดไปจะเห็นอัปเดตเวอร์ชัน
ของอาร์ติแฟกต์เหล่านี้เป็นอินพุต และอื่นๆ
จุดแรกเข้าในการลงทะเบียนการดำเนินการคือคลาส Artifacts
ข้อมูลโค้ดต่อไปนี้แสดงวิธีรับสิทธิ์เข้าถึงอินสแตนซ์ของ Artifacts
จากพร็อพเพอร์ตี้ในออบเจ็กต์ Variant
ในแฮนเดิล onVariants()
จากนั้นคุณจะส่ง TaskProvider
ที่กำหนดเองเพื่อรับออบเจ็กต์
TaskBasedOperation
(1) และใช้เพื่อเชื่อมต่ออินพุตและเอาต์พุตโดยใช้วิธีใดวิธีหนึ่งของ
wiredWith*
(2) ได้
วิธีการที่แน่นอนที่คุณต้องเลือกจะขึ้นอยู่กับคาร์ดินาลิตีและ
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
คาร์ดินาลิตีและประเภท FileSystemLocation
หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการขยาย AGP เราขอแนะนำให้อ่านส่วนต่อไปนี้ จากคู่มือระบบบิลด์ Gradle
- การพัฒนาปลั๊กอิน Gradle ที่กำหนดเอง
- การติดตั้งใช้งานปลั๊กอิน Gradle
- การพัฒนาประเภทงาน Gradle ที่กำหนดเอง
- การกำหนดค่าแบบ Lazy
- การหลีกเลี่ยงการกำหนดค่างาน