在我的情况下,System.loadLibrary(...)找不到本机库

use*_*225 80 android android-ndk

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

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

  static{
    System.loadLibrary("calculate");
  }
Run Code Online (Sandbox Code Playgroud)

当我运行我的新Android项目时,我收到错误:

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
Run Code Online (Sandbox Code Playgroud)

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

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

==== UPDATE =====

我还尝试在项目根目录下创建一个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)
Run Code Online (Sandbox Code Playgroud)

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

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

lib/armeabi/libcalculate.so
lib/armeabi-v7a/libcalculate.so
Run Code Online (Sandbox Code Playgroud)

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

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
Run Code Online (Sandbox Code Playgroud)

ph0*_*h0b 156

为了根本原因(也许可以在同一时间解决您的问题),您可以执行以下操作:

  1. 删除jni文件夹和所有.mk文件.如果你没有编译任何东西,你不需要这些也不需要NDK.

  2. 复制你的libcalculate.so文件<project>/libs/(armeabi|armeabi-v7a|x86|...).当使用Android Studio时,它是<project>/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文件的位置感到困惑,这里有一个摘要:

  • eclipse项目中的libs/CPU_ABI

  • Android Studio项目中的jniLibs/CPU_ABI

  • AAR中的jni/CPU_ABI

  • 最终APK内的lib/CPU_ABI

  • 在<5.0设备上的应用程序的nativeLibraryPath内部,以及在= = 5.0设备上的应用程序的legacyNativeLibraryDir/CPU_ARCH内部.

其中CPU_ABI是以下任何一个:armeabi,armeabi-v7a,arm64-v8a,x86,x86_64,mips,mips64.取决于您所针对的架构和已编译的库.

还要注意的lib未混合CPU_ABI目录之间:你所需要的全套你使用的是什么的,一个lib是内部 armeabi文件夹将不被一个安装armeabi-V7A设备,如果有内部的任何库armeabi来自APK的-v7a文件夹.

  • 精彩!在我非常奇怪的情况下,我使用第三方库(OpenCV - 在**armeabi**文件夹中),当我通过Gradle添加不同的第三方库时,这些库停止加载.事实证明,第二个库不支持ARMv5或6,并且通过包含它,我的OpenCV库变得不可见(尽管它们实际上是_).关于完整集的观点给了我线索 - 重命名armeabi文件夹并调用它**armeabi-v7a**解决了问题(因为我现在不支持ARM 5或6 ......).邪恶的问题!! (5认同)
  • 关于需要全套的最后一点说明对我来说至关重要.那是我的问题,谢谢! (4认同)
  • 太棒了,谢谢!我正在使用Android Studio,我的jni构建被复制到lib而不是jniLibs. (3认同)
  • 找到放置 lib 文件 (*.so) 的位置的另一种方法是运行您的应用程序并使用以下命令打印 nativeLibraryDir:System.out.println(getApplicationContext().getApplicationInfo().nativeLibraryDir),该目录的名称也将为您提供 ABI。 (2认同)

小智 18

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

jniLibs.srcDirs = ['libs']
Run Code Online (Sandbox Code Playgroud)

添加上述行来sourceSetsbuild.gradle文件中工作.没有其他任何工作.

  • 在build.gradle文件中的“ sourceSets”是什么? (2认同)

Ass*_*iel 12

你在使用gradle吗?如果是这样,把.so文件放入<project>/src/main/jniLibs/armeabi/

我希望它有所帮助.


Daw*_*ozd 12

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

android {

    ...
    sourceSets {
        ...
        main.jni.srcDirs = []
        main.jniLibs.srcDirs = ['libs']
    }
....
Run Code Online (Sandbox Code Playgroud)


And*_*wel 8

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

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

   System.loadLibrary("myfablib"); // this loads the file 'libmyfablib.so' 
Run Code Online (Sandbox Code Playgroud)

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


Alg*_*ter 8

这是 Android 8 更新。

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

/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
Run Code Online (Sandbox Code Playgroud)

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

“你不能再假设 APK 位于名称以 -1 或 -2 结尾的目录中。应用程序应该使用 sourceDir 来获取目录,而不是直接依赖目录格式。”

更正, sourceDir 不是查找本机共享库的方法;使用类似的东西。测试 Android 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;
}
Run Code Online (Sandbox Code Playgroud)


wda*_*xna 6

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

如果您使用最新的Android Studio模板创建应用,则可能会针对您的应用,arm64-v8a但您的.so目标可能armeabi-v7a就是.

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

  1. 为您的应用支持的每个ABI构建您的本机库.
  2. 将您的应用更改为针对您.so构建的旧ABI .

选择2很脏,但我想你可能更感兴趣:

改变你的应用程序 build.gradle

android {
    defaultConfig {
        ...
        ndk {
            abiFilters 'armeabi-v7a'
        }
   }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*lex 5

尝试在包含部分后调用您的库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
Run Code Online (Sandbox Code Playgroud)

更新:

如果您将在 Java 中使用此库,则需要将其编译为共享库

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := libcalculate
LOCAL_SRC_FILES := <PATH>/libcalculate.so
include $(BUILD_SHARED_LIBRARY)
Run Code Online (Sandbox Code Playgroud)

并且您需要将库部署到/vendor/lib目录中。