การแก้ไขปัญหาส่วนที่ขึ้นต่อกันของ SDK บน Android

ปัญหาจากส่วนที่ขึ้นต่อกันเกิดขึ้นกับแพ็คเกจหรือไลบรารีที่ใช้ร่วมกัน ซึ่งแพ็คเกจอื่นๆ จำนวนมากมีส่วนที่ขึ้นต่อกัน แต่ส่วนที่ขึ้นต่อกันเหล่านั้นกลับต้องอาศัยแพ็คเกจที่ใช้ร่วมกันในเวอร์ชั่นที่แตกต่างกันหรือไม่สามารถเข้ากันได้ Gradle ช่วยให้ผู้พัฒนา Android สะดวกสบายขึ้น เพียงแค่เพิ่มส่วนที่ขึ้นต่อกันหนึ่งรายการใน build.gradle แล้วไลบรารีที่จำเป็นก็จะรวมอยู่ในบิลด์ได้อย่างราบรื่น แต่จะเกิดอะไรขึ้นหากส่วนที่ขึ้นต่อกันสองรายการต้องอาศัยไลบรารีเดียวกันแต่คนละเวอร์ชั่น

Gradle สามารถแก้ไขปัญหาจากส่วนที่ขึ้นต่อกันได้โดยอัตโนมัติหากส่วนที่ขึ้นต่อกันทั้งสองรายการมาจากการกำหนดค่าเดียวกัน เช่น การกำหนดค่าแอพ ตัวอย่างเช่น Audience Network Android SDK ต้องอาศัยไลบรารี "exoplayer" หากคุณต้องการเพิ่มไลบรารี "exoplayer" เวอร์ชั่นอื่น Gradle จะเลือกเวอร์ชั่นที่สูงกว่าให้ แต่หากส่วนที่ขึ้นต่อกันทั้งสองรายการมาจากการกำหนดค่าที่แตกต่างกัน เช่น แอพและการทดสอบ Gradle ก็จะแสดงข้อผิดพลาด เราจะกล่าวถึงข้อขัดแย้งและแนวทางแก้ไขต่างๆ ด้านล่างนี้

ข้อกำหนดเบื้องต้น

อย่าลืมดูคู่มือเริ่มต้นใช้งาน Audience Network และเริ่มต้นใช้งาน Android ก่อนดำเนินการต่อ

ข้อขัดแย้งจากส่วนที่ขึ้นต่อกัน

1: ไลบรารีที่ใช้ร่วมกันในส่วนที่ขึ้นต่อกันจากการกำหนดค่าเดียวกัน

2: ไลบรารีที่ใช้ร่วมกันในส่วนที่ขึ้นต่อกันจากการกำหนดค่าที่แตกต่างกัน

แนวทางการแก้ไขข้อขัดแย้งจากส่วนที่ขึ้นต่อกัน

1: ให้ Gradle แก้ไขปัญหาจากส่วนที่ขึ้นต่อกันสำหรับคุณ

2: ยกเว้นส่วนที่ขึ้นต่อกันในเวอร์ชั่นใดเวอร์ชั่นหนึ่ง

3: กำหนดไลบรารีที่ขัดแย้งกันอย่างชัดเจนใน Gradle

4: บังคับการแก้ไขปัญหาของไลบรารี



ข้อขัดแย้งจากส่วนที่ขึ้นต่อกัน

1: ไลบรารีที่ใช้ร่วมกันในส่วนที่ขึ้นต่อกันจากการกำหนดค่าเดียวกัน

ลองพิจารณาตัวอย่างต่อไปนี้ ส่วนที่ขึ้นต่อกันทั้งสองรายการในโค้ดด้านล่างยังคงอยู่ในการกำหนดค่าเดียวกัน และมีส่วนที่ขึ้นต่อกันภายในกับไลบรารี "org.hamcrest:hamcrest-core" เนื่องจากส่วนที่ขึ้นต่อกันทั้งสองรายการใช้ไลบรารีเดียวกันแต่คนละเวอร์ชั่นเป็นการภายใน ระบบจะรวมเวอร์ชั่นสูงสุดไว้ในบิลด์ เอาต์พุตจากการซิงค์ของ Gradle จะระบุอย่างชัดเจนว่าจะอัพเกรดไลบรารี hamcrest จากเวอร์ชั่น 1.1 เป็น 1.3 โดยอัตโนมัติในบิลด์สุดท้าย

// Depends on version 1.3 of org.hamcrest:hamcrest-core
androidTestImplementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19'  

2: ไลบรารีที่ใช้ร่วมกันในส่วนที่ขึ้นต่อกันจากการกำหนดค่าที่แตกต่างกัน

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

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

// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19' 

แนวทางการแก้ไขข้อขัดแย้งจากส่วนที่ขึ้นต่อกัน

1: ให้ Gradle แก้ไขปัญหาให้คุณ

แนวทางนี้เป็นแนวทางที่ง่ายที่สุด แต่จำกัดเฉพาะส่วนที่ขึ้นต่อกันในการกำหนดค่าเดียวกัน ตัวอย่างเช่น โมดูลของคุณต้องอาศัย ExoPlayer เวอร์ชั่นใดเวอร์ชั่นหนึ่งอย่างชัดเจน อย่างไรก็ตาม Audience Network SDK ได้รวม ExoPlayer เวอร์ชั่นอื่นไว้แล้ว โดยค่าเริ่มต้น ระบบจะรวมเวอร์ชั่นสูงสุดไว้ในบิลด์ ส่วนย่อยของโค้ดด้านล่างจะช่วยให้เอาต์พุตจากการซิงค์ของ Gradle ระบุอย่างชัดเจนว่าจะอัพเกรดไลบรารี ExoPlayer จากเวอร์ชั่น r2.4.2 เป็น 2.7.3 โดยอัตโนมัติในบิลด์สุดท้าย

implementation 'com.google.android.exoplayer:exoplayer-core:2.7.3'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.7.3'
...
// audience-network-sdk depends on exoplayer-core:r2.4.2 and exoplayer-dash:r2.4.2
implementation 'com.facebook.android:audience-network-sdk:4.28.1' 

2: ยกเว้นส่วนที่ขึ้นต่อกันในเวอร์ชั่นใดเวอร์ชั่นหนึ่ง

ในสถานการณ์ส่วนใหญ่ ผู้พัฒนาอาจต้องการควบคุมว่าไลบรารีเวอร์ชั่นใดที่จะรวมอยู่ในบิลด์ในท้ายที่สุด คุณสามารถกำหนดค่า build.gradle เพื่อดำเนินการดังกล่าวได้ ตัวอย่างเช่น หากผู้พัฒนาต้องการ ExoPlayer r2.4.0 ซึ่งเป็นเวอร์ชั่นต่ำกว่าแทนที่จะเป็นเวอร์ชั่น r2.4.2 ใน Audience Network SDK คุณก็สามารถยกเว้นโมดูลนั้นในขณะที่ระบุส่วนที่ขึ้นต่อกันของ "audience-network-sdk" ได้ แท็กยกเว้นจะมีผลกับส่วนที่ขึ้นต่อกันในการกำหนดค่าที่แตกต่างกันด้วย

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

สถานการณ์ที่ 1: ส่วนที่ขึ้นต่อกันในการกำหนดค่าเดียวกัน
implementation 'com.google.android.exoplayer:exoplayer-core:r2.4.0'
implementation 'com.google.android.exoplayer:exoplayer-dash:r2.4.0'
...
// audience-network-sdk depends on exoplayer-core:r2.4.2 and exoplayer-dash:r2.4.2
implementation ('com.facebook.android:audience-network-sdk:4.28.1') {
    exclude group: 'com.google.android.exoplayer', module:'exoplayer-core'
    exclude group: 'com.google.android.exoplayer', module:'exoplayer-dash'
}
สถานการณ์ที่ 2: ส่วนที่ขึ้นต่อกันในการกำหนดค่าที่แตกต่างกัน
// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation ('org.mockito:mockito-core:1.10.19'){
    exclude group: 'org.hamcrest', module:'hamcrest-core'
}

3: กำหนดไลบรารีที่ขัดแย้งกันอย่างชัดเจนใน Gradle

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

แนวทางนี้เป็นแนวทางแก้ไขข้อขัดแย้งมีความซับซ้อนน้อยกว่า แต่มีข้อเสียคือในขณะที่อัพเดตส่วนที่ขึ้นต่อกันจริง เช่น junit และ mockito ผู้พัฒนาจำเป็นต้องอัพเดตไลบรารีที่ขัดแย้งด้วยเช่นกัน

// Depends on version 1.3 of org.hamcrest:hamcrest-core 
implementation 'junit:junit:4.12' 
// Depends on version 1.1 of org.hamcrest:hamcrest-core
androidTestImplementation 'org.mockito:mockito-core:1.10.19' 
// Explictly mention that include version 1.3 of org.hamcrest:hamcrest-core
androidTestCompile 'org.hamcrest:hamcrest-core:1.3' 

4: บังคับการแก้ไขปัญหาของไลบรารี

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

คุณควรใช้แนวทางนี้ด้วยความระมัดระวัง ในตัวอย่างแรก หาก audience-network-sdk ได้รับการอัพเดต และไลบรารีเหล่านี้อัพเดตเวอร์ชั่นของไลบรารี exoplayer-core และ exoplayer-dash เราก็จะยังคงบังคับให้ใช้เวอร์ชั่นย้อนหลัง แม้ว่าคุณจะสามารถใช้แนวทางแก้ไขปัญหาที่สองกับสถานการณ์ดังกล่าวได้ แต่ในแนวทางนี้ เราจะบังคับใช้ส่วนที่ขึ้นต่อกันเวอร์ชั่นนี้ในการกำหนดค่าทั้งหมด แทนที่จะใช้ในการกำหนดค่าเดียว

สถานการณ์ที่ 1: ส่วนที่ขึ้นต่อกันในการกำหนดค่าเดียวกัน
android {
    configurations.all {
        resolutionStrategy.force 'com.google.android.exoplayer:exoplayer-core:r2.4.0'
        resolutionStrategy.force 'com.google.android.exoplayer:exoplayer-dash:r2.4.0'
    }
}
สถานการณ์ที่ 2: ส่วนที่ขึ้นต่อกันในการกำหนดค่าที่แตกต่างกัน
android {
    configurations.all {
        resolutionStrategy.force 'org.hamcrest:hamcrest-core:1.1'
    }
}

ขั้นตอนถัดไป

แหล่งข้อมูลเพิ่มเติม

คู่มือการเริ่มต้นใช้งาน

คู่มือเชิงเทคนิคในการเริ่มต้นใช้งาน Audience Network

ข้อมูลอ้างอิงเกี่ยวกับ API

ข้อมูลอ้างอิง Facebook SDK สำหรับ iOS