对于特定共享包或库,如果其他一些包对这些共享包或库具有依赖项,但依赖于不同且互不兼容的共享包版本,这时候便会发生依赖项问题。Gradle 让 Android 开发者的工作变得很轻松:开发者只需在 build.gradle 中添加一个依赖项,所需的库就会无缝纳入 build 文件中。但是,如果两个依赖项依赖于同一个库的不同版本,会发生什么?
如果两个依赖项属于同一个配置(即应用配置),Gradle 能够自动解决依赖项问题。例如,Android 版 Audience Network SDK 依赖于 "exoplayer" 库。如果您需要添加不同版本的 "exoplayer" 库,Gradle 将选择纳入较高版本的库。但是,如果两个依赖项属于不同配置(即应用配置和测试配置),Gradle 就会抛出错误。下面我们将介绍不同的冲突类型和解决方案。
请确保先阅读 Audience Network 入门指南和 Android 入门指南,然后再继续操作。
请参考以下示例。以下代码中的两个依赖项属于同一个配置,并有一个对 "org.hamcrest:hamcrest-core" 库的内部依赖项。由于两个依赖项内部使用同一库的不同版本,系统会将最高版本的库纳入 build 文件中。Gradle 同步的输出结果将清楚表明,系统在最终 build 文件中自动将 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'
如果两个依赖项属于不同配置(即应用配置和测试配置),Gradle 就会抛出错误。请参考以下代码片段。第一个依赖项属于应用配置,而第二个依赖项属于测试配置。因此,项目构建会失败,并出现异常。
当运行插桩测试时,主 APK 和测试 APK 使用相同的类路径。如果主 APK 和测试 APK 使用相同的库(例如 Guava),但库的版本不同,则 Gradle 构建会失败。如果 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'
这是最简单的方法,但限用于属于同一个配置的依赖项。例如,您的模块显式依赖于 ExoPlayer 的某个特定版本。然而,Audience Network SDK 已包含了 ExoPlayer 的另一版本。默认情况下,系统会将最高版本纳入 build 文件中。根据以下代码片段,Gradle 同步的输出结果将清楚地说明,它在最终 build 文件中自动将 ExoPlayer 库的版本从 2.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'
在大多数情况下,开发者可能想控制要将哪个库的版本纳入最终 build 文件中。您可以配置 build.gradle 来实现库版本控制。例如,如果开发者希望使用低版本 ExoPlayer r2.4.0,而不是 Audience Network SDK 中的 r2.4.2,则您可以在声明 "audience-network-sdk" 依赖项时排除此模块。排除标签也适用于属于不同配置的依赖项。
在实际项目中,有许多依赖项会具有同一库的不同版本。在这种情况下,对每个依赖项,您都需要设置排除标签,以便可以将该库的预期版本纳入 build 文件中。
情景 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' }
当属于不同配置的依赖项发生冲突时,这是较简便的解决方法。在这种情况下,无论依赖项属于哪种配置,我们都需要显式提及要纳入最终 build 文件中的特定库版本。
这种冲突解决方法较为简便,但缺点在于:在更新 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'
这是解决冲突的另一种方法。该方法不是为一种配置声明,而是强制为所有配置声明。在以下示例中,您可以将自己的 "resolutionStrategy" 添加到模块级 build.gradle 中,从而强制将指定的包版本纳入 build 文件中,无论依赖项属于同一个配置还是不同配置。
该方法应谨慎使用。在第一个示例中,如果 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 政策和 Facebook 社区守则。详细了解 Facebook 的审核流程。