Giải pháp cho phần phụ thuộc SDK trên Android

Vấn đề về phần phụ thuộc phát sinh từ các gói hoặc thư viện dùng chung mà trong đó, một số gói khác có phần phụ thuộc nhưng chúng lại phụ thuộc vào những phiên bản khác và không tương thích của các gói dùng chung nêu trên. Gradle đã giúp cuộc sống của các nhà phát triển Android trở nên khá dễ dàng - chỉ cần thêm một phần phụ thuộc vào file build.gradle thì thư viện bắt buộc sẽ mặc nhiên có trong bản dựng. Tuy nhiên, điều gì sẽ xảy ra khi 2 phần phụ thuộc đều có phần phụ thuộc trên các phiên bản khác nhau của cùng một thư viện?

Gradle có thể tự động giải quyết các phần phụ thuộc nếu cả hai phần phụ thuộc này nằm trong cùng một cấu hình, tức là cấu hình ứng dụng. Ví dụ: Audience Network Android SDK phụ thuộc vào thư viện "exoplayer". Nếu bạn cần thêm một phiên bản khác của thư viện "exoplayer", Gradle sẽ chọn đưa vào phiên bản cao hơn. Nhưng nếu cả hai phần phụ thuộc nằm trong các cấu hình khác nhau, tức là cấu hình ứng dụng và cấu hình thử nghiệm, Gradle sẽ trả về lỗi. Trong phần bên dưới, chúng tôi sẽ trình bày các xung đột và giải pháp khác nhau.

Điều kiện tiên quyết

Đảm bảo bạn đã hoàn tất hướng dẫn Bắt đầuBắt đầu dành cho Android với Audience Network trước khi tiếp tục.

Xung đột phần phụ thuộc

1: Thư viện dùng chung trong phần phụ thuộc từ cùng một cấu hình

2: Thư viện dùng chung trong phần phụ thuộc từ các cấu hình khác nhau

Giải pháp cho xung đột phần phụ thuộc

1: Để Gradle giải quyết phần phụ thuộc cho bạn

2: Loại trừ phiên bản cụ thể của phần phụ thuộc

3: Xác định rõ ràng thư viện xung đột trong Gradle

4: Buộc phải giải quyết thư viện



Xung đột phần phụ thuộc

1: Thư viện dùng chung trong phần phụ thuộc từ cùng một cấu hình

Hãy xem xét ví dụ sau đây. Cả hai phần phụ thuộc trong mã dưới đây đều nằm trong cùng một cấu hình và có phần phụ thuộc nội bộ trên thư viện "org.hamcrest:hamcrest-core". Cả hai phần phụ thuộc đều sử dụng nội bộ các phiên bản khác nhau của cùng một thư viện, do đó, phiên bản cao nhất sẽ được đưa vào bản dựng. Kết quả của quá trình đồng bộ Gradle sẽ cho thấy rõ rằng hệ thống tự động nâng cấp phiên bản thư viện hamcrest từ 1.1 lên 1.3 trong bản dựng cuối cùng.

// 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: Thư viện dùng chung trong phần phụ thuộc từ các cấu hình khác nhau

Nếu cả hai phần phụ thuộc nằm trong các cấu hình khác nhau, tức là cấu hình ứng dụng và cấu hình thử nghiệm, Gradle sẽ trả về lỗi. Hãy xem xét đoạn mã sau đây. Phần phụ thuộc đầu tiên nằm trong cấu hình ứng dụng, còn phần phụ thuộc thứ hai nằm trong cấu hình thử nghiệm. Vì vậy, trong quá trình tạo dự án, bản dựng sẽ bị lỗi kèm theo ngoại lệ.

Khi chạy thử nghiệm đo lường, cả APK chính và APK thử nghiệm đều dùng chung một classpath. Bản dựng Gradle sẽ bị lỗi nếu APK chính và APK thử nghiệm sử dụng cùng một thư viện (ví dụ: Guava) nhưng ở các phiên bản khác nhau. Nếu Gradle không xử lý được vấn đề đó, ứng dụng của bạn có thể hoạt động không giống nhau giữa quá trình thử nghiệm và quá trình chạy bình thường (bao gồm cả bị lỗi ở một trong các trường hợp).

// 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' 

Giải pháp cho xung đột phần phụ thuộc

1: Để Gradle giải quyết cho bạn

Đây là phương pháp đơn giản nhất nhưng chỉ áp dụng được khi các phần phụ thuộc nằm trong cùng một cấu hình. Ví dụ: mô-đun của bạn phụ thuộc rõ ràng vào một phiên bản cụ thể của ExoPlayer. Tuy nhiên, Audience Network SDK đã bao gồm một phiên bản ExoPlayer khác. Theo mặc đinh, phiên bản cao nhất sẽ được đưa vào bản dựng. Với đoạn mã dưới đây, kết quả của quá trình đồng bộ Gradle sẽ cho biết rõ rằng hệ thống tự động nâng cấp phiên bản thư viện ExoPlayer từ r2.4.2 lên 2.7.3 trong bản dựng cuối cùng.

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: Loại trừ phiên bản cụ thể của phần phụ thuộc

Trong hầu hết các trường hợp, nhà phát triển nên kiểm soát phiên bản thư viện cuối cùng sẽ được đưa vào bản dựng. Bạn được phép đặt cấu hình file build.gradle để kiểm soát việc đó. Ví dụ: nếu nhà phát triển của bạn thích phiên bản thấp hơn, tức là ExoPlayer r2.4.0 chứ không phải r2.4.2 trong Audience Network SDK, bạn có thể loại trừ mô-đun đó trong khi khai báo phần phụ thuộc "audience-network-sdk". Thẻ loại trừ cũng sẽ áp dụng cho các phần phụ thuộc nằm trong những cấu hình khác nhau.

Dự án thực sẽ có nhiều phần phụ thuộc nằm trong các phiên bản khác nhau của cùng một thư viện. Trong trường hợp đó, đối với mỗi và từng phần phụ thuộc, bạn sẽ cần có thẻ loại trừ để có thể thêm phiên bản mong muốn của thư viện đó.

Trường hợp 1: Các phần phụ thuộc nằm trong cùng một cấu hình
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'
}
Trường hợp 2: Các phần phụ thuộc nằm trong cấu hình khác nhau
// 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: Xác định rõ ràng thư viện xung đột trong Gradle

Đây là một cách nhanh gọn hơn để giải quyết xung đột khi các phần phụ thuộc nằm trong những cấu hình khác nhau. Trong trường hợp này, chúng ta cần đề cập rõ ràng phiên bản của thư viện mà chúng ta muốn đưa vào bản dựng cuối cùng cho một cấu hình bất kỳ.

Phương pháp này giúp giải quyết xung đột nhanh gọn hơn, nhưng nhược điểm là khi cập nhật các phần phụ thuộc thực tế như junitmockito, nhà phát triển cũng cần phải cập nhật thư viện bị xung đột.

// 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: Buộc phải giải quyết thư viện

Đây là một cách khác để giải quyết xung đột, trong đó, thay vì khai báo cho một cấu hình thì chúng ta sẽ buộc phải khai báo cho tất cả cấu hình. Trong ví dụ dưới đây, bạn có thể thêm "resolutionStrategy" của riêng mình vào file build.gradle ở cấp độ mô-đun để buộc phải thêm phiên bản gói đã chỉ định, bất kể phần phụ thuộc nằm trong cùng một cấu hình hay trong những cấu hình khác nhau.

Bạn nên thận trọng khi sử dụng phương pháp này. Trong ví dụ đầu tiên, nếu audience-network-sdk được cập nhật và những thư viện này cập nhật phiên bản của các thư viện exoplayer-core và exoplayer-dash, chúng ta vẫn buộc phải sử dụng phiên bản trước đó. Mặc dù trường hợp này đúng với phương pháp tiếp cận giải pháp thứ hai, nhưng theo phương pháp này, chúng ta sẽ buộc phải sử dụng phiên bản của phần phụ thuộc nằm trong tất cả cấu hình chứ không chỉ trong một cấu hình.

Trường hợp 1: Các phần phụ thuộc nằm trong cùng một cấu hình
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'
    }
}
Trường hợp 2: Các phần phụ thuộc nằm trong cấu hình khác nhau
android {
    configurations.all {
        resolutionStrategy.force 'org.hamcrest:hamcrest-core:1.1'
    }
}

Các bước tiếp theo

Thông tin và nguồn lực khác

Hướng dẫn bắt đầu

Hướng dẫn kỹ thuật để bắt đầu sử dụng Audience Network

Tài liệu tham khảo về API

Tài liệu tham khảo về Facebook SDK dành cho iOS