โดยปกติแล้ว แอปพลิเคชัน Android จะสร้างขึ้นโดยใช้ระบบบิลด์ Gradle ก่อนที่จะเจาะลึกรายละเอียดวิธีกำหนดค่าบิลด์ เราจะ สำรวจแนวคิดเบื้องหลังบิลด์เพื่อให้คุณเห็นระบบโดยรวม
บิลด์คืออะไร
ระบบบิลด์จะเปลี่ยนซอร์สโค้ดให้เป็นแอปพลิเคชันที่เรียกใช้งานได้ การสร้างมักเกี่ยวข้องกับเครื่องมือหลายอย่างเพื่อวิเคราะห์ คอมไพล์ ลิงก์ และแพ็กเกจแอปพลิเคชันหรือไลบรารี Gradle ใช้แนวทางที่อิงตามงานเพื่อจัดระเบียบและเรียกใช้ คำสั่งเหล่านี้
งานจะห่อหุ้มคำสั่งที่แปลอินพุตเป็นเอาต์พุต
ปลั๊กอินกำหนดงานและการกำหนดค่าของงาน การใช้
ปลั๊กอินกับบิลด์จะลงทะเบียนงานของปลั๊กอินและเชื่อมโยงงานเหล่านั้นเข้าด้วยกันโดยใช้
อินพุตและเอาต์พุตของงาน เช่น การใช้ปลั๊กอิน Android Gradle (AGP)
กับไฟล์บิลด์จะลงทะเบียนงานทั้งหมดที่จำเป็นต่อการสร้าง APK หรือ
ไลบรารี Android java-library ปลั๊กอินช่วยให้คุณสร้างไฟล์ JAR จากซอร์สโค้ด Java ได้
นอกจากนี้ยังมีปลั๊กอินที่คล้ายกันสำหรับ Kotlin และภาษาอื่นๆ แต่ปลั๊กอินอื่นๆ
มีไว้เพื่อขยายปลั๊กอิน เช่น ปลั๊กอิน protobuf มีไว้เพื่อเพิ่ม
การรองรับ Protobuf ให้กับปลั๊กอินที่มีอยู่ เช่น AGP หรือ java-library
Gradle ชอบใช้กฎเกณฑ์มากกว่าการกำหนดค่า ดังนั้นปลั๊กอินจึงมาพร้อมค่าเริ่มต้นที่ดี ตั้งแต่แรก แต่คุณสามารถกำหนดค่าบิลด์เพิ่มเติมผ่านภาษาเฉพาะโดเมน (DSL) แบบประกาศได้ DSL ออกแบบมาเพื่อให้คุณระบุได้ว่าต้องการสร้างอะไร แทนที่จะระบุวิธีสร้าง ตรรกะใน ปลั๊กอินจะจัดการ "วิธีการ" การกำหนดค่าดังกล่าวระบุไว้ในไฟล์บิลด์หลายไฟล์ในโปรเจ็กต์ (และโปรเจ็กต์ย่อย)
อินพุตของงานอาจเป็นไฟล์และไดเรกทอรี รวมถึงข้อมูลอื่นๆ ที่เข้ารหัสเป็น ประเภท Java (จำนวนเต็ม สตริง หรือคลาสที่กำหนดเอง) เอาต์พุตต้องเป็นไดเรกทอรี หรือไฟล์เท่านั้น เนื่องจากต้องเขียนลงในดิสก์ การเชื่อมต่อเอาต์พุตของงานเข้ากับอินพุตของอีกงานหนึ่งจะลิงก์งานเข้าด้วยกันเพื่อให้งานหนึ่งต้องทำงานก่อนอีกงานหนึ่ง
แม้ว่า Gradle จะรองรับการเขียนโค้ดและการประกาศงานที่กำหนดเองในไฟล์บิลด์ แต่การทำเช่นนี้อาจทำให้เครื่องมือต่างๆ เข้าใจบิลด์ได้ยากขึ้น และทำให้คุณดูแลรักษาได้ยากขึ้น เช่น คุณสามารถเขียนการทดสอบสำหรับโค้ดภายในปลั๊กอิน แต่จะเขียนในไฟล์บิลด์ไม่ได้ แต่คุณควรจำกัดตรรกะการบิลด์และการประกาศงานไว้ในปลั๊กอิน (ที่คุณหรือผู้อื่นกำหนด) และประกาศวิธีที่คุณต้องการใช้ตรรกะดังกล่าวในไฟล์บิลด์
จะเกิดอะไรขึ้นเมื่อเรียกใช้การสร้าง Gradle
การบิลด์ 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 ที่ต้องการใช้ และระบบบิลด์จะดาวน์โหลด Dependency เหล่านั้นในระหว่างการบิลด์
ระบบจะระบุ Maven Artifacts ตามชื่อกลุ่ม (บริษัท นักพัฒนาแอป ฯลฯ) ชื่อ 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 ในโปรเจ็กต์