ภาพรวมของบิลด์ 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 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 จะสร้างตัวแปรต่อไปนี้

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

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

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