ปลั๊กอิน Android Gradle (AGP) เป็นระบบบิลด์อย่างเป็นทางการสำหรับ Android แอปพลิเคชัน รองรับการคอมไพล์แหล่งที่มาประเภทต่างๆ และลิงก์ทั้งสองเข้าด้วยกันเป็นแอปพลิเคชัน ที่คุณสามารถเรียกใช้บน อุปกรณ์ Android หรือโปรแกรมจำลอง
AGP มีจุดขยายให้ปลั๊กอินเพื่อควบคุมอินพุตของบิลด์และขยาย ผ่านขั้นตอนใหม่ที่สามารถผสานรวมกับบิลด์มาตรฐาน งาน AGP เวอร์ชันก่อนหน้าไม่มีการแยก API อย่างเป็นทางการอย่างชัดเจน จากการใช้งานภายใน ตั้งแต่เวอร์ชัน 7.0 เป็นต้นไป AGP มีชุด API อย่างเป็นทางการที่เสถียรและมั่นคงซึ่งคุณพึ่งพาได้ เปิดอยู่
วงจรการใช้งาน AGP API
AGP เป็นไปตามวงจรการใช้งานฟีเจอร์ Gradle เพื่อกำหนดสถานะของ API ดังนี้
- ภายใน: ไม่ได้มีไว้เพื่อใช้สาธารณะ
- การบ่มเพาะ: มีให้ใช้งานแบบสาธารณะ แต่ยังไม่สิ้นสุด ซึ่งหมายความว่า อาจไม่สามารถเข้ากันได้แบบย้อนหลังในเวอร์ชันล่าสุด
- สาธารณะ: พร้อมใช้งานแบบสาธารณะและเสถียร
- เลิกใช้งานแล้ว: ไม่รองรับอีกต่อไป และแทนที่ด้วย API ใหม่
นโยบายการเลิกใช้งาน
AGP มีการพัฒนาจากการเลิกใช้งาน API เก่าและ API ด้วย API ใหม่ที่เสถียรและ Domain Specific Language (DSL) ใหม่ การพัฒนานี้จะครอบคลุม AGP รุ่นต่างๆ และดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ ในไทม์ไลน์การย้ายข้อมูล AGP API/DSL
เมื่อเลิกใช้งาน AGP API แล้ว สำหรับการย้ายข้อมูลนี้หรืออื่นๆ ยังคงพร้อมใช้งานในรุ่นหลัก ปัจจุบันแต่จะสร้าง API ที่เลิกใช้งานแล้วจะถูกนำออกจาก AGP ใน API หลักถัดไป ตัวอย่างเช่น หากเลิกใช้งาน API ใน AGP 7.0 ก็จะพร้อมให้บริการ ในเวอร์ชันนั้นและสร้างคำเตือน API นั้นจะไม่มีให้ใช้ใน AGP 8.0
หากต้องการดูตัวอย่าง API ใหม่ที่ใช้ในการปรับแต่งบิลด์ทั่วไป โปรดดู ที่สูตรอาหารสำหรับปลั๊กอิน Android Gradle โดยจะมีตัวอย่างการปรับแต่งบิลด์ที่พบบ่อย คุณยังหาข้อมูลเพิ่มเติม รายละเอียดเกี่ยวกับ API ใหม่ใน เอกสารอ้างอิง
ข้อมูลเบื้องต้นเกี่ยวกับบิลด์ของ Gradle
คู่มือนี้ไม่ได้ครอบคลุมระบบบิลด์ Gradle ทั้งหมด แต่ก็ครอบคลุม ชุดแนวคิดขั้นต่ำที่จำเป็นเพื่อช่วยคุณผสานรวมกับ API ของเรา และ ไปยังเอกสารหลักของ Gradle เพื่ออ่านข้อมูลเพิ่มเติม
เราสันนิษฐานถึงความรู้พื้นฐานเกี่ยวกับวิธีการทำงานของ Gradle ซึ่งรวมถึงวิธีกำหนดค่า แก้ไขไฟล์บิลด์ ใช้ปลั๊กอิน และเรียกใช้งานต่างๆ หากต้องการเรียนรู้เกี่ยวกับ ข้อมูลเบื้องต้นเกี่ยวกับ Gradle ในเรื่อง AGP เราขอแนะนำให้คุณอ่านหัวข้อกำหนดค่า บิลด์ เพื่อเรียนรู้เกี่ยวกับเฟรมเวิร์กทั่วไปสำหรับการปรับแต่ง ปลั๊กอิน Gradle ดู การพัฒนาปลั๊กอิน Gradle ที่กำหนดเอง
อภิธานศัพท์เกี่ยวกับประเภท Lazy ของ Gradle
Gradle มีหลายประเภทที่ทำงานได้ "แบบ Lazy Loading" หรือช่วยเลื่อนของหนัก
การคำนวณหรือ
Task
ไปจนถึงช่วงหลังๆ ของการสร้าง ประเภทเหล่านี้เป็นหัวใจสำคัญของ
Gradle และ AGP API รายการต่อไปนี้มีประเภท Gradle หลักที่เกี่ยวข้อง
ในการดำเนินการแบบ Lazy Loading และวิธีการหลัก
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
ด้วย ต่างจากProvider<T>
ซึ่งเป็นแบบอ่านอย่างเดียว คุณยังสามารถตั้งค่าสำหรับProperty<T>
โดยมี 2 วิธีดังนี้- ตั้งค่าประเภท
T
โดยตรงเมื่อพร้อมใช้งาน โดยไม่ต้องใช้ การคำนวณที่มีการเลื่อนเวลา - กำหนด
Provider<T>
อีกรายการเป็นแหล่งที่มาของค่าของProperty<T>
ใน ในกรณีนี้ ค่าT
จะเป็นรูปธรรมเมื่อProperty.get()
เป็น โทรออก
- ตั้งค่าประเภท
TaskProvider
- นำ
Provider<Task>
มาใช้ หากต้องการสร้างTaskProvider
ให้ใช้tasks.register()
ไม่ใช่tasks.create()
เพื่อให้มั่นใจว่างานจะมีการสร้างอินสแตนซ์เท่านั้น ขี้เกียจเมื่อจำเป็น คุณสามารถใช้flatMap()
เพื่อเข้าถึงเอาต์พุตของTask
ก่อนที่จะสร้างTask
ซึ่งจะเป็นประโยชน์หากคุณต้องการใช้ เอาต์พุตเป็นอินพุตไปยังอินสแตนซ์Task
อื่นๆ
ผู้ให้บริการและวิธีการเปลี่ยนรูปแบบเป็นสิ่งสําคัญสําหรับการตั้งค่าอินพุต และเอาต์พุตของงานในแบบ Lazy Loading โดยไม่ต้อง ให้สร้างงานทั้งหมดขึ้นด้านหน้าและแก้ไขค่า
นอกจากนี้ ผู้ให้บริการยังมีข้อมูลเกี่ยวกับทรัพยากร Dependency ของงานด้วย เมื่อคุณสร้าง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
เชื่อมต่ออยู่
ในงานอื่นและต้องมีค่าของงานนั้น
แม้ว่าคุณจะเขียนงานที่กำหนดเองซึ่งต้องใช้อินพุตและ/หรือสร้างเอาต์พุต ทั้งนี้ AGP ไม่ได้ให้สิทธิ์สาธารณะในการเข้าถึงงานของตนเองโดยตรง เป็น รายละเอียดการใช้งานอาจมีการเปลี่ยนแปลงไปในแต่ละเวอร์ชัน แต่เป็น AGP แทน มี API เวอร์ชันแปรผันและสิทธิ์เข้าถึงเอาต์พุตของงาน หรือสร้าง ที่คุณสามารถอ่านและเปลี่ยนรูปแบบได้ โปรดดู API, อาร์ติแฟกต์ และ Tasks ของตัวแปรใน เพื่อดูข้อมูลเพิ่มเติม
เฟสการสร้าง Gradle
การสร้างโครงการเป็นกระบวนการที่ซับซ้อนและต้องใช้ทรัพยากร และยังมีคุณลักษณะหลายอย่าง เช่น การหลีกเลี่ยงการกำหนดค่างาน และฟีเจอร์การแคชการกำหนดค่าที่ช่วยลดเวลาที่ใช้ เกี่ยวกับการคำนวณซ้ำหรือไม่จำเป็น
หากต้องการใช้การเพิ่มประสิทธิภาพเหล่านี้ สคริปต์และปลั๊กอิน Gradle ต้อง ปฏิบัติตามกฎที่เข้มงวดในแต่ละขั้นการสร้าง Gradle ที่ต่างกัน การเริ่มต้น การกำหนดค่า และการดำเนินการ ในคู่มือนี้ เราจะมุ่งเน้นไปที่ เฟสการกำหนดค่าและการดำเนินการ คุณสามารถดูข้อมูลเพิ่มเติมเกี่ยวกับ ขั้นตอนต่างๆ ในคู่มือวงจรการสร้าง Gradle
ระยะการกำหนดค่า
ในระหว่างขั้นตอนการกำหนดค่า สคริปต์บิลด์สำหรับโปรเจ็กต์ทั้งหมดที่เป็นส่วนหนึ่งของ ของบิลด์จะได้รับการประเมิน ใช้ปลั๊กอิน และทรัพยากร Dependency ของบิลด์ แก้ปัญหาแล้ว ขั้นตอนนี้ควรใช้เพื่อกำหนดค่าบิลด์โดยใช้ออบเจ็กต์ DSL และ สำหรับการลงทะเบียนงานและ อินพุตแบบ Lazy Loading
เนื่องจากเฟสการกำหนดค่าจะทำงานเสมอ ไม่ว่างานใดจะเป็นงานใด
ที่ต้องเรียกใช้ สิ่งสำคัญคือต้องทำให้เรียบง่ายและจำกัด
การคำนวณที่มาจากอินพุตอื่นๆ ที่ไม่ใช่สคริปต์ของบิลด์
กล่าวคือ คุณไม่ควรเรียกใช้โปรแกรมภายนอกหรืออ่านจากเครือข่าย หรือ
ทำการคำนวณระยะยาวที่สามารถเลื่อนไปยังระยะการดำเนินการได้ตามความเหมาะสม
Task
อินสแตนซ์
ระยะการดำเนินการ
ในระยะการดำเนินการ งานที่ขอและงานที่ต้องพึ่งพากันมีดังนี้
ดำเนินการแล้ว กล่าวอย่างเจาะจงคือ วิธีการในชั้นเรียน Task
รายการที่ทำเครื่องหมายด้วย @TaskAction
คือ
ดำเนินการแล้ว ในระหว่างดำเนินงาน คุณอ่านจากอินพุตได้ (เช่น
) และแก้ปัญหาผู้ให้บริการ Lazy Loading โดยโทรไปที่ Provider<T>.get()
แก้ปัญหาขี้เกียจ
ผู้ให้บริการด้วยวิธีนี้จะเริ่มต้นการโทร map()
หรือ flatMap()
ตามลำดับที่ตามมา
ข้อมูลทรัพยากร Dependency ของงานที่มีอยู่ภายในผู้ให้บริการ งานที่ทำอยู่
อย่างเฉื่อยชาที่จะนำค่าที่จำเป็นไปใช้
API, อาร์ติแฟกต์ และ Tasks ของตัวแปร
Variant API คือกลไกส่วนขยายในปลั๊กอิน Android Gradle ซึ่งช่วยให้ คุณเป็นผู้จัดการตัวเลือกต่างๆ ซึ่งปกติตั้งค่าโดยใช้ DSL ในบิลด์ ที่มีผลต่อบิลด์ของ Android นอกจากนี้ API ของตัวแปรยัง มอบสิทธิ์เข้าถึงอาร์ติแฟกต์ขั้นกลางและสุดท้ายที่สร้างโดย เช่น ไฟล์คลาส ไฟล์ Manifest ที่ผสานรวม หรือไฟล์ APK/AAB
ขั้นตอนของบิลด์และส่วนขยายของ Android
เมื่อโต้ตอบกับ AGP ให้ใช้จุดขยายที่สร้างมาเป็นพิเศษแทน
ของการลงทะเบียน Callback ของวงจร Gradle ทั่วไป (เช่น afterEvaluate()
) หรือ
การตั้งค่าทรัพยากร Dependency ของ Task
อย่างชัดเจน งานที่สร้างโดย AGP จะได้รับการพิจารณา
รายละเอียดการนำไปใช้งานและไม่แสดงเป็น API สาธารณะ คุณต้องหลีกเลี่ยง
พยายามดึงข้อมูลอินสแตนซ์ของออบเจ็กต์ Task
หรือเดาชื่อของ Task
และ
การเพิ่ม Callback หรือทรัพยากร Dependency ไปยังออบเจ็กต์ Task
ดังกล่าวโดยตรง
AGP ทำตามขั้นตอนต่อไปนี้เพื่อสร้างและเรียกใช้อินสแตนซ์ Task
ซึ่งจะทำให้เกิดอาร์ติแฟกต์ของบิลด์ ขั้นตอนหลักๆ ที่เกี่ยวข้องใน
Variant
การสร้างออบเจ็กต์ตามด้วย Callback ที่ช่วยให้คุณทำการเปลี่ยนแปลง
ที่เป็นส่วนหนึ่งของบิลด์ สิ่งสำคัญที่ควรทราบคือ
Callback จะเกิดขึ้นในระหว่างช่วงการกำหนดค่า
(ตามที่อธิบายไว้ในหน้านี้) และต้องทำงานอย่างรวดเร็วโดยเลื่อนเวลาการทำงานที่ซับซ้อนออกไป
ที่เหมาะสมในอินสแตนซ์ Task
ในระหว่างขั้นตอนการดำเนินการแทน
- การแยกวิเคราะห์ DSL: คือเมื่อมีการประเมินสคริปต์บิลด์และเมื่อ
มีการสร้างคุณสมบัติที่หลากหลายของออบเจ็กต์ Android DSL จากบล็อก
android
แล้วตั้งค่า Callback ของ Variant API ที่อธิบายไว้ในส่วนต่อไปนี้ ที่ลงทะเบียนในระยะนี้ finalizeDsl()
: Callback ที่ช่วยให้คุณเปลี่ยนออบเจ็กต์ DSL ได้ก่อนที่จะ ล็อกไว้สำหรับการสร้างคอมโพเนนต์ (ตัวแปร) สร้างออบเจ็กต์VariantBuilder
รายการแล้ว จากข้อมูลที่มีอยู่ในออบเจ็กต์ DSLการล็อก DSL: ขณะนี้ระบบล็อก DSL และไม่สามารถเปลี่ยนแปลงได้
beforeVariants()
: Callback นี้อาจส่งผลต่อการสร้างคอมโพเนนต์ และพร็อพเพอร์ตี้บางรายการผ่านVariantBuilder
แต่ยังทำให้ การแก้ไขโฟลว์ของบิลด์และอาร์ติแฟกต์ที่สร้างขึ้นการสร้างตัวแปร: รายการคอมโพเนนต์และอาร์ติแฟกต์ที่จะ ที่สร้างขึ้น ได้รับการสรุปผลแล้วและไม่สามารถเปลี่ยนแปลงได้
onVariants()
: ในการติดต่อกลับนี้ คุณจะได้รับสิทธิ์เข้าถึงVariant
ที่สร้างขึ้น และคุณสามารถตั้งค่าหรือผู้ให้บริการสำหรับค่าProperty
ของออบเจ็กต์ดังกล่าว คำนวณแบบ Lazy Loadingการล็อกตัวแปร: ตอนนี้ออบเจ็กต์ตัวแปรถูกล็อก และจะไม่มีการเปลี่ยนแปลงอีกต่อไป เท่าที่จะเป็นไปได้
สร้างงานแล้ว: มีการใช้ออบเจ็กต์
Variant
และค่าProperty
เพื่อ สร้างอินสแตนซ์Task
ที่จำเป็นต่อการดำเนินการสร้าง
AGP เปิดตัว
AndroidComponentsExtension
ซึ่งช่วยให้
คุณลงทะเบียน Callback สำหรับ 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 ->
...
}
}
}
มาดูรายละเอียดของ Callback ที่มีและประเภทของ Use Case กัน ที่ปลั๊กอินของคุณสามารถรองรับในแต่ละปลั๊กอินได้
finalizeDsl(callback: (DslExtensionT) -> Unit)
ใน Callback นี้ คุณสามารถเข้าถึงและแก้ไขออบเจ็กต์ 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
}
}
การเรียกกลับของ beforeVariants()
จะใช้ VariantSelector
หรือไม่ก็ได้ ซึ่งคุณสามารถ
ผ่านเมธอด selector()
ใน androidComponentsExtension
คุณสามารถ
ใช้หน้านี้เพื่อกรองคอมโพเนนต์ที่เข้าร่วมการเรียกใช้ Callback โดยอิงตาม
ชื่อ ประเภทบิลด์ หรือรสชาติของผลิตภัณฑ์
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.
...
}
}
ดูสูตร addCustomAsset เพื่อดูรายละเอียดเพิ่มเติม
เข้าถึงและแก้ไขอาร์ติแฟกต์
นอกจากให้คุณแก้ไขคุณสมบัติอย่างง่ายในออบเจ็กต์ Variant
แล้ว AGP ยัง
ยังมีกลไกส่วนขยายที่ช่วยให้คุณอ่านหรือเปลี่ยนรูปแบบ
อาร์ติแฟกต์ขั้นกลางและสุดท้ายที่ผลิตขึ้นระหว่างบิลด์ ตัวอย่างเช่น คุณสามารถ
อ่านเนื้อหาสุดท้ายที่ผสานรวมAndroidManifest.xml
ในไฟล์ใน Task
ที่กำหนดเองเพื่อ
วิเคราะห์ไฟล์ หรือจะแทนที่เนื้อหาทั้งหมดด้วยไฟล์ Manifest
ที่สร้างโดย Task
ที่คุณกำหนดเอง
คุณดูรายการอาร์ติแฟกต์ที่รองรับในปัจจุบันได้ในข้อมูลอ้างอิง
สำหรับชั้นเรียน Artifact
อาร์ติแฟกต์ทุกประเภทมีคุณสมบัติบางอย่างที่มีประโยชน์สิ่งที่ควรทราบ ได้แก่
จำนวนสมาชิกในเซ็ต
Cardinality ของ Artifact
หมายถึงจํานวน FileSystemLocation
หรือจำนวนไฟล์หรือไดเรกทอรีของประเภทอาร์ติแฟกต์ คุณสามารถ
ดูข้อมูลเกี่ยวกับ Cardinality ของอาร์ติแฟกต์โดยตรวจสอบระดับบนสุดของอาร์ติแฟกต์
class: อาร์ติแฟกต์ที่มี 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
พร้อมอาร์ติแฟกต์เวอร์ชันสุดท้าย
(หลังจากที่การดำเนินการทั้งหมดเสร็จสิ้นแล้ว)
ปลั๊กอินหลายรายการจะเพิ่มการดำเนินการบนอาร์ติแฟกต์ในไปป์ไลน์ได้ไม่จำกัดจำนวน
จาก Callback onVariants()
และ 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
- การหลีกเลี่ยงการกำหนดค่างาน