我想使用来自另一个 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)
==== 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)
然后,在项目根目录下,我执行了ndk-build。之后,armeabi /和armeabi-v7a /目录由ndk-build生成(文件夹中有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"
答案 0 :(得分:150)
为了根本原因(也许可以在同一时间解决您的问题),您可以执行以下操作:
删除jni文件夹和所有 .mk 文件。如果你没有编译任何东西,你就不需要这些也不需要NDK。
将libcalculate.so
文件复制到<project>/libs/(armeabi|armeabi-v7a|x86|...)
内。在使用Android Studio时,它是<project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...)
,但我看到你正在使用eclipse。
构建您的APK并将其作为 zip文件打开,以检查您的libcalculate.so
文件是否在 lib /(armeabi | armeabi-v7a | x86 | ...)强>
删除并安装您的应用程序
运行 dumpsys包软件包| grep yourpackagename 以获取应用程序的 nativeLibraryPath 或 legacyNativeLibraryDir 。
在 nativeLibraryDir / armeabi 上的 nativeLibraryPath 上运行 ls ,检查你的libcalculate.so是否确实存在
如果有,请检查它是否已从原始 libcalculate.so 文件中更改:是否针对正确的体系结构进行了编译,是否包含预期的符号,是否有任何遗漏的依赖。您可以使用readelf分析libcalculate.so。
为了检查步骤5-7,您可以使用我的应用程序而不是命令行和readelf:Native Libs Monitor
PS:在默认情况下应该放置或生成.so文件的位置很容易混淆,这里有一个摘要:
libs / CPU_ABI
jniLibs / CPU_ABI
jni / CPU_ABI
lib / CPU_ABI
在&lt; 5.0设备上的应用 nativeLibraryPath 内,以及&gt;上应用的 legacyNativeLibraryDir / CPU_ARCH 内部= 5.0设备。
CPU_ABI 的任何一个: armeabi,armeabi-v7a,arm64-v8a,x86,x86_64,mips,mips64 。取决于您针对哪些体系结构以及编译的库。
另请注意,libs不会在CPU_ABI目录之间混合:您需要使用的全套内容, armeabi 文件夹中的lib将不会被安装如果APK中的 armeabi-v7a 文件夹中有任何库,则在 armeabi-v7a 设备上。
答案 1 :(得分:16)
在gradle中,将所有文件夹复制到libs/
jniLibs.srcDirs = ['libs']
将上述行添加到sourceSets
文件中的build.gradle
。没有其他任何工作。
答案 2 :(得分:12)
.so
文件放入<project>/src/main/jniLibs/armeabi/
我希望它有所帮助。
答案 3 :(得分:11)
在我的情况下,我必须通过gradle排除编译源并设置libs路径
android {
...
sourceSets {
...
main.jni.srcDirs = []
main.jniLibs.srcDirs = ['libs']
}
....
答案 4 :(得分:5)
出现此错误的原因是您的应用与您链接的本机库之间的ABI不匹配。换句话说,您的应用和public async Task<string> myFunction()
{
string back = "this is my code";
return back;
}
针对的是不同的ABI。
如果您使用最新的Android Studio模板创建应用,则可能定位.so
,但您的arm64-v8a
可能会定位.so
。
有两种方法可以解决这个问题:
armeabi-v7a
构建的旧版ABI。选择2很脏,但我想你可能更感兴趣:
更改您的应用.so
build.gradle
答案 5 :(得分:4)
尝试在加入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
目录中部署库。
答案 6 :(得分:4)
作为参考,我有这个错误消息,解决方案是当你指定库时,你会错过前面的'lib'和最后的'.so'。
因此,如果你有一个文件libmyfablib.so,你需要调用:
System.loadLibrary("myfablib"); // this loads the file 'libmyfablib.so'
看了apk,安装/卸载并尝试了各种复杂的解决方案后,我无法看到面前的简单问题!
答案 7 :(得分:4)
这是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
这种方法很有用,不适用于Android 8;来自https://developer.android.com/about/versions/oreo/android-8.0-changes.html 您将看到,作为“安全”更改的一部分,您现在需要使用sourceDir:
“您不能再认为APK位于名称以-1或-2结尾的目录中。应用程序应使用sourceDir获取目录,而不是直接依赖目录格式。”
更正,sourceDir不是查找本机共享库的方法;使用类似的东西。测试Android 4.4.4 - &gt; 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;
}
答案 8 :(得分:1)
您可以更改ABI以使用旧版本:
defaultConfig {
...
ndk {
abiFilters 'armeabi-v7a'
}
...
}
您还应该通过将以下行添加到gradle.properties
中来使用已弃用的NDK:
android.useDeprecatedNdk=true
答案 9 :(得分:0)
请添加所有支持
应用程序/的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
答案 10 :(得分:0)
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "x86", "armeabi", "mips"
}
}
只需将这些行添加到build.gradle应用程序级别
答案 11 :(得分:-1)
实际上,您不能只在/libs/armeabi/
中添加.so文件并使用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)
答案 12 :(得分:-1)
根据我的经验,在armeabi-v7a手机中,当apk中存在armeabi和armeabi-v7a目录时,armeabi目录中的.so文件不会被链接,尽管armeabi中的.so文件如果armeabi-v7a不存在,将链接在相同的armeabi-v7a手机中。