【问题标题】:Android native library (.so) - unsatisfied link errorAndroid 本机库 (.so) - 不满意的链接错误
【发布时间】:2019-03-13 07:49:16
【问题描述】:

我最近创建并发布了一个 Android 应用程序包,其中包含适用于所有处理器架构的已编译本机库。在大多数设备上,一切都运行正常。但在某些设备上,我可以在 Crashlytics 控制台中看到此错误 致命异常:java.lang.UnsatisfiedLinkError dalvik.system.PathClassLoader[DexPathList[[zip 文件“/system/framework/org.apache.http.legacy.boot.jar”,zip 文件“/data/app/com.someapp-wAu5DoLmLvM_RVnbU1qsCg==/base.apk” ],nativeLibraryDirectories=[/data/app/com.someapp-wAu5DoLmLvM_RVnbU1qsCg==/lib/arm64, /system/lib64]]] 找不到“somemylib.so”

我想知道 - 为什么会发生这种情况。我有 x64 处理器的库。这仅在某些设备上发生 - 但这种崩溃是 Crashlytics 中最常见的。 我所有的库都存储在 jniLibs 目录中 这些是我的 build.gradle 中的一些片段

bundle {
    density {
        // Different APKs are generated for devices with different screen densities; true by default.
        enableSplit false
    }
    abi {
        // Different APKs are generated for devices with different CPU architectures; true by default.
        enableSplit true
    }
    language {
        // This is disabled so that the App Bundle does NOT split the APK for each language.
        // We're gonna use the same APK for all languages.
        enableSplit false
    }
}
splits {
    abi {
        enable true
        reset()
        include 'armeabi', 'mips', 'x86', 'armeabi-v7a', 'arm64-v8a', 
 'mips64', 'x86_64'
    }
}
sourceSets {

    main {
        jniLibs.srcDirs = ['jniLibs']
    }
}

我的应用程序中有一个服务类,它试图在有人启动它时加载本机库。我有时会在操作系统检测到我的应用程序中的本机库之前执行对服务的“开始”调用?但我不认为是这样。 你能帮帮我吗

【问题讨论】:

    标签: android c kotlin java-native-interface


    【解决方案1】:

    您的问题不在于库代码,而在于 .so 文件本身。 Android 设备有一个主要的 ABI,即处理器支持的指令集。 例如,某些具有 64 位处理器的设备使用 ABI arm64-v8a

    但是,许多库和应用程序还不支持 64 位处理器。所以通常,较新的处理器还支持辅助 ABI,这是一种更常见的 ABI。例如,arm64-v8a 处理器通常也支持armeabi-v7a

    当应用启动时,它会开始在目录中查找本机库。首先,它检查主 ABI 目录,在此示例中为 arm64-v8a。如果 .so 文件不存在,它会检查辅助 ABI 目录 (armeabi-v7a)。如果仍未找到,您将收到您描述的错误。

    就您而言,正如您所说,您拥有文件,所以这不是问题。

    这个选择的一个大问题是,如果目录存在,它总是坚持主 ABI。如果不是所有库都为所有 ABI 提供所有 .so 文件,这可能会导致崩溃。这被描述为here

    这是一个示例:您在应用中包含 2 个库: 1. VideoPlayerLibrary,其中包含所有 ABI 的 .so 文件 2. GifLibrary,只有armeabiarmeabi-v7a 的.so 文件。

    现在,如果您在 arm64-v8a 设备上启动应用程序,它将坚持使用它的主要 ABI,因为它已在其中找到文件(VideoPlayerLibrary 的 .so 文件)。但是在你想播放 gif 的那一刻,它会尝试从 arm64-v8a 目录加载 .so 文件,但它不会在那里找到它们,它会像你的帖子一样崩溃并出现链接错误。

    那你能做什么?

    你有两个选择:

    1. 如果是您自己的库缺少 .so 文件,请为所有 ABI 编译它。 如果不是您自己的,请检查是否有修复此问题的更新版本。
    2. 从应用程序中排除不完整的 ABI。这样,较新的处理器将使用辅助 ABI 来运行应用程序。这当然会导致性能下降,但不会崩溃。 根据我的经验,最重要的 ABI 是 armeabi-v7a,这应该是所有 Android 设备都支持的。

    【讨论】:

    • 您是否检查过拆分发行版 apk 中的 .so 文件?也许它可能在发布构建过程中被忽略了。也可能是虚假报告,请参阅此类似问题:stackoverflow.com/questions/52595535/…
    • 可能就是这样。在 Google Play 崩溃统计信息中,您可以过滤安装源(Google Play 或其他),这会过滤掉这个问题。
    • 我的 build.gradle ndk.abiFilters = 'armeabi-v7a' 'arm64-v8a' 'x86' 'x86_64' 中缺少这一行。可能问题在于我在 build.gradle 中没有这一行?
    • 从这个媒体帖子中查看 bundletool:medium.com/google-developer-experts/explor...
    • 好的。谢谢。我会检查并稍后写下我的成功
    【解决方案2】:

    这个问题可能与https://issuetracker.google.com/issues/127691101有关

    在用户已将应用移至 SD 卡的部分 LG 设备或旧三星设备上会发生这种情况。

    解决此问题的一种方法是使用 Relinker 库来加载您的本地库,而不是直接调用 System.load 方法。

    https://github.com/KeepSafe/ReLinker

    另一种方法是阻止应用移动到 SD 卡。

    您还可以在 gradle.properties 文件中保留 android.bundle.enableUncompressedNativeLibs=false。但它会增加 Play Store 上的应用下载大小以及磁盘大小。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-26
      • 1970-01-01
      • 2016-04-26
      • 2014-03-26
      • 1970-01-01
      • 1970-01-01
      • 2012-04-22
      • 2013-09-10
      相关资源
      最近更新 更多