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

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

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

ดูการอ้างอิงโมดูล

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

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

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 > งาน > android และ ดับเบิลคลิก androidDependencies หลังจาก Gradle ดำเนินการ งานนั้น หน้าต่าง Run ควรเปิดขึ้นเพื่อแสดงเอาต์พุต

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

ไม่รวมการอ้างอิงแบบสับเปลี่ยน

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

Kotlin

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

ดึงดูด

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

ไม่รวมทรัพยากร Dependency แบบทรานซิทีฟจากการกำหนดค่าการทดสอบ

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

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

Kotlin

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

ดึงดูด

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

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

แก้ไขข้อผิดพลาดเกี่ยวกับการแปลงทรัพยากร Dependency

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

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

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

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

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

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

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

Program type already present com.example.MyClass

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

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

แก้ไขความขัดแย้งระหว่างเส้นทางคลาส

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

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

รูปที่ 1 หมายเลขเวอร์ชันของทรัพยากร Dependency ที่ปรากฏในหลายคลาสพาธต้องตรงกับ ลำดับชั้น

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

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

แต่หากคลาสพาธรันไทม์มีไลบรารี A เวอร์ชัน 1.0 และคอมไพล์ classpath มีไลบรารี A เวอร์ชัน 2.0 แต่ปลั๊กอินจะไม่ปรับลดรุ่น ขึ้นอยู่กับคลาสพาธการคอมไพล์ไปยังไลบรารี A เวอร์ชัน 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 เวอร์ชันที่ต้องการเป็นทรัพยากร Dependency api ของคุณ โมดูลไลบรารี กล่าวคือ มีเพียงโมดูลไลบรารีของคุณเท่านั้นที่จะประกาศทรัพยากร Dependency โมดูลแอปจะมีสิทธิ์เข้าถึง API แบบทางอ้อมด้วย
  • อีกทางเลือกหนึ่งคือคุณสามารถประกาศ Dependency ในทั้ง 2 โมดูลได้ แต่คุณควร ตรวจสอบว่าแต่ละโมดูลใช้ทรัพยากร Dependency เวอร์ชันเดียวกัน พิจารณา การกำหนดค่าพร็อพเพอร์ตี้ของทั้งโปรเจ็กต์ เพื่อให้มั่นใจว่าทรัพยากร Dependency แต่ละเวอร์ชันจะสอดคล้องกันตลอดทั้งโปรเจ็กต์