โดยปกติแล้วแอปพลิเคชัน Android จะสร้างขึ้นโดยใช้ระบบบิลด์ Gradle ก่อนที่จะลงรายละเอียดเกี่ยวกับวิธีกำหนดค่าบิลด์ เราจะมาดูแนวคิดเบื้องหลังบิลด์เพื่อให้คุณเห็นภาพรวมของระบบ
บิลด์คืออะไร
ระบบบิลด์จะแปลงซอร์สโค้ดเป็นแอปพลิเคชันที่เรียกใช้งานได้ บิลด์มักจะเกี่ยวข้องกับเครื่องมือหลายอย่างเพื่อวิเคราะห์ คอมไพล์ ลิงก์ และแพ็กเกจแอปพลิเคชันหรือไลบรารี Gradle ใช้แนวทางที่อิงตามงานเพื่อจัดระเบียบและเรียกใช้คำสั่งเหล่านี้
งานจะห่อหุ้มคำสั่งที่แปลอินพุตเป็น
เอาต์พุต ปลั๊กอินจะกำหนดงานและการกำหนดค่าของงาน การใช้ปลั๊กอินกับบิลด์จะลงทะเบียนงานของปลั๊กอินและเชื่อมโยงงานเข้าด้วยกันโดยใช้อินพุตและเอาต์พุต ตัวอย่างเช่น การใช้ ปลั๊กอิน Android Gradle (AGP)
กับไฟล์บิลด์จะลงทะเบียนงานทั้งหมดที่จำเป็นในการสร้าง APK หรือ
Android Library ปลั๊กอิน java-library ช่วยให้คุณสร้าง jar จากซอร์สโค้ด Java ได้ นอกจากนี้ยังมีปลั๊กอินที่คล้ายกันสำหรับ Kotlin และภาษาอื่นๆ แต่ปลั๊กอินอื่นๆ มีไว้เพื่อขยายปลั๊กอิน ตัวอย่างเช่น ปลั๊กอิน protobuf มีไว้เพื่อเพิ่มการรองรับ protobuf ให้กับปลั๊กอินที่มีอยู่ เช่น AGP หรือ java-library
Gradle ชอบการกำหนดค่าตามธรรมเนียม ดังนั้นปลั๊กอินจะมีค่าเริ่มต้นที่ดี พร้อมใช้งาน แต่คุณสามารถกำหนดค่าบิลด์เพิ่มเติมผ่าน Domain-Specific Language (DSL) แบบประกาศได้ DSL ได้รับการออกแบบมาเพื่อให้คุณระบุ สิ่งที่ จะสร้างได้ แทนที่จะระบุ วิธี สร้าง ตรรกะในปลั๊กอินจะจัดการ "วิธี" การกำหนดค่าดังกล่าวจะระบุไว้ในไฟล์ บิลด์หลายไฟล์ในโปรเจ็กต์ (และโปรเจ็กต์ย่อย)
อินพุตของงานอาจเป็นไฟล์และไดเรกทอรี รวมถึงข้อมูลอื่นๆ ที่เข้ารหัสเป็นประเภท Java (จำนวนเต็ม สตริง หรือคลาสที่กำหนดเอง) เอาต์พุตอาจเป็นไดเรกทอรีหรือไฟล์เท่านั้น เนื่องจากต้องเขียนลงในดิสก์ การเชื่อมโยงเอาต์พุตของงานหนึ่งไปยังอินพุตของอีกงานหนึ่งจะลิงก์งานเข้าด้วยกันเพื่อให้งานหนึ่งต้องทำงานก่อนอีกงานหนึ่ง
แม้ว่า Gradle จะรองรับการเขียนโค้ดและการประกาศงานที่กำหนดเองในไฟล์บิลด์ แต่การดำเนินการดังกล่าวอาจทำให้เครื่องมือต่างๆ เข้าใจบิลด์ได้ยากขึ้นและคุณดูแลรักษาได้ยากขึ้น ตัวอย่างเช่น คุณสามารถเขียนการทดสอบสำหรับโค้ดภายในปลั๊กอินได้ แต่เขียนในไฟล์บิลด์ไม่ได้ คุณควรจำกัดตรรกะบิลด์และการประกาศงานไว้ที่ปลั๊กอิน (ที่คุณหรือผู้อื่นกำหนด) และประกาศวิธีที่คุณต้องการใช้ตรรกะดังกล่าวในไฟล์บิลด์
จะเกิดอะไรขึ้นเมื่อบิลด์ Gradle ทำงาน
บิลด์ Gradle จะทำงานใน 3 ระยะ แต่ละระยะจะเรียกใช้โค้ดส่วนต่างๆ ที่คุณกำหนดไว้ในไฟล์บิลด์
- การเริ่มต้น จะกำหนดว่าโปรเจ็กต์และโปรเจ็กต์ย่อยใดบ้างที่จะรวมไว้ในบิลด์ และตั้งค่า Classpath ที่มีไฟล์บิลด์และปลั๊กอินที่ใช้ ระยะนี้จะเน้นที่ไฟล์การตั้งค่าที่คุณประกาศโปรเจ็กต์ที่จะสร้างและตำแหน่งที่จะดึงปลั๊กอินและไลบรารี
- การกำหนดค่า จะลงทะเบียนงานสำหรับแต่ละโปรเจ็กต์ และเรียกใช้ไฟล์บิลด์เพื่อใช้ข้อกำหนดบิลด์ของผู้ใช้ คุณต้องเข้าใจว่าโค้ดการกำหนดค่าจะไม่มีสิทธิ์เข้าถึงข้อมูลหรือไฟล์ที่สร้างขึ้นระหว่างการดำเนินการ
- การดำเนินการ จะดำเนินการ "สร้าง" แอปพลิเคชันจริง เอาต์พุต ของการกำหนดค่าคือ Directed Acyclic Graph (DAG) ของงาน ซึ่งแสดงถึงขั้นตอนการสร้างทั้งหมดที่ผู้ใช้ขอ (งานที่ระบุในบรรทัดคำสั่งหรือเป็นค่าเริ่มต้นในไฟล์บิลด์) กราฟนี้แสดงถึงความสัมพันธ์ระหว่างงาน ไม่ว่าจะเป็นความสัมพันธ์ที่ชัดเจนในการประกาศงาน หรือความสัมพันธ์ที่อิงตามอินพุตและเอาต์พุตของงาน หากงานหนึ่งมีอินพุตที่เป็นเอาต์พุตของอีกงานหนึ่ง งานนั้นจะต้องทำงานหลังจากอีกงานหนึ่ง ระยะนี้จะเรียกใช้งานที่ล้าสมัยตามลำดับที่กำหนดไว้ในกราฟ หากอินพุตของงานไม่เปลี่ยนแปลงนับตั้งแต่การดำเนินการครั้งล่าสุด Gradle จะข้ามงานนั้น
ดูข้อมูลเพิ่มเติมได้ที่วงจรการสร้าง Gradle
DSL การกำหนดค่า
Gradle ใช้ Domain-Specific Language (DSL) เพื่อกำหนดค่า บิลด์ แนวทางแบบประกาศนี้จะเน้นที่การระบุข้อมูลของคุณแทนการเขียนวิธีการทีละขั้นตอน (แบบบังคับ) คุณสามารถเขียนไฟล์บิลด์โดยใช้ Kotlin หรือ Groovy ก็ได้ แต่เราขอแนะนำให้ใช้ Kotlin
DSL พยายามทำให้ทุกคน ทั้งผู้เชี่ยวชาญด้านโดเมนและโปรแกรมเมอร์ มีส่วนร่วมในโปรเจ็กต์ได้ง่ายขึ้น โดยกำหนดภาษาขนาดเล็กที่แสดงข้อมูลในลักษณะที่เป็นธรรมชาติมากขึ้น ปลั๊กอิน Gradle สามารถขยาย DSL เพื่อกำหนดค่าข้อมูลที่จำเป็นสำหรับงานของตนได้
ตัวอย่างเช่น การกำหนดค่าส่วน Android ของบิลด์อาจมีลักษณะดังนี้
Kotlin
android { namespace = "com.example.app" compileSdk { version = release(36) { minorApiLevel = 1 } } // ... defaultConfig { applicationId = "com.example.app" minSdk { version = release(23) } targetSdk { version = release(36) } // ... } }
ดึงดูด
android { namespace = 'com.example.app' compileSdk { version = release(36) { minorApiLevel = 1 } } // ... defaultConfig { applicationId = 'com.example.app' minSdk { version = release(23) } targetSdk { version = release(36) } // ... } }
เบื้องหลังโค้ด DSL จะมีลักษณะคล้ายกับโค้ดต่อไปนี้
fun Project.android(configure: ApplicationExtension.() -> Unit) {
...
}
interface ApplicationExtension {
var namespace: String?
fun compileSdk(configure: CompileSdkSpec.() -> Unit) {
...
}
val defaultConfig: DefaultConfig
fun defaultConfig(configure: DefaultConfig.() -> Unit) {
...
}
}
แต่ละบล็อกใน DSL จะแสดงด้วยฟังก์ชันที่ใช้แลมบ์ดาเพื่อกำหนดค่า และพร็อพเพอร์ตี้ที่มีชื่อเดียวกันเพื่อเข้าถึงบล็อก ซึ่งจะทำให้โค้ดในไฟล์บิลด์ดูเหมือนข้อกำหนดข้อมูลมากขึ้น
ทรัพยากร Dependency ภายนอก
ระบบบิลด์ Maven ได้นำเสนอระบบการระบุ ทรัพยากร Dependency การจัดเก็บ และการจัดการ ไลบรารีจะจัดเก็บไว้ใน ที่เก็บ (เซิร์ฟเวอร์หรือไดเรกทอรี) พร้อมข้อมูลเมตา ซึ่งรวมถึง เวอร์ชันและทรัพยากร Dependency ของไลบรารีอื่นๆ คุณระบุที่เก็บที่จะค้นหา เวอร์ชันของทรัพยากร Dependency ที่ต้องการใช้ และระบบบิลด์จะดาวน์โหลดทรัพยากร Dependency เหล่านั้นระหว่างบิลด์
Maven Artifacts จะระบุด้วยชื่อกลุ่ม (บริษัท นักพัฒนาแอป ฯลฯ) ชื่อ Artifact (ชื่อไลบรารี) และเวอร์ชันของ Artifact นั้น โดยทั่วไปจะแสดงเป็น group:artifact:version
แนวทางนี้ช่วยปรับปรุงการจัดการบิลด์ได้อย่างมาก คุณมักจะได้ยินที่เก็บดังกล่าวเรียกว่า "ที่เก็บ Maven" แต่ทั้งหมดนี้ขึ้นอยู่กับวิธีแพ็กเกจและเผยแพร่ Artifacts ที่เก็บและข้อมูลเมตาเหล่านี้ถูกนำกลับมาใช้ซ้ำในระบบบิลด์หลายระบบ รวมถึง Gradle (และ Gradle สามารถเผยแพร่ไปยังที่เก็บเหล่านี้ได้) ที่เก็บสาธารณะอนุญาตให้แชร์เพื่อให้ทุกคนใช้ได้ และที่เก็บของบริษัทจะเก็บทรัพยากร Dependency ภายในไว้ภายใน
นอกจากนี้ คุณยังแยกโปรเจ็กต์ออกเป็นโปรเจ็กต์ย่อย (หรือที่เรียกว่า "โมดูล" ใน Android Studio) ซึ่งสามารถใช้เป็น ทรัพยากร Dependency ได้ด้วย แต่ละโปรเจ็กต์ย่อยจะสร้างเอาต์พุต (เช่น jar) ที่โปรเจ็กต์ย่อยหรือโปรเจ็กต์ระดับบนสุดใช้ได้ การดำเนินการนี้สามารถปรับปรุงเวลาบิลด์ได้โดยการแยกส่วนที่ต้องสร้างใหม่ รวมถึงแยกความรับผิดชอบในแอปพลิเคชันได้ดียิ่งขึ้น
เราจะลงรายละเอียดเพิ่มเติมเกี่ยวกับวิธีระบุทรัพยากร Dependency ในหัวข้อ เพิ่มทรัพยากร Dependency ของบิลด์
ตัวแปรบิลด์
เมื่อสร้างแอปพลิเคชัน Android คุณมักจะต้องการสร้างตัวแปรหลายรายการ variants ตัวแปรมีโค้ดที่แตกต่างกันหรือสร้างขึ้นด้วยตัวเลือกที่แตกต่างกัน และประกอบด้วยประเภทบิลด์และเวอร์ชันผลิตภัณฑ์
ประเภทบิลด์จะแตกต่างกันไปตามตัวเลือกบิลด์ที่ประกาศ โดยค่าเริ่มต้น AGP จะตั้งค่าประเภทบิลด์ "release" และ "debug" แต่คุณสามารถปรับเปลี่ยนและเพิ่มประเภทบิลด์อื่นๆ ได้ (เช่น สำหรับการจัดเตรียมหรือการทดสอบภายใน)
บิลด์การแก้ไขข้อบกพร่องจะไม่ลดขนาดหรือปรับให้แอปพลิเคชันของคุณอ่านยาก ซึ่งจะช่วยเร่งความเร็วในการสร้างและรักษาอักขระทั้งหมดไว้ตามเดิม นอกจากนี้ยังทำเครื่องหมายแอปพลิเคชันเป็น "แก้ไขข้อบกพร่องได้" ลงนามด้วยคีย์ดีบักทั่วไป และเปิดใช้การเข้าถึงไฟล์แอปพลิเคชันที่ติดตั้งในอุปกรณ์ ซึ่งจะช่วยให้คุณสำรวจข้อมูลที่บันทึกไว้ในไฟล์และฐานข้อมูลขณะเรียกใช้แอปพลิเคชันได้
บิลด์ที่เผยแพร่จะเพิ่มประสิทธิภาพแอปพลิเคชัน ลงนามด้วยคีย์รีลีส และปกป้องไฟล์แอปพลิเคชันที่ติดตั้ง
การใช้เวอร์ชันผลิตภัณฑ์ช่วยให้คุณเปลี่ยนซอร์สและทรัพยากร Dependency ที่รวมไว้สำหรับแอปพลิเคชันได้ ตัวอย่างเช่น คุณอาจต้องการสร้างเวอร์ชัน "demo" และ "full" สำหรับแอปพลิเคชัน หรืออาจเป็นเวอร์ชัน "free" และ "paid" คุณเขียนซอร์สทั่วไปในไดเรกทอรี ชุดซอร์ส "main" และ ลบล้างหรือเพิ่มซอร์สในชุดซอร์สที่ตั้งชื่อตามเวอร์ชัน
AGP จะสร้างตัวแปรสำหรับชุดค่าผสมของประเภทบิลด์และเวอร์ชันผลิตภัณฑ์แต่ละชุด หากคุณไม่ได้กำหนดเวอร์ชัน ระบบจะตั้งชื่อตัวแปรตามประเภทบิลด์ หากคุณ
กำหนดทั้ง 2 อย่าง ระบบจะตั้งชื่อตัวแปรเป็น <flavor><Buildtype> ตัวอย่างเช่น หากมีประเภทบิลด์ release และ debug และเวอร์ชัน demo และ full AGP จะสร้างตัวแปรต่อไปนี้
demoReleasedemoDebugfullReleasefullDebug
ขั้นตอนถัดไป
เมื่อทำความเข้าใจแนวคิดเกี่ยวกับบิลด์แล้ว ให้ดูโครงสร้างบิลด์ Androidในโปรเจ็กต์