在Android的不同模块中使用不同版本的SO文件(如libc++_shared.so)

问题描述 投票:0回答:3

我在应用程序的两个单独的模块中使用两个不同的自定义 aar 库。库附带了许多“.so”文件 - 例如“libc++_shared.so”等。在包含这两个文件后,我收到如下错误:

2 files found with path 'lib/arm64-v8a/libc++_shared.so' from inputs

所以我用了:

packagingOptions {
      pickFirst 
}

不幸的是,在我的情况下,这不是一个好的解决方案,因为现在运行我得到的应用程序后:

  java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "vpx_codec_enc_config_default" referenced by "[...]/base.apk!/lib/arm64-v8a/libmediaengine.so"...

有什么解决方案可以让我在不同版本的不同模块中使用两个相同的 .so 文件吗?

android kotlin android-ndk
3个回答
0
投票

当您在应用程序中包含两个包含相同 .so 文件的不同自定义 aar 库时,您可能会遇到链接器无法决定使用哪个版本的 .so 文件的问题。解决此问题的一种方法是为每个库中的 .so 文件使用不同的名称,例如

libc++_shared_v1.so
libc++_shared_v2.so
。这样,链接器就会知道每个库使用哪个版本的 .so 文件。

另一个解决方案是为您的应用程序使用不同的构建类型或风格。这样您就可以为每种构建类型或风格包含不同版本的 .so 文件。例如,您可以拥有使用第一个库的

debug
构建类型和使用第二个库的
release
构建类型。

您还可以使用自定义链接描述文件来指定要使用哪个版本的 .so 文件。该脚本可用于覆盖默认链接器行为,您可以使用它来指定每个库使用哪个版本的 .so 文件。

值得一提的是,使用自定义链接器脚本的解决方案并不总是那么容易,它需要一些 android NDK 和 JNI 的经验,并且在尝试此解决方案之前熟悉 android 构建过程非常重要。

综上所述,在android中的不同模块中使用相同.so文件的不同版本有多种解决方案。这取决于您的用例以及您愿意实施的解决方案的复杂性。


0
投票

以 Android 开发文档作为起点,了解如何使用 Android Gradle 插件的原生依赖项。同样有趣的是,虽然主要不是针对本机依赖项,但有关如何修复依赖项解析错误应用自定义构建逻辑的章节。

那么,让我们看看您的具体问题。

重复文件冲突

您有两个

libc++_shared.so
文件,具有相同的名称和路径。 Android 开发文档(见上文)建议:

要解决此问题,请删除其中一个二进制依赖项

请注意,您实际上是通过使用

pickFirst
来做到这一点的,并且您的
libc++_shared.so
问题已得到解决并转移到另一个库。但
pickFirst
不幸地影响了 Gradle 的进一步决定。

因此,更改您的

packagingOptions
以首先使用 pickFirst 'lib/arm64-v8a/libc++_shared.so' 选择一个
特定
文件。或者,您可以使用
exclude 'lib/arm64-v8a/libc++_shared.so'
,它将在添加到您的 APK 后从语义上排除该名称的更多(重复)文件。

严格来说,

exclude
pickFirst
现已弃用。如果我没记错的话,现在是
resources.excludes
resources.pickFirsts
,用作:

packagingOptions {
    resources.excludes += 'foo'
    resources.excludes += 'bar'

    // or:
    // resources.excludes += setOf(
    //     'foo',
    //     'bar'
    // )
  }

版本冲突

你提到过

我发现问题在于

libgnustl_shared.so
- 两个库正在使用该文件的不同版本。

通常使用更新的库版本是正确的选择,因此:

为了解决这一冲突,Android Gradle 插件使用以下依赖解析策略:当插件检测到依赖图中存在同一模块的不同版本时,默认情况下,它会选择版本号最高的版本。

通常就是这样,问题会自动解决。我怀疑,您通过使用

pickFirst
覆盖了该行为,而不命名具体文件,例如将其应用于所有内容。

如果您需要两个版本,您必须将它们视为不同的库并重命名它们,例如

libfoo.so.1.1
libfoo.so.1.2
变成
libfoo1.so
libfoo2.so
什么的。

当然,还要检查您是否提供了所有必要的依赖项。


希望对您有帮助。


0
投票

有两种方法可以解决此问题。

  1. 确保两个模块都是使用相同版本的 NDK 构建的。那么两个模块的 libc++_shared.so 都是相同的,你可以选择第一个。

  2. 另一种选择是使用 ANDROID_STL=c++_static 构建一个模块,那么它不会产生 libc++_shared.so,因此不会发生冲突。

感谢我之前的同事李建明在我遇到这个问题时给了我以上两种解决方案。对于我的情况,我们使用第二种方法来解决问题。

© www.soinside.com 2019 - 2024. All rights reserved.