【问题标题】:System.loadLibrary(...) couldn't find native library in my caseSystem.loadLibrary(...) 在我的情况下找不到本机库
【发布时间】:2023-03-11 05:36:01
【问题描述】:

我想使用来自另一个 Android 项目的现有原生库,所以我只是将 NDK 构建的库 (libcalculate.so) 复制到我的新 Android 项目中。在我的新 Android 项目中,我创建了一个文件夹 libs/armeabi/ 并将 libcalculate.so 放在那里。没有没有 jni/ 文件夹。我的测试设备采用 ARM 架构。

在我的 java 代码中,我通过以下方式加载库:

  static{
    System.loadLibrary("calculate");
  }

当我运行我的新 android 项目时,出现错误:

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"

所以,正如错误所说,复制的本机库不在 /verdor/lib 或 /system/lib 中,在我的情况下如何解决这个问题?

(我解压了apk包,lib/下有libcalculate.so)

====更新=====

我还尝试在项目根目录下创建一个 jni/ 文件夹,并在 jni/ 下添加一个 Android.mk 文件。 Android.mk的内容是:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := libcalculate
LOCAL_SRC_FILES := libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)

然后,在项目根目录下,我执行了 ndk-build 。之后,由ndk-build生成armeabi/和armeabi-v7a/目录(文件夹内有libcalculate.so)。

然后我成功运行我的 maven 构建项目。在最终的apk包中,有:

lib/armeabi/libcalculate.so
lib/armeabi-v7a/libcalculate.so

但是当我运行我的应用程序时,同样的错误抛出:

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"

【问题讨论】:

  • 你把库直接放在libs/下?您可能需要为每个要支持的目标 ABI(armeabi、armeabi-v7a、x86、mips 等)创建一个子目录,并将适当的 .so 文件放在每个子目录中(即为 armeabi 构建的 .so 文件放在 @ 987654329@等)。
  • @Michael ,我只是错过了在我的帖子中,我实际上把它放在了 libs/armeabi/
  • 检查 libcalculate.so 是否实际被打包过程拾取 - 尝试例如unzip -l package.apk,或将 apk 重命名为 .zip 并使用某些应用程序打开它。如果不存在,则说明打包有问题(您的 IDE 是否注意到文件夹存在,是否需要刷新项目?)。
  • @mstorsjo,我解压了apk包,在lib/下有libcalculate.so
  • 您不需要有 Android.mk 或任何与编译相关的文件。只需将 so 文件放在 jniLibs 的相应子目录中,如下所示:github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/…

标签: android android-ndk


【解决方案1】:
defaultConfig {
ndk {
            abiFilters "armeabi-v7a", "x86", "armeabi", "mips"
    }
}

只需在 build.gradle 应用级别添加这些行

【讨论】:

  • 对我来说,它需要是这样的:ndk { abiFilters 'armeabi-v7a', 'x86' }
【解决方案2】:

您可以更改 ABI 以使用旧版本:

defaultConfig {
    ...

    ndk {
        abiFilters 'armeabi-v7a'
    }
    ...
}

您还应该通过将此行添加到 gradle.properties 来使用已弃用的 NDK:

android.useDeprecatedNdk=true

【讨论】:

    【解决方案3】:

    此错误的原因是您的应用与您链接的本机库之间的 ABI 不匹配。换句话说,你的应用和你的.so 是针对不同的ABI。

    如果您使用最新的 Android Studio 模板创建您的应用,它可能以 arm64-v8a 为目标,但您的 .so 可能以 armeabi-v7a 为目标。

    有两种方法可以解决这个问题:

    1. 为您的应用支持的每个 ABI 构建您的原生库。
    2. 更改您的应用以针对您的 .so 构建的旧 ABI。

    选择 2 很脏,但我认为您可能对以下内容更感兴趣:

    更改您应用的build.gradle

    android {
        defaultConfig {
            ...
            ndk {
                abiFilters 'armeabi-v7a'
            }
       }
    }
    

    【讨论】:

    • 如果我的应用程序在 Eclipse 中怎么办?当我将同一个自定义应用从 6 迁移到 9 时,就会出现这个问题。
    • 这是对我有用的真正方法! :-)。
    【解决方案4】:

    这是 Android 8 更新。

    在早期版本的 Android 中,对于 LoadLibrary 本地共享库(例如,通过 JNI 访问),我硬连线我的本地代码,以根据各种 apk 安装迭代遍历 lib 文件夹的一系列潜在目录路径/升级算法:

    /data/data/<PackageName>/lib
    /data/app-lib/<PackageName>-1/lib
    /data/app-lib/<PackageName>-2/lib
    /data/app/<PackageName>-1/lib
    /data/app/<PackageName>-2/lib
    

    这种方法很老套,不适用于 Android 8;来自https://developer.android.com/about/versions/oreo/android-8.0-changes.html 您会看到,作为他们“安全”更改的一部分,您现在需要使用 sourceDir:

    “您不能再假设 APK 驻留在名称以 -1 或 -2 结尾的目录中。应用应使用 sourceDir 获取目录,而不是直接依赖目录格式。”

    更正,sourceDir 不是查找本机共享库的方法;使用类似的东西。测试安卓 4.4.4 --> 8.0

    // Return Full path to the directory where native JNI libraries are stored.
    private static String getNativeLibraryDir(Context context) {
        ApplicationInfo appInfo = context.getApplicationInfo();
        return appInfo.nativeLibraryDir;
    }
    

    【讨论】:

      【解决方案5】:

      请添加所有支持

      app/build.gradle

      ndk {
              moduleName "serial_port"
              ldLibs "log", "z", "m"
              abiFilters "arm64-v8a","armeabi", "armeabi-v7a", "x86","x86_64","mips","mips64"
      }
      

      app\src\jni\Application.mk

      APP_ABI := arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64
      

      【讨论】:

      • 您能否更具体地说明该怎么做?
      • 项目中的 .so 文件。你应该支持 arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64。当我这样做的时候,效果很好。
      【解决方案6】:

      在gradle中,将所有文件夹复制到libs/

      jniLibs.srcDirs = ['libs']
      

      将上述行添加到build.gradle 文件中的sourceSets 有效。没有其他任何工作。

      【讨论】:

      • “sourceSets”是否位于 build.gradle 文件中?
      • @Ashana.Jackol 在你的 build.gradle 中
      【解决方案7】:

      作为参考,我收到了这条错误消息,解决方案是,当您指定库时,您错过了前面的“lib”和末尾的“.so”。

      所以,如果你有一个文件 libmyfablib.so,你需要调用:

         System.loadLibrary("myfablib"); // this loads the file 'libmyfablib.so' 
      

      查看了apk,安装/卸载并尝试了各种复杂的解决方案,我看不到摆在我面前的简单问题!

      【讨论】:

      • 就是这样。由于某些未知原因,Android 不会安装文件名不以“lib”开头的库,即使它们存在于包中。去图...
      • 在项目中哪里可以查看?我的意思是在代码中哪里可以找到System.loadLibrary 这一行
      • 谢谢。这有帮助!
      • 哦。我的。上帝!我花了一整天的时间通过检查路径来解决它,但一切都很容易,非常感谢!
      【解决方案8】:

      为了根本原因(也许同时解决您的问题),您可以这样做:

      1. 删除 jni 文件夹和所有 .mk 文件。如果您不编译任何内容,则不需要这些,也不需要 NDK。

      2. 将您的 libcalculate.so 文件复制到 &lt;project&gt;/libs/(armeabi|armeabi-v7a|x86|...) 中。使用 Android Studio 时是&lt;project&gt;/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...),但我看到你使用的是 eclipse。

      3. 构建您的 APK 并将其打开为 zip 文件,以检查您的 libcalculate.so 文件是否在 lib/(armeabi|armeabi-v7a|x86|.. .).

      4. 删除并安装您的应用程序

      5. 运行 dumpsys 软件包 | grep yourpackagename 以获取您的应用程序的 nativeLibraryPathlegacyNativeLibraryDir

      6. 在您拥有的 nativeLibraryPathlegacyNativeLibraryDir/armeabi 上运行 ls,以检查您的 libcalculate.so 是否确实存在.

      7. 如果存在,请检查它是否未从您的原始 libcalculate.so 文件中更改:它是否针对正确的体系结构编译,是否包含预期的符号,是否存在任何缺少的依赖项。您可以使用 readelf 分析 libcalculate.so。

      为了检查步骤 5-7,您可以使用我的应用程序而不是命令行和 readelf:Native Libs Monitor

      PS: 很容易混淆.so文件应该放在哪里或者默认生成,这里是一个总结:

      • libs/CPU_ABI 在 Eclipse 项目中

      • jniLibs/CPU_ABI 在 Android Studio 项目中

      • jni/CPU_ABI 在 AAR 中

      • lib/CPU_ABI 在最终 APK 中

      • 在 nativeLibraryPath 内,在 >=5.0 设备上应用的 legacyNativeLibraryDir/CPU_ARCH 内。

        李>

      其中 CPU_ABI 是以下任一项:armeabi、armeabi-v7a、arm64-v8a、x86、x86_64、mips、mips64。取决于您所针对的架构以及您的库已针对哪些架构进行编译。

      另请注意,库不会在 CPU_ABI 目录之间混合:您需要您正在使用的完整集,armeabi 文件夹中的库不会安装在 armeabi-v7a 设备,如果在 APK 的 armeabi-v7a 文件夹中有任何库。

      【讨论】:

      • 好人,谢谢!我正在使用 Android Studio,我的 jni 版本被复制到 libs 而不是 jniLibs。
      • 关于需要全套的最后一条说明对我来说至关重要。那是我的问题,谢谢!
      • 对于7 部分:您的意思是.so 可能会在安装到设备上后从APK 中更改?如果是这样,系统是否有可能破坏 .so 文件?
      • 太棒了!在我非常奇怪的情况下,我使用的是第 3 方库集(OpenCV - 在 armeabi 文件夹中),当我通过 Gradle 添加不同的第 3 方库时,这些库停止加载。事实证明,第二个库不支持 ARMv5 或 6,并且通过包含它,我的 OpenCV 库变得不可见(尽管它们实际上存在)。你关于全套的观点给了我线索 - 重命名 armeabi 文件夹并将其命名为 armeabi-v7a 解决了问题(因为我现在不支持 ARM 5 或 6...)。邪恶的问题!!
      • 另一种查找 lib 文件 (*.so) 放置位置的方法是运行应用程序并使用以下命令打印 nativeLibraryDir:System.out.println(getApplicationContext().getApplicationInfo().nativeLibraryDir) ,目录的名称也会为您提供 ABI。
      【解决方案9】:

      实际上,您不能只将 .so 文件放入 /libs/armeabi/ 并使用 System.loadLibrary 加载它。您需要创建一个 Android.mk 文件并声明一个预构建模块,您将在其中指定您的 .so 文件作为源。

      为此,请将您的 .so 文件和 Android.mk 文件放在 jni 文件夹中。 你的 Android.mk 应该是这样的:

      LOCAL_PATH := $(call my-dir)
      
      include $(CLEAR_VARS)
      LOCAL_MODULE    := libcalculate
      LOCAL_SRC_FILES := libcalculate.so
      include $(PREBUILT_SHARED_LIBRARY)
      

      来源:Android NDK documentation about prebuilt

      【讨论】:

        【解决方案10】:

        在我的情况下,我必须排除通过 gradle 编译源并设置库路径

        android {
        
            ...
            sourceSets {
                ...
                main.jni.srcDirs = []
                main.jniLibs.srcDirs = ['libs']
            }
        ....
        

        【讨论】:

        • 这也为我解决了,我在 armeabi-v7a 和 x86 文件夹中添加了 armeabi 的文件,但我不确定是否有必要。
        【解决方案11】:

        根据我的经验,在 armeabi-v7a 手机中,当 apk 中同时存在 armeabi 和 armeabi-v7a 目录时,不会链接 armeabi 目录中的 .so 文件,尽管 armeabi 中的 .so 文件将如果 armeabi-v7a 不存在,则链接在同一个 armeabi-v7a 移动设备中。

        【讨论】:

          【解决方案12】:

          尝试在包含PREBUILT_SHARED_LIBRARY 部分之后调用您的库:

          LOCAL_PATH := $(call my-dir)
          
          include $(CLEAR_VARS)
          LOCAL_MODULE    := libcalculate
          LOCAL_SRC_FILES := <PATH>/libcalculate.so
          include $(PREBUILT_SHARED_LIBRARY)
          
          #...
          
          LOCAL_SHARED_LIBRARIES += libcalculate
          

          更新:

          如果你要在 Java 中使用这个库,你需要将它编译为共享库

          LOCAL_PATH := $(call my-dir)
          
          include $(CLEAR_VARS)
          LOCAL_MODULE    := libcalculate
          LOCAL_SRC_FILES := <PATH>/libcalculate.so
          include $(BUILD_SHARED_LIBRARY)
          

          您需要将库部署在/vendor/lib 目录中。

          【讨论】:

          • 仅在部分末尾。
          【解决方案13】:

          你在使用 gradle 吗?如果是这样,请将.so 文件放入&lt;project&gt;/src/main/jniLibs/armeabi/

          希望对你有帮助。

          【讨论】:

          • 不,我没有使用gradle,我使用的是eclipse+maven
          猜你喜欢
          • 1970-01-01
          • 2013-03-06
          • 1970-01-01
          • 1970-01-01
          • 2018-05-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多