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"
为了根源(也许在同一时间解决你的问题),你可以做的是:
-
删除jni文件夹和所有的.mk文件。 如果你没有编译任何东西,你不需要这些,也不需要NDK。
-
在
<project>/libs/(armeabi|armeabi-v7a|x86|...)
复制libcalculate.so
文件。 当使用Android Studio时,它是<project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...)
,但是我看到你正在使用eclipse。 -
构buildAPK并将其作为zip文件打开,以检查
libcalculate.so
文件是否位于lib /(armeabi | armeabi-v7a | x86 | …)内部 。 -
删除并安装您的应用程序
-
运行dumpsys软件包包 grep yourpackagename以获取应用程序的nativeLibraryPath或legacyNativeLibraryDir 。
-
在您有的legacyLibraryPath或legacyNativeLibraryDir / armeabi上运行ls ,检查libcalculate.so是否确实存在。
-
如果它在那里,检查它是否没有从原来的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_ABI是armeabi,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文档