แก้ไขข้อผิดพลาดในการแปลงทรัพยากร Dependency

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

ดูคําแนะนําในการแก้ไขข้อผิดพลาดในการแก้ไขข้อกําหนดซึ่งเกี่ยวข้องกับตรรกะการสร้างที่กําหนดเองได้ที่กลยุทธ์การแก้ไขข้อกําหนดที่กำหนดเอง

แก้ไขข้อผิดพลาดในการแก้ไขข้อขัดข้อง

ข้อความแจ้งนี้ขอความช่วยเหลือในการแก้ไขข้อขัดแย้งของ Dependency

เรียกใช้พรอมต์นี้ใน Android Studio โดยเปิด build.gradle ไว้

I'm getting the following error in my build: Conflict with dependency. Resolved versions for runtime classpath and compile classpath differ. What changes do I need to make to my dependencies to resolve this error.

การใช้พรอมต์ AI

พรอมต์ AI มีไว้เพื่อใช้ใน Gemini ใน Android Studio (ต้องใช้ Canary เวอร์ชันล่าสุด)

ดูข้อมูลเพิ่มเติมเกี่ยวกับ Gemini ใน Studio ได้ที่ https://developer.android.com/studio/preview/gemini

ดูทรัพยากร Dependency ของโมดูล

ไลบรารีที่ขึ้นต่อกันโดยตรงบางรายการอาจมีการขึ้นต่อกันของตนเอง ความสัมพันธ์เหล่านี้เรียกว่าการพึ่งพาแบบทรานซิทีฟ Gradle จะรวบรวมและเพิ่มข้อกำหนดที่ไม่เกี่ยวข้องกันแต่ละรายการให้คุณโดยอัตโนมัติแทนที่จะให้คุณประกาศด้วยตนเอง ปลั๊กอิน Android สำหรับ Gradle มีงานที่แสดงรายการของข้อกําหนดซึ่ง Gradle แก้ปัญหาสําหรับโมดูลหนึ่งๆ

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

debugRuntimeClasspath - Dependencies for runtime/packaging
+--- :mylibrary (variant: debug)
+--- com.google.android.material:material:1.0.0@aar
+--- androidx.appcompat:appcompat:1.0.2@aar
+--- androidx.constraintlayout:constraintlayout:1.1.3@aar
+--- androidx.fragment:fragment:1.0.0@aar
+--- androidx.vectordrawable:vectordrawable-animated:1.0.0@aar
+--- androidx.recyclerview:recyclerview:1.0.0@aar
+--- androidx.legacy:legacy-support-core-ui:1.0.0@aar
...

debugAndroidTest
debugAndroidTestCompileClasspath - Dependencies for compilation
+--- androidx.test.ext:junit:1.1.0@aar
+--- androidx.test.espresso:espresso-core:3.1.1@aar
+--- androidx.test:runner:1.1.1@aar
+--- junit:junit:4.12@jar
...

หากต้องการเรียกใช้งาน ให้ทําตามขั้นตอนต่อไปนี้

  1. เลือกดู > หน้าต่างเครื่องมือ > Gradle (หรือคลิก Gradle ในแถบหน้าต่างเครื่องมือ)
  2. ขยาย AppName > Tasks > android และดับเบิลคลิก androidDependencies หลังจาก Gradle ดำเนินการแล้ว หน้าต่างเรียกใช้จะเปิดขึ้นเพื่อแสดงผลลัพธ์

ดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดการทรัพยากรใน Gradle ได้ที่ข้อมูลเบื้องต้นเกี่ยวกับการจัดการทรัพยากรในคู่มือผู้ใช้ Gradle

ยกเว้น Dependency แบบทรานซิทีฟ

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

Kotlin

dependencies {
    implementation("some-library") {
        exclude(group = "com.example.imgtools", module = "native")
    }
}

Groovy

dependencies {
    implementation('some-library') {
        exclude group: 'com.example.imgtools', module: 'native'
    }
}

ยกเว้นการพึ่งพาแบบทรานซิทีฟจากการกําหนดค่าการทดสอบ

หากต้องการยกเว้นการพึ่งพาแบบเปลี่ยนผ่านบางอย่างออกจากการทดสอบ ตัวอย่างโค้ดที่แสดงด้านบนอาจไม่ทำงานตามที่คาดไว้ นั่นเป็นเพราะการกำหนดค่าการทดสอบ (เช่น androidTestImplementation) ขยายการกำหนดค่าของimplementationโมดูล กล่าวคือ ไฟล์ดังกล่าวจะมีimplementation dependency เสมอเมื่อ Gradle แก้ปัญหาการกำหนดค่า

ดังนั้น หากต้องการยกเว้นการพึ่งพาแบบทรานซิทีฟจากการทดสอบ คุณต้องดำเนินการดังกล่าว ณ เวลาดำเนินการดังที่แสดงด้านล่าง

Kotlin

android.testVariants.all {
    compileConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
    runtimeConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
}

Groovy

android.testVariants.all { variant ->
    variant.getCompileConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
    variant.getRuntimeConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
}

หมายเหตุ: คุณยังคงใช้คีย์เวิร์ด exclude ในบล็อก dependencies ได้ตามที่แสดงในตัวอย่างโค้ดต้นฉบับจากส่วนยกเว้น dependencies แบบทรานซิทีฟ เพื่อละเว้น dependencies แบบทรานซิทีฟที่ใช้กับการกําหนดค่าการทดสอบโดยเฉพาะและไม่รวมอยู่ในการกําหนดค่าอื่นๆ

แก้ไขข้อผิดพลาดในการแก้ไขข้อขัดข้อง

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

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

หากระบุการพึ่งพาที่ซ้ำกันไม่ง่ายนัก ให้ลองใช้ UI ของ Android Studio เพื่อค้นหาการพึ่งพาที่มีคลาสที่ซ้ำกัน ดังนี้

  1. เลือกไปยังส่วนต่างๆ > ชั้นเรียนจากแถบเมนู
  2. ในกล่องโต้ตอบการค้นหาแบบป๊อปอัป ให้เลือกช่องข้างรวมรายการที่ไม่ใช่โปรเจ็กต์
  3. พิมพ์ชื่อคลาสที่ปรากฏในข้อผิดพลาดของบิลด์
  4. ตรวจสอบผลลัพธ์เพื่อหา Dependency ที่มีคลาส

ส่วนต่อไปนี้จะอธิบายข้อผิดพลาดในการแก้ไขข้อกําหนดเบื้องต้นประเภทต่างๆ ที่คุณอาจพบและวิธีแก้ไข

แก้ไขข้อผิดพลาดเกี่ยวกับชั้นเรียนที่ซ้ำกัน

หากคลาสปรากฏมากกว่า 1 ครั้งใน classpath รันไทม์ คุณจะได้รับข้อผิดพลาดที่คล้ายกับต่อไปนี้

Program type already present com.example.MyClass

ข้อผิดพลาดนี้มักเกิดขึ้นเนื่องจากสถานการณ์อย่างใดอย่างหนึ่งต่อไปนี้

  • Dependency แบบไบนารีประกอบด้วยไลบรารีที่แอปของคุณรวมไว้ด้วยในฐานะ Dependency โดยตรง เช่น แอปของคุณประกาศว่าขึ้นต่อกันโดยตรงกับไลบรารี ก และไลบรารี ข แต่ไลบรารี ก มีไลบรารี ข รวมอยู่ในไบนารีอยู่แล้ว
    • วิธีแก้ปัญหานี้คือนําไลบรารี ข. ออกในฐานะทรัพยากรที่ต้องพึ่งพาโดยตรง
  • แอปของคุณมีทรัพยากร Dependency แบบไบนารีในเครื่องและแบบไบนารีระยะไกลในไลบรารีเดียวกัน
    • วิธีแก้ปัญหานี้คือนําข้อกําหนดของไบนารีรายการใดรายการหนึ่งออก

แก้ไขความขัดแย้งระหว่าง classpath

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

คลาสพาธรันไทม์ของแอปจะกำหนดหมายเลขเวอร์ชันที่ Gradle ต้องใช้สำหรับไลบรารีที่เกี่ยวข้องซึ่งตรงกันในคลาสพาธรันไทม์สำหรับ APK การทดสอบของแอปด้วย ลำดับชั้นของ classpath มีคำอธิบายอยู่ในรูปที่ 1

รูปที่ 1 หมายเลขเวอร์ชันของไลบรารีที่ใช้ร่วมกันซึ่งปรากฏใน classpath หลายรายการต้องตรงกันตามลําดับชั้นนี้

ข้อขัดแย้งที่ทรัพยากร Dependency เดียวกันปรากฏใน classpath หลายรายการอาจเกิดขึ้นได้เมื่อแอปของคุณมีทรัพยากร Dependency เวอร์ชันหนึ่งที่ใช้implementation การกำหนดค่า Dependency และโมดูลไลบรารีมีทรัพยากร Dependency เวอร์ชันอื่นที่ใช้การกำหนดค่า runtimeOnly

เมื่อแก้ไขการพึ่งพาในรันไทม์และ classpath ขณะคอมไพล์ ปลั๊กอิน Gradle ของ Android เวอร์ชัน 3.3.0 ขึ้นไปจะพยายามแก้ไขข้อขัดแย้งของเวอร์ชันดาวน์สตรีมบางรายการโดยอัตโนมัติ ตัวอย่างเช่น หาก classpath รันไทม์มีไลบรารี ก เวอร์ชัน 2.0 และ classpath การคอมไพล์มีไลบรารี ก เวอร์ชัน 1.0 ปลั๊กอินจะอัปเดตทรัพยากร Dependency ใน classpath การคอมไพล์เป็นไลบรารี ก เวอร์ชัน 2.0 โดยอัตโนมัติเพื่อหลีกเลี่ยงข้อผิดพลาด

อย่างไรก็ตาม หาก classpath รันไทม์มีไลบรารี ก เวอร์ชัน 1.0 และ classpath การคอมไพล์มีไลบรารี ก เวอร์ชัน 2.0 ปลั๊กอินจะไม่ดาวน์เกรดการพึ่งพา classpath การคอมไพล์เป็นไลบรารี ก เวอร์ชัน 1.0 และคุณยังคงได้รับข้อผิดพลาดที่คล้ายกับข้อความต่อไปนี้

Conflict with dependency 'com.example.library:some-lib:2.0' in project 'my-library'.
Resolved versions for runtime classpath (1.0) and compile classpath (2.0) differ.

หากต้องการแก้ไขปัญหานี้ ให้ทำอย่างใดอย่างหนึ่งต่อไปนี้

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