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

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

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

ตัวอย่างเช่น สมมติว่าแอปพลิเคชันของคุณใช้ไลบรารี 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 จะแก้ไขเป็นเวอร์ชันที่เปลี่ยนผ่าน และแอปพลิเคชันจะเห็นเวอร์ชันที่ใหม่กว่านั้น

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

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

เช่น คุณสามารถใช้งาน 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 (*)

ส่วนนี้ของรายงานแสดงรายการพึ่งพาบางส่วนที่แก้ไขแล้วสำหรับการกําหนดค่า 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 เป็นข้อกำหนดในไฟล์ 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 เพื่อแสดงถึงคลัง เวอร์ชันนี้ไม่ถือเป็นเวอร์ชันที่เป็นไปได้ เว้นแต่คุณจะใช้ตัวแปรดังกล่าวเพื่อระบุการอ้างอิง

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

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

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

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

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

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

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

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

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

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

ตัวอย่างเช่น แคตตาล็อกเวอร์ชันของคุณมี 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 และ D เป็น Dependency ไลบรารี ค ใช้ไลบรารี ข เป็น Dependency ไม่ได้ใช้ไลบรารี C โดยตรงหรือโดยอ้อมในแอปพลิเคชันนี้
รูปที่ 3 สถานการณ์ BOM

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

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