กำหนดค่าตัวแปรของบิวด์

หน้านี้แสดงวิธีกำหนดค่าตัวแปรบิลด์เพื่อสร้างแอปเวอร์ชันต่างๆ จากโปรเจ็กต์เดียว รวมถึงวิธีจัดการทรัพยากร Dependency และการกำหนดค่าการลงชื่ออย่างเหมาะสม

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

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

ตัวอย่างเช่น เวอร์ชันผลิตภัณฑ์ "เดโม" อาจระบุฟีเจอร์และข้อกำหนดของอุปกรณ์บางอย่าง เช่น ซอร์สโค้ดที่กำหนดเอง ทรัพยากร และระดับ API ขั้นต่ำ ขณะที่ประเภทบิลด์ "แก้ไขข้อบกพร่อง" จะใช้การตั้งค่าบิลด์และแพ็กเกจที่แตกต่างกัน เช่น ตัวเลือกการแก้ไขข้อบกพร่องและคีย์การรับรอง ตัวแปรบิลด์ที่รวม 2 รายการนี้เข้าด้วยกันคือเวอร์ชัน "demoDebug" ของแอป และประกอบด้วยการกำหนดค่าและทรัพยากรที่รวมอยู่ในเวอร์ชันผลิตภัณฑ์ "demo", ประเภทบิลด์ "debug" และชุดซอร์ส main/

กำหนดค่าประเภทบิลด์

คุณสร้างและกำหนดค่าประเภทบิลด์ได้ภายในบล็อก android ของไฟล์ build.gradle.kts ระดับโมดูล เมื่อคุณสร้างโมดูลใหม่ Android Studio จะสร้างประเภทบิลด์สำหรับการแก้ไขข้อบกพร่องและบิลด์ที่เผยแพร่โดยอัตโนมัติ แม้ว่าประเภทบิลด์การแก้ไขข้อบกพร่องจะไม่ปรากฏในไฟล์การกำหนดค่าบิลด์ แต่ Android Studio จะกำหนดค่าด้วย debuggable true ซึ่งจะช่วยให้คุณแก้ไขข้อบกพร่องของแอปในอุปกรณ์ Android ที่ปลอดภัยและกำหนดค่า App Signing ด้วยคีย์สโตร์การแก้ไขข้อบกพร่องทั่วไปได้

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

Kotlin

android {
    defaultConfig {
        manifestPlaceholders["hostName"] = "www.example.com"
        ...
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
        }

        getByName("debug") {
            applicationIdSuffix = ".debug"
            isDebuggable = true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        create("staging") {
            initWith(getByName("debug"))
            manifestPlaceholders["hostName"] = "internal.example.com"
            applicationIdSuffix = ".debugStaging"
        }
    }
}

ดึงดูด

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
        ...
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        staging {
            initWith debug
            manifestPlaceholders = [hostName:"internal.example.com"]
            applicationIdSuffix ".debugStaging"
        }
    }
}

หมายเหตุ: เมื่อคุณทำการเปลี่ยนแปลงไฟล์การกำหนดค่าบิลด์ Android Studio จะกำหนดให้คุณซิงค์โปรเจ็กต์กับการกำหนดค่าใหม่ หากต้องการซิงค์โปรเจ็กต์ ให้คลิกซิงค์เลยในแถบการแจ้งเตือนที่ปรากฏขึ้นเมื่อคุณทำการเปลี่ยนแปลง หรือคลิกซิงค์โปรเจ็กต์ จากแถบเครื่องมือ หาก Android Studio พบข้อผิดพลาดในการกำหนดค่า หน้าต่างข้อความจะปรากฏขึ้นเพื่ออธิบายปัญหา

ดูข้อมูลเพิ่มเติมเกี่ยวกับพร็อพเพอร์ตี้ทั้งหมดที่คุณกำหนดค่าด้วยประเภทบิลด์ได้ที่ข้อมูลอ้างอิง BuildType

กำหนดค่าเวอร์ชันผลิตภัณฑ์

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

หมายเหตุ: คุณยังคงต้องระบุชื่อแพ็กเกจโดยใช้แอตทริบิวต์ package ในไฟล์ Manifest main/ นอกจากนี้ คุณต้องใช้ชื่อแพ็กเกจนั้นในซอร์สโค้ดเพื่ออ้างอิงถึงคลาส R หรือเพื่อแก้ไขการลงทะเบียนกิจกรรมหรือบริการที่เกี่ยวข้อง ซึ่งจะช่วยให้คุณใช้ applicationId เพื่อกำหนดรหัสที่ไม่ซ้ำกันให้กับเวอร์ชันผลิตภัณฑ์แต่ละเวอร์ชันสำหรับการแพ็กเกจและการจัดจำหน่ายโดยไม่ต้องเปลี่ยนซอร์สโค้ด

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

  Error: All flavors must now belong to a named flavor dimension.
  The flavor 'flavor_name' is not assigned to a flavor dimension.

หากโมดูลหนึ่งๆ ระบุมิติข้อมูลของเวอร์ชันเพียงรายการเดียว ปลั๊กอิน Android Gradle จะกำหนดเวอร์ชันทั้งหมดของโมดูลให้กับมิติข้อมูลนั้นโดยอัตโนมัติ

ตัวอย่างโค้ดต่อไปนี้จะสร้างมิติข้อมูลของเวอร์ชันชื่อ "version" และเพิ่มเวอร์ชันผลิตภัณฑ์ "demo" และ "full" เวอร์ชันเหล่านี้มี applicationIdSuffix และ versionNameSuffix ของตัวเอง ดังนี้

Kotlin

android {
    ...
    defaultConfig {...}
    buildTypes {
        getByName("debug"){...}
        getByName("release"){...}
    }
    // Specifies one flavor dimension.
    flavorDimensions += "version"
    productFlavors {
        create("demo") {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension = "version"
            applicationIdSuffix = ".demo"
            versionNameSuffix = "-demo"
        }
        create("full") {
            dimension = "version"
            applicationIdSuffix = ".full"
            versionNameSuffix = "-full"
        }
    }
}

ดึงดูด

android {
    ...
    defaultConfig {...}
    buildTypes {
        debug{...}
        release{...}
    }
    // Specifies one flavor dimension.
    flavorDimensions "version"
    productFlavors {
        demo {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension "version"
            applicationIdSuffix ".demo"
            versionNameSuffix "-demo"
        }
        full {
            dimension "version"
            applicationIdSuffix ".full"
            versionNameSuffix "-full"
        }
    }
}

หมายเหตุ: หากคุณมีแอปเดิม (สร้างก่อนเดือนสิงหาคม 2021) ที่เผยแพร่โดยใช้ APK ใน Google Play หากต้องการเผยแพร่แอปโดยใช้การรองรับ APK หลายรายการใน Google Play ให้กำหนดค่า applicationId เดียวกันให้กับตัวแปรทั้งหมด และกำหนด versionCode ที่แตกต่างกันให้กับตัวแปรแต่ละรายการ หากต้องการจัดจำหน่ายตัวแปรต่างๆ ของแอปเป็นแอปแยกกันใน Google Play คุณต้องกำหนด applicationId ที่แตกต่างกันให้กับตัวแปรแต่ละรายการ

หลังจากสร้างและกำหนดค่าเวอร์ชันผลิตภัณฑ์แล้ว ให้คลิกซิงค์เลยในแถบการแจ้งเตือน เมื่อซิงค์เสร็จแล้ว Gradle จะสร้างตัวแปรบิลด์โดยอัตโนมัติตามประเภทบิลด์และเวอร์ชันผลิตภัณฑ์ และตั้งชื่อตาม <product-flavor><Build-Type> ตัวอย่างเช่น หากคุณสร้างเวอร์ชันผลิตภัณฑ์ "เดโม" และ "เต็มรูปแบบ" และเก็บประเภทบิลด์ "แก้ไขข้อบกพร่อง" และ "เผยแพร่" ไว้เป็นค่าเริ่มต้น Gradle จะสร้างตัวแปรบิลด์ต่อไปนี้

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

หากต้องการเลือกตัวแปรบิลด์ที่จะสร้างและเรียกใช้ ให้ไปที่สร้าง > เลือกตัวแปรบิลด์ แล้วเลือกตัวแปรบิลด์จากเมนู หากต้องการเริ่มปรับแต่งตัวแปรบิลด์แต่ละรายการด้วยฟีเจอร์และทรัพยากรของตัวเอง คุณจะต้องสร้างและจัดการชุดซอร์สตามที่อธิบายไว้ในหน้านี้

เปลี่ยนรหัสแอปพลิเคชันสำหรับตัวแปรบิลด์

เมื่อคุณสร้าง APK หรือ AAB สำหรับแอป เครื่องมือสร้างจะติดแท็กแอปด้วยรหัสแอปพลิเคชันที่กำหนดไว้ในบล็อก defaultConfig จากไฟล์ build.gradle.kts ดังที่แสดงในตัวอย่างต่อไปนี้ อย่างไรก็ตาม หากต้องการสร้างแอปเวอร์ชันต่างๆ ให้ปรากฏเป็นข้อมูลที่แยกกันใน Google Play Store เช่น เวอร์ชัน "ฟรี" และ "โปร" คุณต้องสร้างตัวแปรบิลด์แยกกันซึ่งแต่ละรายการมีรหัสแอปพลิเคชันต่างกัน

ในกรณีนี้ ให้กำหนดตัวแปรบิลด์แต่ละรายการเป็นเวอร์ชันผลิตภัณฑ์แยกต่างหาก สำหรับแต่ละ Flavor ภายในบล็อก productFlavors คุณสามารถกำหนดพร็อพเพอร์ตี้ applicationId ใหม่ หรือจะต่อท้ายกลุ่มด้วยรหัสแอปพลิเคชันเริ่มต้นโดยใช้ applicationIdSuffix ก็ได้ ดังที่แสดงที่นี่

Kotlin

android {
    defaultConfig {
        applicationId = "com.example.myapp"
    }
    productFlavors {
        create("free") {
            applicationIdSuffix = ".free"
        }
        create("pro") {
            applicationIdSuffix = ".pro"
        }
    }
}

ดึงดูด

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    productFlavors {
        free {
            applicationIdSuffix ".free"
        }
        pro {
            applicationIdSuffix ".pro"
        }
    }
}

ด้วยวิธีนี้ รหัสแอปพลิเคชันสำหรับเวอร์ชันผลิตภัณฑ์ "ฟรี" จะเป็น "com.example.myapp.free"

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

Kotlin

android {
    ...
    buildTypes {
        getByName("debug") {
            applicationIdSuffix = ".debug"
        }
    }
}

ดึงดูด

android {
    ...
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }
    }
}

เนื่องจาก Gradle ใช้การกำหนดค่าประเภทบิลด์หลังจากเวอร์ชันผลิตภัณฑ์ รหัสแอปพลิเคชันสำหรับตัวแปรบิลด์ "free debug" จึงเป็น "com.example.myapp.free.debug" ซึ่งจะมีประโยชน์เมื่อคุณต้องการมีทั้งบิลด์แก้ไขข้อบกพร่องและบิลด์ที่เผยแพร่ในอุปกรณ์เดียวกัน เนื่องจากแอป 2 แอปจะมีรหัสแอปพลิเคชันเดียวกันไม่ได้

หากคุณมีแอปเดิม (สร้างขึ้นก่อนเดือนสิงหาคม 2021) ที่เผยแพร่โดยใช้ APK ใน Google Play และต้องการใช้ข้อมูลแอปเดียวกันเพื่อเผยแพร่ APK หลายรายการที่แต่ละรายการกำหนดเป้าหมายการกำหนดค่าอุปกรณ์ที่แตกต่างกัน เช่น ระดับ API คุณต้องใช้รหัสแอปพลิเคชันเดียวกันสำหรับตัวแปรบิลด์แต่ละรายการ แต่ให้ APK แต่ละรายการมี versionCode ที่แตกต่างกัน อ่านข้อมูลเพิ่มเติมได้ที่การรองรับ APK หลายรายการ การเผยแพร่โดยใช้ AAB จะไม่ได้รับผลกระทบ เนื่องจากใช้ Artifact รายการเดียวที่ใช้รหัสเวอร์ชันและรหัสแอปพลิเคชันรายการเดียวโดยค่าเริ่มต้น

เคล็ดลับ: หากต้องการอ้างอิงรหัสแอปพลิเคชันในไฟล์ Manifest คุณสามารถใช้ตัวยึดตำแหน่ง ${applicationId} ในแอตทริบิวต์ Manifest ใดก็ได้ ในระหว่างการบิลด์ Gradle จะแทนที่แท็กนี้ด้วยรหัสแอปพลิเคชันจริง ดูข้อมูลเพิ่มเติมได้ที่แทรกตัวแปรบิลด์ลงในไฟล์ Manifest

รวมเวอร์ชันผลิตภัณฑ์หลายรายการเข้ากับมิติข้อมูลของเวอร์ชัน

ในบางกรณี คุณอาจต้องการรวมการกำหนดค่าจากเวอร์ชันผลิตภัณฑ์หลายรายการ ตัวอย่างเช่น คุณอาจต้องการสร้างการกำหนดค่าที่แตกต่างกันสำหรับเวอร์ชันผลิตภัณฑ์ "เต็ม" และ "เดโม" ที่อิงตามระดับ API ในการดำเนินการนี้ ปลั๊กอิน Android Gradle จะช่วยให้คุณสร้างเวอร์ชันผลิตภัณฑ์หลายกลุ่มเป็นมิติข้อมูลของเวอร์ชันได้

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

ตัวอย่างโค้ดต่อไปนี้ใช้พร็อพเพอร์ตี้ flavorDimensions เพื่อสร้างมิติข้อมูลของเวอร์ชัน "mode" เพื่อจัดกลุ่มเวอร์ชันผลิตภัณฑ์ "full" และ "demo" และมิติข้อมูลของเวอร์ชัน "api" เพื่อจัดกลุ่มการกำหนดค่าเวอร์ชันผลิตภัณฑ์ตามระดับ API

Kotlin

android {
  ...
  buildTypes {
    getByName("debug") {...}
    getByName("release") {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions += listOf("api", "mode")

  productFlavors {
    create("demo") {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension = "mode"
      ...
    }

    create("full") {
      dimension = "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    create("minApi24") {
      dimension = "api"
      minSdk = 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.
      versionCode = 30000 + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi24"
      ...
    }

    create("minApi23") {
      dimension = "api"
      minSdk = 23
      versionCode = 20000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi23"
      ...
    }

    create("minApi21") {
      dimension = "api"
      minSdk = 21
      versionCode = 10000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi21"
      ...
    }
  }
}
...

ดึงดูด

android {
  ...
  buildTypes {
    debug {...}
    release {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions "api", "mode"

  productFlavors {
    demo {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    minApi24 {
      dimension "api"
      minSdkVersion 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.

      versionCode 30000 + android.defaultConfig.versionCode
      versionNameSuffix "-minApi24"
      ...
    }

    minApi23 {
      dimension "api"
      minSdkVersion 23
      versionCode 20000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi23"
      ...
    }

    minApi21 {
      dimension "api"
      minSdkVersion 21
      versionCode 10000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi21"
      ...
    }
  }
}
...

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

เมื่อใช้การกำหนดค่าบิลด์ก่อนหน้าเป็นตัวอย่าง Gradle จะสร้างตัวแปรบิลด์ทั้งหมด 12 รายการโดยใช้รูปแบบการตั้งชื่อต่อไปนี้

  • ตัวแปรบิลด์: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
  • APK ที่เกี่ยวข้อง: app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
  • ตัวอย่างเช่น
    ตัวแปรบิลด์: minApi24DemoDebug
    APK ที่เกี่ยวข้อง: app-minApi24-demo-debug.apk

นอกจากไดเรกทอรีชุดซอร์สที่คุณสร้างสำหรับเวอร์ชันผลิตภัณฑ์และตัวแปรบิลด์แต่ละรายการได้แล้ว คุณยังสร้างไดเรกทอรีชุดซอร์สสำหรับเวอร์ชันผลิตภัณฑ์แต่ละชุดค่าผสมได้ด้วย เช่น คุณสามารถสร้างและเพิ่มแหล่งที่มา Java ลงในไดเรกทอรี src/demoMinApi24/java/ และ Gradle จะใช้แหล่งที่มาเหล่านั้นเฉพาะเมื่อสร้างตัวแปรที่รวมเวอร์ชันผลิตภัณฑ์ทั้ง 2 เวอร์ชันเข้าด้วยกัน

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

กรองตัวแปร

Gradle จะสร้างตัวแปรบิลด์สำหรับชุดค่าผสมที่เป็นไปได้ทั้งหมดของเวอร์ชันผลิตภัณฑ์และประเภทบิลด์ที่คุณกำหนดค่า อย่างไรก็ตาม อาจมีตัวแปรบิลด์บางรายการที่คุณไม่ต้องการหรือไม่มีความหมายในบริบทของโปรเจ็กต์ หากต้องการนำการกำหนดค่าตัวแปรบิลด์บางอย่างออก ให้สร้างตัวกรองตัวแปรในไฟล์ build.gradle.kts ระดับโมดูล

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

Kotlin

android {
  ...
  buildTypes {...}

  flavorDimensions += listOf("api", "mode")
  productFlavors {
    create("demo") {...}
    create("full") {...}
    create("minApi24") {...}
    create("minApi23") {...}
    create("minApi21") {...}
  }
}

androidComponents {
    beforeVariants { variantBuilder ->
        // To check for a certain build type, use variantBuilder.buildType == "<buildType>"
        if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) {
            // Gradle ignores any variants that satisfy the conditions above.
            variantBuilder.enable = false
        }
    }
}
...

ดึงดูด

android {
  ...
  buildTypes {...}

  flavorDimensions "api", "mode"
  productFlavors {
    demo {...}
    full {...}
    minApi24 {...}
    minApi23 {...}
    minApi21 {...}
  }

  variantFilter { variant ->
      def names = variant.flavors*.name
      // To check for a certain build type, use variant.buildType.name == "<buildType>"
      if (names.contains("minApi21") && names.contains("demo")) {
          // Gradle ignores any variants that satisfy the conditions above.
          setIgnore(true)
      }
  }
}
...

เมื่อเพิ่มตัวกรองตัวแปรลงในการกำหนดค่าบิลด์แล้วคลิกซิงค์เลยในแถบการแจ้งเตือน Gradle จะละเว้นตัวแปรบิลด์ที่ตรงตามเงื่อนไขที่คุณระบุ ตัวแปรบิลด์จะไม่ปรากฏในเมนูอีกต่อไปเมื่อคุณคลิกสร้าง > เลือกตัวแปรบิลด์จากแถบเมนูหรือตัวแปรบิลด์ ในแถบหน้าต่างเครื่องมือ

สร้างชุดซอร์ส

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

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

Gradle คาดหวังให้ไฟล์และไดเรกทอรีชุดซอร์สได้รับการจัดระเบียบในลักษณะที่เฉพาะเจาะจง คล้ายกับชุดซอร์ส main/ ตัวอย่างเช่น Gradle คาดหวังว่าไฟล์คลาส Kotlin หรือ Java ที่เจาะจงสำหรับประเภทบิลด์ "debug" จะอยู่ในไดเรกทอรี src/debug/kotlin/ หรือ src/debug/java/

ปลั๊กอิน Android Gradle มี Gradle Task ที่เป็นประโยชน์ซึ่งจะแสดงวิธีจัดระเบียบไฟล์สำหรับประเภทบิลด์ เวอร์ชันผลิตภัณฑ์ และตัวแปรบิลด์แต่ละรายการ ตัวอย่างเช่น ตัวอย่างต่อไปนี้จากเอาต์พุตของงานจะอธิบายตำแหน่งที่ Gradle คาดว่าจะพบไฟล์บางไฟล์สำหรับประเภทบิลด์ "debug"

------------------------------------------------------------
Project :app
------------------------------------------------------------

...

debug
----
Compile configuration: debugCompile
build.gradle name: android.sourceSets.debug
Java sources: [app/src/debug/java]
Kotlin sources: [app/src/debug/kotlin, app/src/debug/java]
Manifest file: app/src/debug/AndroidManifest.xml
Android resources: [app/src/debug/res]
Assets: [app/src/debug/assets]
AIDL sources: [app/src/debug/aidl]
RenderScript sources: [app/src/debug/rs]
JNI sources: [app/src/debug/jni]
JNI libraries: [app/src/debug/jniLibs]
Java-style resources: [app/src/debug/resources]

หากต้องการดูเอาต์พุตนี้ ให้ทำดังนี้

  1. คลิก Gradle ในแถบหน้าต่างเครื่องมือ
  2. ไปที่ MyApplication > Tasks > android แล้วดับเบิลคลิก sourceSets

    หากต้องการดูโฟลเดอร์ Tasks คุณต้องอนุญาตให้ Gradle สร้างรายการงานระหว่างการซิงค์ โดยทำตามขั้นตอนต่อไปนี้

    1. คลิกไฟล์ > การตั้งค่า > เวอร์ชันทดลอง (Android Studio > การตั้งค่า > เวอร์ชันทดลองใน macOS)
    2. ยกเลิกการเลือกไม่สร้างรายการงาน Gradle ระหว่างการซิงค์ Gradle
  3. หลังจาก Gradle ดำเนินงานแล้ว หน้าต่างเรียกใช้จะเปิดขึ้นเพื่อแสดงเอาต์พุต

หมายเหตุ: เอาต์พุตของงานยังแสดงวิธีจัดระเบียบชุดซอร์สสำหรับไฟล์ที่คุณต้องการใช้เพื่อทำการทดสอบแอป เช่น ชุดซอร์สสำหรับการทดสอบ test/ และ androidTest/ ด้วย

เมื่อคุณสร้างตัวแปรบิลด์ใหม่ Android Studio จะไม่สร้างไดเรกทอรีชุดซอร์สให้คุณ แต่จะมีตัวเลือกบางอย่างเพื่อช่วยคุณ เช่น หากต้องการสร้างเฉพาะไดเรกทอรี java/ สำหรับประเภทบิลด์ "debug" ให้ทำดังนี้

  1. เปิดแผงโปรเจ็กต์ แล้วเลือกมุมมองโปรเจ็กต์จากเมนูด้านบนของแผง
  2. ไปยัง MyProject/app/src/
  3. คลิกขวาที่ไดเรกทอรี src แล้วเลือกใหม่ > ไดเรกทอรี
  4. จากเมนูในส่วนชุดซอร์ส Gradle ให้เลือก full/java
  5. กด Enter

Android Studio จะสร้างไดเรกทอรีชุดซอร์สสำหรับประเภทบิลด์การแก้ไขข้อบกพร่อง แล้วสร้างไดเรกทอรี java/ ไว้ภายใน หรือ Android Studio จะสร้างไดเรกทอรีให้คุณเมื่อคุณเพิ่มไฟล์ใหม่ลงในโปรเจ็กต์สำหรับตัวแปรบิลด์ที่เฉพาะเจาะจง

เช่น หากต้องการสร้างไฟล์ XML ของค่าสำหรับประเภทบิลด์ "แก้ไขข้อบกพร่อง" ให้ทำดังนี้

  1. ในแผงโปรเจ็กต์ ให้คลิกขวาที่ไดเรกทอรี src แล้วเลือกใหม่ > XML > ไฟล์ XML ของค่า
  2. ป้อนชื่อไฟล์ XML หรือใช้ชื่อเริ่มต้น
  3. จากเมนูข้างชุดซอร์สเป้าหมาย ให้เลือกแก้ไขข้อบกพร่อง
  4. คลิกเสร็จสิ้น

เนื่องจากมีการระบุประเภทบิลด์ "debug" เป็นชุดซอร์สเป้าหมาย Android Studio จึงสร้างไดเรกทอรีที่จำเป็นโดยอัตโนมัติเมื่อสร้างไฟล์ XML โครงสร้างไดเรกทอรีที่ได้จะมีลักษณะดังรูปที่ 1

รูปที่ 1 ไดเรกทอรีชุดซอร์สใหม่สำหรับประเภทบิลด์ "debug"

ชุดซอร์สที่ใช้งานอยู่จะมีสัญญาณบอกสถานะสีเขียวในไอคอนเพื่อแสดงว่ามีการใช้งานอยู่ ชุดซอร์ส debug จะต่อท้ายด้วย [main] เพื่อแสดงว่าจะผสานรวมเข้ากับชุดซอร์ส main

คุณยังใช้ขั้นตอนเดียวกันนี้เพื่อสร้างไดเรกทอรีชุดซอร์สสำหรับเวอร์ชันผลิตภัณฑ์ เช่น src/demo/ และตัวแปรบิลด์ เช่น src/demoDebug/ ได้ด้วย นอกจากนี้ คุณยังสร้างชุดซอร์สการทดสอบที่กำหนดเป้าหมายตัวแปรบิลด์ที่เฉพาะเจาะจงได้ เช่น src/androidTestDemoDebug/ ดูข้อมูลเพิ่มเติมได้ที่การทดสอบชุดซอร์ส

เปลี่ยนการกำหนดค่าชุดซอร์สเริ่มต้น

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

บล็อก sourceSets ต้องอยู่ในบล็อก android คุณไม่จำเป็นต้องย้ายตำแหน่งไฟล์ต้นฉบับ เพียงแค่ระบุเส้นทางให้ Gradle โดยสัมพันธ์กับไฟล์ build.gradle.kts ระดับโมดูล ซึ่ง Gradle จะค้นหาไฟล์สำหรับคอมโพเนนต์ชุดซอร์สแต่ละรายการได้ หากต้องการดูคอมโพเนนต์ที่คุณกำหนดค่าได้และดูว่าคุณสามารถแมปคอมโพเนนต์เหล่านั้นกับไฟล์หรือไดเรกทอรีหลายรายการได้หรือไม่ โปรดดูเอกสารอ้างอิง API ของปลั๊กอิน Android Gradle

ตัวอย่างโค้ดต่อไปนี้จะแมปแหล่งที่มาจากไดเรกทอรี app/other/ กับคอมโพเนนต์บางอย่างของชุดซอร์ส main และเปลี่ยนไดเรกทอรีรากของชุดซอร์ส androidTest

Kotlin

android {
  ...
  // Encapsulates configurations for the main source set.
  sourceSets.getByName("main") {
    // Changes the directory for Java sources. The default directory is
    // 'src/main/java'.
    java.setSrcDirs(listOf("other/java"))

    // If you list multiple directories, Gradle uses all of them to collect
    // sources. Because Gradle gives these directories equal priority, if
    // you define the same resource in more than one directory, you receive an
    // error when merging resources. The default directory is 'src/main/res'.
    res.setSrcDirs(listOf("other/res1", "other/res2"))

    // Note: Avoid specifying a directory that is a parent to one
    // or more other directories you specify. For example, avoid the following:
    // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
    // Specify either only the root 'other/res1' directory or only the
    // nested 'other/res1/layouts' and 'other/res1/strings' directories.

    // For each source set, you can specify only one Android manifest.
    // By default, Android Studio creates a manifest for your main source
    // set in the src/main/ directory.
    manifest.srcFile("other/AndroidManifest.xml")
    ...
  }

  // Create additional blocks to configure other source sets.
  sourceSets.getByName("androidTest") {
      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot("src/tests")
      ...
  }
}
...

ดึงดูด

android {
  ...
  sourceSets {
    // Encapsulates configurations for the main source set.
    main {
      // Changes the directory for Java sources. The default directory is
      // 'src/main/java'.
      java.srcDirs = ['other/java']

      // If you list multiple directories, Gradle uses all of them to collect
      // sources. Because Gradle gives these directories equal priority, if
      // you define the same resource in more than one directory, you receive an
      // error when merging resources. The default directory is 'src/main/res'.
      res.srcDirs = ['other/res1', 'other/res2']

      // Note: Avoid specifying a directory that is a parent to one
      // or more other directories you specify. For example, avoid the following:
      // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
      // Specify either only the root 'other/res1' directory or only the
      // nested 'other/res1/layouts' and 'other/res1/strings' directories.

      // For each source set, you can specify only one Android manifest.
      // By default, Android Studio creates a manifest for your main source
      // set in the src/main/ directory.
      manifest.srcFile 'other/AndroidManifest.xml'
      ...
    }

    // Create additional blocks to configure other source sets.
    androidTest {

      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot 'src/tests'
      ...
    }
  }
}
...

โปรดทราบว่าไดเรกทอรีต้นทางจะอยู่ในชุดซอร์สได้เพียงชุดเดียวเท่านั้น ตัวอย่างเช่น คุณไม่สามารถแชร์แหล่งที่มาของการทดสอบเดียวกันกับทั้งชุดซอร์ส test และ androidTest เนื่องจาก Android Studio สร้างโมดูล IntelliJ แยกต่างหากสำหรับชุดซอร์สแต่ละชุด และไม่รองรับรูทเนื้อหาที่ซ้ำกันในชุดซอร์ส

สร้างด้วยชุดซอร์ส

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

  1. src/demoDebug/ (ชุดซอร์สของตัวแปรบิลด์)
  2. src/debug/ (ชุดซอร์สประเภทบิลด์)
  3. src/demo/ (ชุดซอร์สของเวอร์ชันผลิตภัณฑ์)
  4. src/main/ (ชุดซอร์สหลัก)

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

หากคุณรวมเวอร์ชันผลิตภัณฑ์หลายเวอร์ชัน ลำดับความสำคัญระหว่างเวอร์ชันผลิตภัณฑ์จะกำหนดโดยมิติข้อมูลของเวอร์ชันที่เวอร์ชันผลิตภัณฑ์นั้นๆ เป็นส่วนหนึ่ง เมื่อแสดงมิติข้อมูลของเวอร์ชันด้วยพร็อพเพอร์ตี้ android.flavorDimensions ระบบจะจัดลำดับความสำคัญของเวอร์ชันผลิตภัณฑ์ตามลำดับที่มีการประกาศมิติข้อมูล โดยมิติข้อมูลที่ประกาศก่อนจะมีความสำคัญเหนือกว่ามิติข้อมูลที่ประกาศทีหลัง นอกจากนี้ ชุดซอร์สที่คุณสร้างขึ้นสำหรับการรวมเวอร์ชันผลิตภัณฑ์จะมีลำดับความสำคัญสูงกว่าชุดซอร์สที่เป็นของเวอร์ชันผลิตภัณฑ์แต่ละรายการ

ลำดับความสำคัญจะกำหนดว่าชุดซอร์สใดมีลำดับความสำคัญสูงกว่าเมื่อ Gradle รวมโค้ดและทรัพยากร เนื่องจากไดเรกทอรีชุดซอร์ส demoDebug/ มีแนวโน้มที่จะมีไฟล์ที่เจาะจงสำหรับตัวแปรบิลด์นั้น หาก demoDebug/ มีไฟล์ที่กำหนดไว้ใน debug/ ด้วย Gradle จะใช้ไฟล์ในชุดซอร์ส demoDebug/ ในทำนองเดียวกัน Gradle จะให้ไฟล์ในชุดซอร์สของประเภทบิลด์และเวอร์ชันผลิตภัณฑ์มีลำดับความสำคัญสูงกว่าไฟล์เดียวกันใน main/ Gradle จะพิจารณาลำดับความสำคัญนี้เมื่อใช้กฎการสร้างต่อไปนี้

  • ซอร์สโค้ดทั้งหมดในไดเรกทอรี kotlin/ หรือ java/ จะคอมไพล์ร่วมกันเพื่อสร้างเอาต์พุตเดียว

    หมายเหตุ: สำหรับตัวแปรบิลด์หนึ่งๆ Gradle จะแสดงข้อผิดพลาดของบิลด์หากพบไดเรกทอรีชุดซอร์สอย่างน้อย 2 รายการที่กำหนดคลาส Kotlin หรือ Java เดียวกัน ตัวอย่างเช่น เมื่อสร้างแอปแก้ไขข้อบกพร่อง คุณจะกำหนดทั้ง src/debug/Utility.kt และ src/main/Utility.kt ไม่ได้ เนื่องจาก Gradle จะดูทั้ง 2 ไดเรกทอรีนี้ในระหว่างกระบวนการสร้างและแสดงข้อผิดพลาด "คลาสซ้ำ" หากต้องการ Utility.kt เวอร์ชันต่างๆ สำหรับประเภทบิลด์ที่แตกต่างกัน ประเภทบิลด์แต่ละประเภทต้องกำหนดเวอร์ชันของไฟล์เองและไม่รวมไว้ในชุดซอร์ส main/

  • ระบบจะรวมไฟล์ Manifest เข้าด้วยกันเป็นไฟล์ Manifest เดียว ระบบจะให้ความสำคัญตามลำดับเดียวกับรายการในตัวอย่างก่อนหน้า เช่น การตั้งค่าไฟล์ Manifest สำหรับประเภทบิลด์จะลบล้างการตั้งค่าไฟล์ Manifest สำหรับเวอร์ชันผลิตภัณฑ์ ดูข้อมูลเพิ่มเติมได้ที่หัวข้อการรวมไฟล์ Manifest
  • ระบบจะผสานไฟล์ในไดเรกทอรี values/ เข้าด้วยกัน หากไฟล์ 2 ไฟล์มีชื่อเดียวกัน เช่น ไฟล์ strings.xml 2 ไฟล์ ระบบจะให้ความสำคัญตามลำดับเดียวกับรายการในตัวอย่างก่อนหน้า เช่น ค่าที่กำหนดไว้ในไฟล์ในชุดซอร์สประเภทบิลด์จะลบล้างค่าที่กำหนดไว้ในไฟล์เดียวกันในเวอร์ชันผลิตภัณฑ์
  • ทรัพยากรในไดเรกทอรี res/ และ asset/ จะรวมอยู่ในแพ็กเกจเดียวกัน หากมีทรัพยากรที่มีชื่อเดียวกันซึ่งกำหนดไว้ในชุดซอร์สอย่างน้อย 2 ชุด ระบบจะให้ความสำคัญตามลำดับเดียวกับรายการในตัวอย่างก่อนหน้า
  • Gradle จะให้ทรัพยากรและไฟล์ Manifest ที่รวมอยู่กับทรัพยากร Dependency ของโมดูลไลบรารีมีลำดับความสำคัญต่ำสุดเมื่อสร้างแอป

ประกาศทรัพยากร Dependency

หากต้องการกำหนดค่าทรัพยากร Dependency สำหรับตัวแปรบิลด์หรือชุดซอร์สการทดสอบที่เฉพาะเจาะจง ให้ใส่ชื่อตัวแปรบิลด์หรือชุดซอร์สการทดสอบไว้หน้าคีย์เวิร์ด Implementation ดังตัวอย่างต่อไปนี้

Kotlin

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    "freeImplementation"(project(":mylibrary"))

    // Adds a remote binary dependency only for local tests.
    testImplementation("junit:junit:4.12")

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation("com.android.support.test.espresso:espresso-core:3.6.1")
}

ดึงดูด

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    freeImplementation project(":mylibrary")

    // Adds a remote binary dependency only for local tests.
    testImplementation 'junit:junit:4.12'

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.6.1'
}

ดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดค่าทรัพยากร Dependency ได้ที่เพิ่มทรัพยากร Dependency ของบิลด์

ใช้การจัดการทรัพยากร Dependency ที่คำนึงถึงตัวแปร

ปลั๊กอิน Android Gradle 3.0.0 ขึ้นไปมีกลไกทรัพยากร Dependency ใหม่ที่จับคู่ตัวแปรโดยอัตโนมัติเมื่อใช้ไลบรารี เช่น ตัวแปร debug ของแอปจะใช้ตัวแปร debug ของไลบรารีโดยอัตโนมัติ นอกจากนี้ยังใช้ได้เมื่อใช้ Flavor โดยตัวแปร freeDebug ของแอปจะใช้ตัวแปร freeDebug ของไลบรารี

เพื่อให้ปลั๊กอินจับคู่ตัวแปรได้อย่างถูกต้อง คุณต้องระบุตัวเลือกสำรองสำหรับการจับคู่ตามที่อธิบายไว้ในส่วนต่อไปนี้ สำหรับกรณีที่ไม่สามารถจับคู่โดยตรงได้

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

Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
    project :app

แก้ไขข้อผิดพลาดของบิลด์ที่เกี่ยวข้องกับการจับคู่ตัวแปร

ปลั๊กอินประกอบด้วยองค์ประกอบ DSL เพื่อช่วยคุณควบคุมวิธีที่ Gradle แก้ไขสถานการณ์ที่การจับคู่ตัวแปรโดยตรงระหว่างแอปและการขึ้นต่อกันเป็นไปไม่ได้

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

  • แอปของคุณมีประเภทบิลด์ที่ทรัพยากร Dependency ของไลบรารีไม่มี

    ตัวอย่างเช่น แอปของคุณมีประเภทบิลด์ "Staging" แต่ทรัพยากร Dependency มีเฉพาะประเภทบิลด์ "Debug" และ "Release" เท่านั้น

    โปรดทราบว่าไม่มีปัญหาเมื่อทรัพยากร Dependency ของไลบรารีมีประเภทบิลด์ที่แอปของคุณไม่มี เนื่องจากปลั๊กอินไม่เคยขอประเภทบิลด์นั้นจากทรัพยากร Dependency

    ใช้ matchingFallbacks เพื่อระบุการจับคู่ทางเลือกสำหรับประเภทบิลด์ที่กำหนด ดังที่แสดงที่นี่

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        buildTypes {
            getByName("debug") {}
            getByName("release") {}
            create("staging") {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks += listOf("debug", "qa", "release")
            }
        }
    }

    ดึงดูด

    // In the app's build.gradle file.
    android {
        buildTypes {
            debug {}
            release {}
            staging {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks = ['debug', 'qa', 'release']
            }
        }
    }
  • สำหรับมิติข้อมูลของเวอร์ชันหนึ่งๆ ที่มีอยู่ทั้งในแอปและทรัพยากร Dependency ของไลบรารี แอปของคุณมีเวอร์ชันที่ไลบรารีไม่มี

    ตัวอย่างเช่น ทั้งแอปและทรัพยากร Dependency ของไลบรารีมีมิติข้อมูลของเวอร์ชัน "ระดับ" อย่างไรก็ตาม มิติข้อมูล "tier" ในแอปมีเวอร์ชัน "free" และ "paid" แต่ทรัพยากร Dependency มีเฉพาะเวอร์ชัน "demo" และ "paid" สำหรับมิติข้อมูลเดียวกัน

    โปรดทราบว่าสำหรับมิติข้อมูลของเวอร์ชันหนึ่งๆ ที่มีทั้งในแอปและทรัพยากร Dependency ของไลบรารี จะไม่มีปัญหาเมื่อไลบรารีมีเวอร์ชันผลิตภัณฑ์ที่แอปไม่มี เนื่องจากปลั๊กอินไม่เคยขอเวอร์ชันนั้นจากทรัพยากร Dependency

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

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions += "tier"
        productFlavors {
            create("paid") {
                dimension = "tier"
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            create("free") {
                dimension = "tier"
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks += listOf("demo", "trial")
            }
        }
    }

    ดึงดูด

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions 'tier'
        productFlavors {
            paid {
                dimension 'tier'
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            free {
                dimension 'tier'
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks = ['demo', 'trial']
            }
        }
    }
  • ทรัพยากร Dependency ของไลบรารีมีมิติข้อมูลของเวอร์ชันที่แอปของคุณไม่มี

    ตัวอย่างเช่น ทรัพยากร Dependency ของไลบรารีมี Flavor สำหรับมิติข้อมูล "minApi" แต่แอปของคุณมี Flavor สำหรับมิติข้อมูล "tier" เท่านั้น เมื่อคุณต้องการสร้างแอปเวอร์ชัน "freeDebug" ปลั๊กอินจะไม่ทราบว่าควรใช้ทรัพยากร Dependency เวอร์ชัน "minApi23Debug" หรือ "minApi18Debug"

    โปรดทราบว่าไม่มีปัญหาเมื่อแอปของคุณมีมิติข้อมูลของเวอร์ชันที่ทรัพยากร Dependency ของไลบรารีไม่มี เนื่องจากปลั๊กอินจะจับคู่ Flavor ของมิติข้อมูลที่มีอยู่ในทรัพยากร Dependency เท่านั้น เช่น หากทรัพยากร Dependency ไม่มีมิติข้อมูลสำหรับ ABI แอปเวอร์ชัน "freeX86Debug" จะใช้ทรัพยากร Dependency เวอร์ชัน "freeDebug"

    ใช้ missingDimensionStrategy ในบล็อก defaultConfig เพื่อระบุ Flavor เริ่มต้นสำหรับปลั๊กอินที่จะเลือกจากมิติข้อมูลที่ขาดหายไปแต่ละรายการ ดังที่แสดงในตัวอย่างต่อไปนี้ นอกจากนี้ คุณยังลบล้างการเลือกในบล็อก productFlavors ได้ด้วย เพื่อให้แต่ละเวอร์ชันระบุกลยุทธ์การจับคู่ที่แตกต่างกันสำหรับมิติข้อมูลที่ขาดหายไปได้

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy("minApi", "minApi18", "minApi23")
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy("abi", "x86", "arm64")
        }
        flavorDimensions += "tier"
        productFlavors {
            create("free") {
                dimension = "tier"
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the "minApi" dimension.
                missingDimensionStrategy("minApi", "minApi23", "minApi18")
            }
            create("paid") {}
        }
    }

    ดึงดูด

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy 'minApi', 'minApi18', 'minApi23'
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy 'abi', 'x86', 'arm64'
        }
        flavorDimensions 'tier'
        productFlavors {
            free {
                dimension 'tier'
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the 'minApi' dimension.
                missingDimensionStrategy 'minApi', 'minApi23', 'minApi18'
            }
            paid {}
        }
    }

ดูข้อมูลเพิ่มเติมได้ที่ matchingFallbacks และ missingDimensionStrategy ในข้อมูลอ้างอิง DSL ของปลั๊กอิน Android Gradle

กำหนดการตั้งค่าการรับรอง

Gradle จะไม่รับรอง APK หรือ AAB ของบิลด์ที่เผยแพร่ เว้นแต่คุณจะกำหนดการกำหนดค่าการลงชื่อสำหรับบิลด์นี้ไว้อย่างชัดเจน หากยังไม่มีคีย์ Signing ให้สร้างคีย์การอัปโหลดและ Keystore โดยใช้ Android Studio

วิธีกำหนดค่าการลงชื่อด้วยตนเองสำหรับประเภทบิลด์ที่เผยแพร่โดยใช้การกำหนดค่าบิลด์ Gradle

  1. สร้าง Keystore คีย์สโตร์คือไฟล์ไบนารีที่มีชุดคีย์ส่วนตัว คุณต้องเก็บคีย์สโตร์ไว้ในที่ที่ปลอดภัย
  2. สร้างคีย์ส่วนตัว คีย์ส่วนตัวใช้เพื่อรับรองแอปสำหรับการเผยแพร่ และจะไม่รวมอยู่ในแอปหรือเปิดเผยต่อบุคคลที่สามที่ไม่ได้รับอนุญาต
  3. เพิ่มการกำหนดค่าการลงชื่อลงในไฟล์ build.gradle.kts ระดับโมดูล

    Kotlin

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            create("release") {
                storeFile = file("myreleasekey.keystore")
                storePassword = "password"
                keyAlias = "MyReleaseKey"
                keyPassword = "password"
            }
        }
        buildTypes {
            getByName("release") {
                ...
                signingConfig = signingConfigs.getByName("release")
            }
        }
    }

    ดึงดูด

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            release {
                storeFile file("myreleasekey.keystore")
                storePassword "password"
                keyAlias "MyReleaseKey"
                keyPassword "password"
            }
        }
        buildTypes {
            release {
                ...
                signingConfig signingConfigs.release
            }
        }
    }

หมายเหตุ: การใส่รหัสผ่านสำหรับคีย์การเผยแพร่และ Keystore ไว้ในไฟล์บิลด์ไม่ใช่แนวทางปฏิบัติด้านความปลอดภัยที่ดี แต่ให้กำหนดค่าไฟล์บิลด์เพื่อรับรหัสผ่านเหล่านี้จากตัวแปรสภาพแวดล้อม หรือให้กระบวนการบิลด์แจ้งให้คุณป้อนรหัสผ่านเหล่านี้แทน

วิธีรับรหัสผ่านเหล่านี้จากตัวแปรสภาพแวดล้อม

Kotlin

storePassword = System.getenv("KSTOREPWD")
keyPassword = System.getenv("KEYPWD")

ดึงดูด

storePassword System.getenv("KSTOREPWD")
keyPassword System.getenv("KEYPWD")

หรือจะโหลด Keystore จากไฟล์พร็อพเพอร์ตี้ในเครื่องก็ได้ เพื่อความปลอดภัย อย่าเพิ่มไฟล์นี้ลงในการควบคุมแหล่งที่มา แต่ให้ตั้งค่าในเครื่องสำหรับนักพัฒนาแอปแต่ละรายแทน ดูข้อมูลเพิ่มเติมได้ที่ นำข้อมูลการรับรองออกจากไฟล์บิลด์

หลังจากเสร็จสิ้นขั้นตอนนี้แล้ว คุณจะจัดจำหน่ายและเผยแพร่แอปใน Google Play ได้

คำเตือน: เก็บ Keystore และคีย์ส่วนตัวไว้ในที่ปลอดภัย และตรวจสอบว่าคุณได้สำรองข้อมูลไว้อย่างปลอดภัย หากใช้ Play App Signing และทำคีย์การอัปโหลดหาย คุณสามารถขอรีเซ็ตโดยใช้ Play Console หากคุณเผยแพร่แอปโดยไม่มี Play App Signing (สำหรับแอปที่สร้างขึ้นก่อนเดือนสิงหาคม 2021) และคีย์ App Signing สูญหาย คุณจะเผยแพร่การอัปเดตแอปไม่ได้ เนื่องจากคุณต้องรับรองแอปทุกเวอร์ชันด้วยคีย์เดียวกันทุกครั้ง

การรับรองแอป Wear OS

เมื่อเผยแพร่แอป Wear OS ทั้ง APK ของนาฬิกาและ APK ของโทรศัพท์ (ไม่บังคับ) ต้องรับรองด้วยคีย์เดียวกัน ดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดแพ็กเกจและการรับรองแอป Wear OS ได้ที่จัดแพ็กเกจและเผยแพร่แอป Wear