โดยปกติแล้ว แอปพลิเคชัน Android จะสร้างขึ้นโดยใช้ระบบบิลด์ Gradle ก่อนที่จะเจาะลึกรายละเอียดวิธีกำหนดค่าบิลด์ เราจะ สำรวจแนวคิดเบื้องหลังบิลด์เพื่อให้คุณเห็นระบบโดยรวม
บิลด์คืออะไร
ระบบบิลด์จะเปลี่ยนซอร์สโค้ดให้เป็นแอปพลิเคชันที่เรียกใช้งานได้ การสร้างมักเกี่ยวข้องกับเครื่องมือหลายอย่างเพื่อวิเคราะห์ คอมไพล์ ลิงก์ และแพ็กเกจแอปพลิเคชันหรือไลบรารี Gradle ใช้แนวทางที่อิงตามงานเพื่อจัดระเบียบและเรียกใช้ คำสั่งเหล่านี้
งานจะห่อหุ้มคำสั่งที่แปลอินพุตเป็นเอาต์พุต
ปลั๊กอินกำหนดงานและการกำหนดค่าของงาน การใช้ปลั๊กอินกับบิลด์จะลงทะเบียนงานของปลั๊กอินและเชื่อมโยงงานเหล่านั้นเข้าด้วยกันโดยใช้
อินพุตและเอาต์พุตของงาน เช่น การใช้ปลั๊กอิน Android Gradle (AGP)
กับไฟล์บิลด์จะลงทะเบียนงานทั้งหมดที่จำเป็นต่อการสร้าง APK หรือ
คลัง Android java-library ปลั๊กอินช่วยให้คุณสร้างไฟล์ JAR จากซอร์สโค้ด Java ได้
นอกจากนี้ยังมีปลั๊กอินที่คล้ายกันสำหรับ Kotlin และภาษาอื่นๆ แต่ปลั๊กอินอื่นๆ
มีไว้เพื่อขยายปลั๊กอิน เช่น ปลั๊กอิน protobuf มีไว้เพื่อเพิ่ม
การรองรับ Protobuf ให้กับปลั๊กอินที่มีอยู่ เช่น AGP หรือ java-library
Gradle ชอบใช้กฎเกณฑ์มากกว่าการกำหนดค่า ดังนั้นปลั๊กอินจึงมาพร้อมค่าเริ่มต้นที่ดี ตั้งแต่แรก แต่คุณสามารถกำหนดค่าบิลด์เพิ่มเติมผ่านภาษาเฉพาะโดเมน (DSL) แบบประกาศได้ DSL ออกแบบมาเพื่อให้คุณระบุได้ว่าต้องการสร้างอะไร แทนที่จะระบุวิธีสร้าง ตรรกะใน ปลั๊กอินจะจัดการ "วิธีการ" การกำหนดค่าดังกล่าวระบุไว้ในไฟล์บิลด์หลายไฟล์ในโปรเจ็กต์ (และโปรเจ็กต์ย่อย)
อินพุตของงานอาจเป็นไฟล์และไดเรกทอรี รวมถึงข้อมูลอื่นๆ ที่เข้ารหัสเป็น ประเภท Java (จำนวนเต็ม สตริง หรือคลาสที่กำหนดเอง) เอาต์พุตต้องเป็นไดเรกทอรี หรือไฟล์เท่านั้น เนื่องจากต้องเขียนลงในดิสก์ การเชื่อมต่อเอาต์พุตของงานเข้ากับอินพุตของอีกงานหนึ่งจะลิงก์งานเข้าด้วยกันเพื่อให้งานหนึ่งต้องทำงานก่อนอีกงานหนึ่ง
แม้ว่า Gradle จะรองรับการเขียนโค้ดและการประกาศงานที่กำหนดเองในไฟล์บิลด์ แต่การทำเช่นนี้อาจทำให้เครื่องมือต่างๆ เข้าใจบิลด์ได้ยากขึ้น และทำให้คุณดูแลรักษาได้ยากขึ้น เช่น คุณเขียนการทดสอบสำหรับโค้ดภายในปลั๊กอินได้ แต่จะเขียนในไฟล์บิลด์ไม่ได้ แต่คุณควรจำกัดตรรกะการบิลด์และการประกาศงานไว้ในปลั๊กอิน (ที่คุณหรือผู้อื่นกำหนด) และประกาศวิธีที่คุณต้องการใช้ตรรกะดังกล่าวในไฟล์บิลด์
จะเกิดอะไรขึ้นเมื่อเรียกใช้ Gradle Build
การสร้าง Gradle จะทำงานใน 3 เฟส แต่ละเฟสจะเรียกใช้โค้ดส่วนต่างๆ ที่คุณกำหนดไว้ในไฟล์บิลด์
- การเริ่มต้นจะกำหนดว่าควรรวมโปรเจ็กต์และโปรเจ็กต์ย่อยใดไว้ใน บิลด์ และตั้งค่าเส้นทางของคลาสที่มีไฟล์บิลด์และปลั๊กอินที่ใช้ ในขั้นตอนนี้จะเน้นที่ไฟล์การตั้งค่าซึ่งคุณประกาศโปรเจ็กต์ที่จะสร้างและตำแหน่งที่จะดึงข้อมูลปลั๊กอินและไลบรารี
- การกำหนดค่าจะลงทะเบียนงานสำหรับแต่ละโปรเจ็กต์ และเรียกใช้ไฟล์บิลด์ เพื่อใช้ข้อกำหนดการบิลด์ของผู้ใช้ คุณควรทราบว่าโค้ดการกำหนดค่าจะไม่มีสิทธิ์เข้าถึงข้อมูลหรือไฟล์ที่สร้างขึ้นระหว่างการดำเนินการ
- การดำเนินการจะ "สร้าง" แอปพลิเคชันของคุณจริง เอาต์พุต ของการกำหนดค่าคือ Directed Acyclic Graph (DAG) ของงาน ซึ่งแสดงขั้นตอนการสร้างที่จำเป็นทั้งหมดที่ผู้ใช้ร้องขอ (งานที่ระบุในบรรทัดคำสั่งหรือเป็นค่าเริ่มต้นในไฟล์บิลด์) กราฟนี้แสดงความสัมพันธ์ระหว่างงาน ไม่ว่าจะระบุไว้อย่างชัดเจนในการประกาศของงาน หรืออิงตามอินพุตและเอาต์พุตของงาน หากงานมีอินพุตที่เป็นเอาต์พุตของงานอื่น งานนั้นจะต้องทำงานหลังจากงานอื่น เฟสนี้จะเรียกใช้งานที่ล้าสมัยตามลำดับที่กำหนดไว้ในกราฟ หากอินพุตของงานไม่มีการเปลี่ยนแปลงตั้งแต่การดำเนินการครั้งล่าสุด Gradle จะข้ามงานนั้น
ดูข้อมูลเพิ่มเติมได้ที่วงจรการสร้างของ Gradle
DSL การกำหนดค่า
Gradle ใช้ภาษาเฉพาะของโดเมน (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) } // ... } }
Groovy
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 จะแสดงด้วยฟังก์ชันที่ใช้ Lambda เพื่อกำหนดค่า และพร็อพเพอร์ตี้ที่มีชื่อเดียวกันเพื่อเข้าถึง ซึ่งจะทำให้ โค้ดในไฟล์บิลด์ดูเหมือนข้อกำหนดข้อมูลมากขึ้น
ทรัพยากร Dependency ภายนอก
ระบบบิลด์ Maven ได้เปิดตัวข้อกำหนด Dependency ระบบจัดเก็บและจัดการ ไลบรารีจะจัดเก็บไว้ในที่เก็บ (เซิร์ฟเวอร์หรือไดเรกทอรี) พร้อมข้อมูลเมตา ซึ่งรวมถึงเวอร์ชันและไลบรารีอื่นๆ ที่ขึ้นต่อกัน คุณระบุที่เก็บที่จะค้นหา เวอร์ชันของทรัพยากร Dependency ที่ต้องการใช้ และระบบบิลด์จะดาวน์โหลดทรัพยากรเหล่านั้นในระหว่างการบิลด์
ระบบจะระบุ Artifact ของ Maven ตามชื่อกลุ่ม (บริษัท นักพัฒนาแอป ฯลฯ) ชื่อ Artifact (ชื่อของไลบรารี) และเวอร์ชันของ Artifact นั้น โดยทั่วไปแล้วจะแสดงเป็น group:artifact:version
วิธีนี้ช่วยปรับปรุงการจัดการบิลด์ได้อย่างมาก คุณมักจะได้ยินคนเรียกที่เก็บดังกล่าวว่า "ที่เก็บ Maven" แต่จริงๆ แล้วเป็นเรื่องของวิธีแพ็กเกจและเผยแพร่อาร์ติแฟกต์ ที่เก็บและข้อมูลเมตาเหล่านี้ถูกนำกลับมาใช้ในระบบบิลด์หลายระบบ รวมถึง Gradle (และ Gradle สามารถเผยแพร่ไปยังที่เก็บเหล่านี้ได้) ที่เก็บข้อมูลสาธารณะอนุญาตให้แชร์เพื่อให้ทุกคนใช้ได้ และ ที่เก็บข้อมูลของบริษัทจะเก็บการอ้างอิงภายในไว้ภายใน
นอกจากนี้ คุณยังแยกส่วนโปรเจ็กต์ออกเป็นโปรเจ็กต์ย่อย (หรือที่เรียกว่า "โมดูล" ใน Android Studio) ซึ่งใช้เป็น การอ้างอิงได้ด้วย แต่ละโปรเจ็กต์ย่อยจะสร้างเอาต์พุต (เช่น ไฟล์ JAR) ที่โปรเจ็กต์ย่อยหรือโปรเจ็กต์ระดับบนสุดใช้ได้ ซึ่งจะช่วยปรับปรุงเวลาในการบิลด์ ด้วยการแยกส่วนที่ต้องสร้างใหม่ รวมถึงแยก ความรับผิดชอบในแอปพลิเคชันได้ดียิ่งขึ้น
เราจะดูรายละเอียดเพิ่มเติมเกี่ยวกับวิธีระบุการอ้างอิงในเพิ่มการอ้างอิงบิลด์
ตัวแปรบิลด์
เมื่อสร้างแอปพลิเคชัน Android โดยปกติแล้วคุณจะต้องการสร้างตัวแปรหลายรายการ รูปแบบมีโค้ดที่แตกต่างกันหรือสร้างขึ้นด้วย ตัวเลือกที่แตกต่างกัน และประกอบด้วยประเภทบิลด์และ Product Flavor
ประเภทบิลด์จะแตกต่างกันไปตามตัวเลือกบิลด์ที่ประกาศ โดยค่าเริ่มต้น AGP จะตั้งค่าประเภทบิลด์ "รีลีส" และ "แก้ไขข้อบกพร่อง" แต่คุณสามารถปรับค่าและเพิ่มค่าอื่นๆ ได้ (อาจใช้สำหรับการ จัดเตรียมข้อมูลหรือการทดสอบภายใน)
บิลด์สำหรับแก้ไขข้อบกพร่องจะไม่ลดขนาดหรือทำให้แอปพลิเคชันของคุณอ่านยากขึ้น ซึ่งจะช่วยเร่งการบิลด์และรักษาทุกสัญลักษณ์ไว้ตามเดิม นอกจากนี้ยังทำเครื่องหมายแอปพลิเคชันเป็น "แก้ไขข้อบกพร่องได้" โดยลงนามด้วยคีย์การแก้ไขข้อบกพร่องทั่วไปและเปิดใช้การเข้าถึงไฟล์แอปพลิเคชันที่ติดตั้งในอุปกรณ์ ซึ่งจะช่วยให้คุณสำรวจข้อมูลที่บันทึกไว้ในไฟล์และฐานข้อมูลขณะเรียกใช้แอปพลิเคชันได้
บิลด์รุ่นจะเพิ่มประสิทธิภาพแอปพลิเคชัน รับรองด้วยคีย์รุ่น และ ปกป้องไฟล์แอปพลิเคชันที่ติดตั้ง
การใช้รุ่นของผลิตภัณฑ์ช่วยให้คุณเปลี่ยนแหล่งที่มาและตัวแปร การอ้างอิงที่รวมไว้สำหรับแอปพลิเคชันได้ เช่น คุณอาจต้องการสร้างรสชาติ "เดโม" และ "เต็ม" สำหรับแอปพลิเคชัน หรืออาจเป็นรสชาติ "ฟรี" และ "แบบชำระเงิน" คุณเขียนแหล่งที่มาทั่วไปในไดเรกทอรีชุดแหล่งที่มา "หลัก" และ ลบล้างหรือเพิ่มแหล่งที่มาในชุดแหล่งที่มาที่ตั้งชื่อตามรสชาติ
AGP จะสร้างตัวแปรสำหรับชุดค่าผสมแต่ละชุดของประเภทบิลด์และรสชาติของผลิตภัณฑ์ หากไม่ได้กำหนด Flavor ระบบจะตั้งชื่อตัวแปรตามประเภทบิลด์ หากคุณ
กำหนดทั้ง 2 อย่าง ระบบจะตั้งชื่อตัวแปรเป็น <flavor><Buildtype> ตัวอย่างเช่น เมื่อมีประเภทบิลด์ release และ debug รวมถึงเวอร์ชัน demo และ full AGP จะสร้างตัวแปรต่อไปนี้
demoReleasedemoDebugfullReleasefullDebug
ขั้นตอนถัดไป
ตอนนี้คุณได้เห็นแนวคิดการสร้างแล้ว ลองดูโครงสร้างการสร้าง Android ในโปรเจ็กต์