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

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

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

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

当我运行我的新的android项目,我得到错误:

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

所以,如错误所述,复制的本地库不在/ verdor / lib或/系统/ lib,如何解决这个问题在我的情况?

(我unziped的apk包,下lib /有libcalculate.so)

==== UPDATE =====

我也尝试在项目根目录下创build一个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。 之后,armeabi /和armeabi-v7a /目录由ndk-build(在libcalculate.so文件夹内)生成。

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

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

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

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

为了根源(也许在同一时间解决你的问题),你可以做的是:

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

  2. <project>/libs/(armeabi|armeabi-v7a|x86|...)复制libcalculate.so文件。 当使用Android Studio时,它是<project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...) ,但是我看到你正在使用eclipse。

  3. 构buildAPK并将其作为zip文件打开,以检查libcalculate.so文件是否位于lib /(armeabi | armeabi-v7a | x86 | …)内部

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

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

  6. 在您有的legacyLibraryPathlegacyNativeLibraryDir / 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

  • JAR / CPU_ABI在一个AAR里面

  • lib / CPU_ABI在最后的APK里面

  • 在<5.0设备上应用程序的nativeLibraryPath中 ,在> = 5.0设备上的应用程序的legacyNativeLibraryDir / CPU_ARCH中

其中CPU_ABIarmeabi,armeabi-v7a,arm64-v8a,x86,x86_64,mips,mips64中的任何一个 。 取决于你所针对的架构和你的库已被编译。

还要注意的是,libs不会在CPU_ABI目录之间混合使用:如果armeabi中有任何libs,则需要完整的armeabi文件夹内的lib将不会安装在armeabi-v7a设备上APK中的-v7a文件夹。

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

 jniLibs.srcDirs = ['libs'] 

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

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

我希望它有帮助。

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

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

尝试在包含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目录下部署这个库。

作为参考,我有这个错误消息,解决scheme是,当你指定库时,你会错过前面的'lib'和最后的'.so'。

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

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

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

请添加所有的suport

应用程序/的build.gradle

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

应用程序的\ src \ JNI \ Application.mk

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

这是一个Android 8更新。

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

 /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来获取目录,而不是直接依赖目录格式。

根据我的经验,在armeabi-v7a手机中,当armeabi和armeabi-v7a目录出现在apk中时,armeabi目录下的.so文件将不会被链接,尽pipearmeabi中的.so文件将被链接到相同的armeabi-v7a手机,如果armeabi-v7a不存在。

实际上,您不能只将.so文件放在/libs/armeabi/ ,并使用System.loadLibrary加载。 您需要创build一个Android.mk文件,并声明一个预先构build的模块,在其中指定.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文档