ภาพรวมของบิลด์ Gradle

โดยปกติแล้ว แอปพลิเคชัน 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 = 34
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk = 34
        // ...
    }
}

Groovy

android {
    namespace 'com.example.myapplication'
    compileSdk 34
    // ...

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 24
        // ...
    }
}

เบื้องหลังการทำงาน รหัส DSL จะคล้ายกับ

fun Project.android(configure: ApplicationExtension.() -> Unit) {
    ...
}

interface ApplicationExtension {
    var compileSdk: Int
    var namespace: String?

    val defaultConfig: DefaultConfig

    fun defaultConfig(configure: DefaultConfig.() -> Unit) {
        ...
    }
}

แต่ละบล็อกใน DSL จะแสดงโดยฟังก์ชันที่ใช้ LAMBDA เพื่อกําหนดค่า และพร็อพเพอร์ตี้ที่มีชื่อเดียวกันเพื่อเข้าถึง ทำให้โค้ดในไฟล์บิลด์ดูเหมือนเป็นข้อกำหนดในการจัดทำข้อมูลมากขึ้น

ทรัพยากร Dependency ภายนอก

ระบบบิลด์ Maven ได้เปิดตัวข้อกำหนด dependency, ระบบพื้นที่เก็บข้อมูล และระบบการจัดการ ไลบรารีจะจัดเก็บอยู่ในที่เก็บ (เซิร์ฟเวอร์หรือไดเรกทอรี) พร้อมข้อมูลเมตาซึ่งรวมถึงเวอร์ชันและทรัพยากร Dependency ในไลบรารีอื่นๆ คุณจะระบุที่เก็บถาวรที่จะค้นหา เวอร์ชันของข้อกำหนดซึ่งคุณต้องการใช้ และระบบการสร้างจะดาวน์โหลดข้อมูลเหล่านั้นระหว่างการสร้าง

อาร์ติแฟกต์ Maven จะระบุด้วยชื่อกลุ่ม (บริษัท นักพัฒนาแอป ฯลฯ) ชื่ออาร์ติแฟกต์ (ชื่อไลบรารี) และเวอร์ชันของอาร์ติแฟกต์นั้น ซึ่งมักจะแสดงเป็น group:artifact:version

แนวทางนี้ช่วยปรับปรุงการจัดการบิลด์ได้อย่างมาก คุณมักจะได้ยินที่เก็บข้อมูลดังกล่าวเรียกว่า "ที่เก็บ Maven" แต่ทั้งหมดนี้เกี่ยวข้องกับวิธีแพ็กเกจและเผยแพร่อาร์ติแฟกต์ ระบบบิลด์หลายระบบใช้ที่เก็บและข้อมูลเมตาเหล่านี้ซ้ำ ซึ่งรวมถึง Gradle (และ Gradle สามารถเผยแพร่ไปยังที่เก็บเหล่านี้ได้) ที่เก็บข้อมูลสาธารณะอนุญาตให้แชร์กับทุกคน ส่วนที่เก็บข้อมูลของบริษัทจะเก็บข้อมูลที่เกี่ยวข้องภายในไว้

นอกจากนี้ คุณยังแยกโปรเจ็กต์ออกเป็นโมดูลเป็นโปรเจ็กต์ย่อย (หรือที่เรียกว่า "โมดูล" ใน Android Studio) ซึ่งสามารถใช้เป็นข้อกำหนดได้อีกด้วย โปรเจ็กต์ย่อยแต่ละโปรเจ็กต์จะสร้างเอาต์พุต (เช่น Jar) ที่โปรเจ็กต์ย่อยหรือโปรเจ็กต์ระดับบนสุดของคุณนำไปใช้ได้ ซึ่งจะช่วยปรับปรุงเวลาบิลด์โดยการแยกส่วนที่ต้องสร้างขึ้นมาใหม่ ตลอดจนแยกความรับผิดชอบในแอปพลิเคชันได้ดีขึ้น

เราจะอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับวิธีระบุการพึ่งพาในหัวข้อเพิ่มการพึ่งพาบิลด์

ตัวแปรของบิลด์

เมื่อสร้างแอปพลิเคชัน Android ปกติแล้วคุณจะต้องสร้างตัวแปรหลายรายการ ตัวแปรมีโค้ดที่แตกต่างกันหรือสร้างขึ้นด้วยตัวเลือกที่แตกต่างกัน และประกอบด้วยประเภทบิลด์และตัวแปรผลิตภัณฑ์

ประเภทบิลด์จะแตกต่างกันไปตามตัวเลือกบิลด์ที่ประกาศ โดยค่าเริ่มต้น AGP จะตั้งค่าประเภทบิลด์เป็น "รุ่น" และ "แก้ไขข้อบกพร่อง" แต่คุณสามารถปรับแต่งและเพิ่มประเภทอื่นๆ ได้ (เช่น สําหรับการทดสอบเวอร์ชันหรือทดสอบภายใน)

บิลด์สำหรับการแก้ไขข้อบกพร่องจะไม่ย่อขนาดหรือสร้างความสับสนให้กับแอปพลิเคชัน ซึ่งจะช่วยเร่งความเร็วในการสร้างและเก็บสัญลักษณ์ทั้งหมดไว้เหมือนเดิม นอกจากนี้ยังทำเครื่องหมายแอปพลิเคชันเป็น "แก้ไขข้อบกพร่องได้" ลงนามด้วยคีย์แก้ไขข้อบกพร่องทั่วไป และเปิดใช้การเข้าถึงไฟล์แอปพลิเคชันที่ติดตั้งในอุปกรณ์ ซึ่งทำให้คุณสำรวจข้อมูลที่บันทึกไว้ในไฟล์และฐานข้อมูลขณะเรียกใช้แอปพลิเคชันได้

บิลด์รุ่นจะเพิ่มประสิทธิภาพแอปพลิเคชัน รับรองด้วยคีย์รุ่น และปกป้องไฟล์แอปพลิเคชันที่ติดตั้ง

เมื่อใช้รสชาติของผลิตภัณฑ์ คุณสามารถเปลี่ยนแหล่งที่มาและตัวแปรการขึ้นต่อกันที่รวมอยู่สำหรับแอปพลิเคชันได้ เช่น คุณอาจต้องการสร้างรสชาติ "สาธิต" และ "เวอร์ชันเต็ม" ของแอปพลิเคชัน หรือรสชาติ "ฟรี" และ "มีค่าใช้จ่าย" คุณจะเขียนแหล่งที่มาทั่วไปในไดเรกทอรีชุดแหล่งที่มา "หลัก" และลบล้างหรือเพิ่มแหล่งที่มาในชุดแหล่งที่มาที่ตั้งชื่อตามรุ่น

AGP สร้างตัวแปรสําหรับชุดค่าผสมของประเภทบิลด์และเวอร์ชันผลิตภัณฑ์แต่ละรายการ หากไม่ได้กำหนด Flavor ระบบจะตั้งชื่อตัวแปรตามประเภทบิลด์ หากคุณกำหนดทั้ง 2 รายการ ระบบจะตั้งชื่อตัวแปรว่า <flavor><Buildtype> ตัวอย่างเช่น สำหรับประเภทบิลด์ release และ debug และเวอร์ชัน demo และ full จะทำให้ AGP สร้างตัวแปรดังนี้

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

ขั้นตอนถัดไป

เมื่อคุณเห็นแนวคิดการสร้างแล้ว ให้ดูโครงสร้างการสร้าง Android ในโปรเจ็กต์