การแก้ไข Dependency ของ Gradle

ไฟล์บิลด์จะระบุการพึ่งพาโดยตรง แต่การพึ่งพาแต่ละรายการอาจต้องใช้การพึ่งพาอื่นๆ ทรัพยากร Dependency แบบสับเปลี่ยนเหล่านี้จะขยายกราฟทรัพยากร Dependency ทั้งหมดอย่างรวดเร็ว โดยมักมีเวอร์ชันที่ขัดแย้งกัน

เมื่อส่วน minor (ฟีเจอร์ใหม่) หรือ patch (การแก้ไขข้อบกพร่อง) มีการเปลี่ยนแปลง ไลบรารียังคงมีแนวโน้มที่จะเข้ากันได้และมีโอกาสที่จะส่งผลกระทบต่อแอปพลิเคชันน้อยลง

ตัวอย่างเช่น สมมติว่าแอปพลิเคชันของคุณใช้ไลบรารี A และไลบรารี B ซึ่งเวอร์ชันที่ใช้ไลบรารี C ไม่เหมือนกัน

แอปของคุณอาศัยไลบรารี A และไลบรารี B ซึ่งเวอร์ชันต่างๆ ของไลบรารี C Gradle เลือกไลบรารี C เวอร์ชันใหม่ล่าสุด
รูปที่ 1 ความขัดแย้งของเวอร์ชันแบบทรานซิทีฟ Gradle เปลี่ยนเป็นเวอร์ชันใหม่ล่าสุด (โดยค่าเริ่มต้น)

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

แอปอาจมีทรัพยากร Dependency โดยตรงที่เป็นการอ้างอิงแบบสับเปลี่ยนได้ด้วย

แอปของคุณขึ้นอยู่กับไลบรารี A และไลบรารี C ไลบรารี ก. ขึ้นอยู่กับไลบรารี ค. เวอร์ชันใหม่กว่า Gradle จะเลือกไลบรารี C เวอร์ชันล่าสุด
รูปที่ 2 เวอร์ชันแบบทรานซิทีฟที่ขัดแย้งกันอีกรายการ ในกรณีนี้ Gradle จะแก้ไขเป็นเวอร์ชันที่เปลี่ยนผ่าน และแอปพลิเคชันจะเห็นเวอร์ชันที่ใหม่กว่านั้น

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

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

เช่น คุณสามารถใช้งาน dependencies ของ Gradle โดยเรียกใช้ ./gradlew app:dependencies เพื่อแสดงลําดับชั้นของไลบรารีทั้งหมดที่โมดูลแอปของคุณใช้ การเรียกใช้กับแอปพลิเคชันที่ใช้ไลบรารี ดังแสดงในรูปที่ 2 เราจะเห็น

1: releaseRuntimeClasspath - Runtime classpath of /release.
2: +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0
3: |    +--- ... (omitted for brevity) ...
4: +--- com.sample:library.a:1.2.3
5: |    +--- com.sample:library.c:2.1.1
6: |    |    \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
7: |    \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 (*)
8: +--- com.sample:library.c:1.4.1 -> 2.1.1 (*)

รายงานส่วนนี้แสดงทรัพยากร Dependency ที่ได้รับการแก้ไขสำหรับการกำหนดค่า releaseRuntimeClasspath แล้ว

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

ดูรายละเอียดเพิ่มเติมเกี่ยวกับการใช้การรายงานทรัพยากร Dependency ของ Gradle ได้ที่ดูและแก้ไขข้อบกพร่องของทรัพยากร Dependency

คุณสามารถระบุเวอร์ชันที่ขอได้โดยตรงในแคตตาล็อกเวอร์ชันหรือในใบรายการวัสดุ (BOM)

การแก้ไขข้อกำหนดเวอร์ชันโดยตรง

เวอร์ชันทรัพยากร Dependency ที่ระบุจะเป็นทางเลือกสําหรับความละเอียดของเวอร์ชัน

ตัวอย่างเช่น หากต้องการขอไลบรารี androidx.compose.ui:ui เวอร์ชัน 1.7.3 เป็น Dependency ใน app/build.gradle.kts ให้ทำดังนี้

dependencies {
    implementation("androidx.compose.ui:ui:1.7.3")
}

เวอร์ชัน 1.7.3 จะกลายเป็นเวอร์ชันที่พร้อมใช้งาน Gradle จะแก้ไขเป็นเวอร์ชันล่าสุดระหว่าง 1.7.3 และไลบรารีเดียวกันเวอร์ชันอื่นๆ ที่ขอโดย Dependency แบบทรานซิทีฟ

การแก้ปัญหาแคตตาล็อกเวอร์ชัน

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

ตัวอย่างเช่น หากต้องการระบุ androidx.compose.ui:ui เวอร์ชัน 1.7.3 เป็นทรัพยากร Dependency ในไฟล์ gradle/libs.versions.toml ให้ทำดังนี้

[versions]
ui = "1.7.3"

[libraries]
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "ui" }

ตัวแปรนี้กำหนดตัวแปรชื่อ libs.androidx.compose.ui เพื่อแสดงถึงไลบรารี เวอร์ชันนี้ไม่ถือว่าเป็นเวอร์ชันที่แนะนำ เว้นแต่ว่าคุณจะใช้ตัวแปรดังกล่าวเพื่อระบุทรัพยากร Dependency

วิธีขอคลังและเวอร์ชันของคลังใน app/build.gradle.kts

dependencies {
    implementation(libs.androidx.compose.ui)
}

Gradle จะแก้ไขด้วยวิธีเดียวกับที่แก้ไขสำหรับข้อกำหนดโดยตรง

การแก้ไขรายการวัสดุ (BOM)

เวอร์ชันของไลบรารีทั้งหมดที่ปรากฏใน BOM จะกลายเป็นเวอร์ชันที่เป็นไปได้สำหรับการแก้ไขเวอร์ชัน โปรดทราบว่าไลบรารีจะใช้เป็นทรัพยากร Dependency ก็ต่อเมื่อระบุไว้ว่าเป็นแบบโดยตรงหรือโดยอ้อมเท่านั้น ระบบจะไม่สนใจไลบรารีอื่นๆ ใน BOM

เวอร์ชัน BOM จะส่งผลต่อทรัพยากร Dependency โดยตรง รวมถึงการขึ้นต่อกันแบบทรานซิทีฟทั้งหมดที่ปรากฏใน BOM

ตัวอย่างเช่น ระบุ BOM เป็นทรัพยากร Dependency ของแพลตฟอร์มใน app/build.gradle.kts ดังนี้

dependencies {
    implementation(platform("androidx.compose:compose-bom:2024.10.00"))
    implementation("androidx.compose.ui:ui")
}

ไลบรารีใดๆ ที่คุณต้องการใช้เป็นทรัพยากร Dependency ไม่จำเป็นต้องมีข้อกำหนดเวอร์ชัน เนื่องจากเวอร์ชันที่ขอมาจาก BOM

โปรดทราบว่าคุณยังใช้แคตตาล็อกเวอร์ชันเพื่อสร้างตัวแปรสำหรับ BOM และไลบรารีได้ด้วย ละเว้นหมายเลขเวอร์ชันในแคตตาล็อกเวอร์ชันสำหรับไลบรารีที่ปรากฏในทรัพยากร Dependency ของ BOM

ตัวอย่างเช่น แคตตาล็อกเวอร์ชันของคุณมี BOM และหมายเลขเวอร์ชัน แต่ไม่ได้ระบุเวอร์ชันสำหรับไลบรารีที่คุณอ้างอิงจาก BOM ดังนี้

[versions]
composeBom = "2024.10.00"

[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }

app/build.gradle.kts ของคุณอ้างอิง BOM และไลบรารีโดยใช้ตัวแปรที่กําหนดไว้ในแคตตาล็อกเวอร์ชัน ดังนี้

dependencies {
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.compose.ui)
}

เวอร์ชันของไลบรารีที่ระบุใน BOM จะกลายเป็นเวอร์ชันที่เหมาะสำหรับความละเอียดของ Gradle นอกจากนี้ เวอร์ชันไลบรารีอื่นๆ ทั้งหมดที่ระบุไว้ใน BOM จะกลายเป็นเวอร์ชันที่เป็นไปได้ ไม่ว่าคุณจะใช้เป็นทรัพยากร Dependency โดยตรงหรือไม่ก็ตาม

ตัวอย่างเช่น สมมติว่า BOM ระบุเวอร์ชันสำหรับไลบรารี A, B และ C แอปพลิเคชันของคุณต้องการใช้ไลบรารี ก. เป็น Dependency โดยตรง รวมถึงไลบรารี ง. ไลบรารี ค ใช้ไลบรารี ข เป็น Dependency ไม่มีรายการใดที่ใช้ไลบรารี C

BOM มีเวอร์ชันสำหรับไลบรารี A, B และ C แอปพลิเคชันของคุณใช้ไลบรารี A และ D เป็น Dependency ไลบรารี D ใช้ไลบรารี B เป็นทรัพยากร Dependency ไม่มีการใช้ไลบรารี C ในแอปพลิเคชันนี้โดยตรงหรือโดยอ้อม
รูปที่ 3 สถานการณ์ BOM

ไลบรารี A, B และ D คือทรัพยากร Dependency ในแอปพลิเคชัน ระบบจะไม่สนใจไลบรารี C Gradle จะใช้เวอร์ชัน A และ B ที่ระบุไว้ใน BOM เป็นเวอร์ชันที่เป็นไปได้ แม้ว่าคุณจะไม่ได้ระบุไลบรารี B เป็นการพึ่งพาโดยตรงก็ตาม

หากไลบรารี D ขอไลบรารี B เวอร์ชันที่ต่ำกว่า 2.0.1 Gradle เปลี่ยนเป็น 2.0.1 หากไลบรารี D ขอเวอร์ชันไลบรารี B ที่สูงกว่า Gradle จะเปลี่ยนเป็นเวอร์ชันนั้น