在我的例子中,System.loadLibrary (...)找不到本机库

我想使用一个现有的本地库从 另一个 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/there is libCalculate.so 下)

= = = = UPDATE = = = = =

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

LOCAL_PATH := $(call my-dir)


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

然后,在项目 root 下执行 ndk-build。然后,由 ndk-build 生成 armeabi/和 armeabi-v7a/目录(在文件夹中包含 libCalculate.so)。

然后,我成功地运行了我的 maven 构建项目:

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

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

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

actually, you can't just put a .so file in the /libs/armeabi/ and load it with System.loadLibrary. You need to create an Android.mk file and declare a prebuilt module where you specify your .so file as a source.

To do so, put your .so file and the Android.mk file in the jni folder. Your Android.mk should look something like that:

LOCAL_PATH := $(call my-dir)


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

Source : Android NDK documentation about prebuilt

Try to call your library after include PREBUILT_SHARED_LIBRARY section:

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

Update:

If you will use this library in Java you need compile it as shared library

LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)
LOCAL_MODULE    := libcalculate
LOCAL_SRC_FILES := <PATH>/libcalculate.so
include $(BUILD_SHARED_LIBRARY)

And you need deploy the library in the /vendor/lib directory.

Are you using gradle? If so put the .so file in <project>/src/main/jniLibs/armeabi/

I hope it helps.

To root cause (and maybe solve your issue in the same time), here is what you can do:

  1. Remove the jni folder and all the .mk files. You don't need these nor the NDK if you aren't compiling anything.

  2. Copy your libcalculate.so file inside <project>/libs/(armeabi|armeabi-v7a|x86|...) . When using Android Studio, it's <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...), but I see you're using eclipse.

  3. Build your APK and open it as a zip file, to check that your libcalculate.so file is inside lib/(armeabi|armeabi-v7a|x86|...).

  4. Remove and install your application

  5. Run dumpsys package packages | grep yourpackagename to get the nativeLibraryPath or legacyNativeLibraryDir of your application.

  6. Run ls on the nativeLibraryPath you had or on legacyNativeLibraryDir/armeabi, to check if your libcalculate.so is indeed there.

  7. If it's there, check if it hasn't been altered from your original libcalculate.so file: is it compiled against the right architecture, does it contain the expected symbols, are there any missing dependencies. You can analyze libcalculate.so using readelf.

In order to check step 5-7, you can use my application instead of command lines and readelf: Native Libs Monitor

PS: It's easy to get confused on where .so files should be put or generated by default, here is a summary:

  • libs/CPU_ABI inside an eclipse project

  • jniLibs/CPU_ABI inside an Android Studio project

  • jni/CPU_ABI inside an AAR

  • lib/CPU_ABI inside the final APK

  • inside the app's nativeLibraryPath on a <5.0 device, and inside the app's legacyNativeLibraryDir/CPU_ARCH on a >=5.0 device.

Where CPU_ABI is any of: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64. Depending on which architectures you're targeting and your libs have been compiled for.

Note also that libs aren't mixed between CPU_ABI directories: you need the full set of what you're using, a lib that is inside the armeabi folder will not be installed on a armeabi-v7a device if there are any libs inside the armeabi-v7a folder from the APK.

In gradle, after copying all files folders to libs/

jniLibs.srcDirs = ['libs']

Adding the above line to sourceSets in build.gradle file worked. Nothing else worked whatsoever.

In my experience, in an armeabi-v7a mobile, when both armeabi and armeabi-v7a directories are present in the apk, the .so files in armeabi directory won't be linked, although the .so files in armeabi WILL be linked in the same armeabi-v7a mobile, if armeabi-v7a is not present.

In my case i must exclude compiling sources by gradle and set libs path

android {


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

For reference, I had this error message and the solution was that when you specify the library you miss the 'lib' off the front and the '.so' from the end.

So, if you have a file libmyfablib.so, you need to call:

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

Having looked in the apk, installed/uninstalled and tried all kinds of complex solutions I couldn't see the simple problem that was right in front of my face!

please add all suport

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

This is an Android 8 update.

In earlier version of Android, to LoadLibrary native shared libraries (for access via JNI for example) I hard-wired my native code to iterate through a range of potential directory paths for the lib folder, based on the various apk installation/upgrade algorithms:

/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

This approach is hokey and will not work for Android 8; from https://developer.android.com/about/versions/oreo/android-8.0-changes.html you'll see that as part of their "Security" changes you now need to use sourceDir:

"You can no longer assume that APKs reside in directories whose names end in -1 or -2. Apps should use sourceDir to get the directory, and not rely on the directory format directly."

Correction, sourceDir is not the way to find your native shared libraries; use something like. Tested for 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;
}

The reason for this error is because there is a mismatch of the ABI between your app and the native library you linked against. Another words, your app and your .so is targeting different ABI.

if you create your app using latest Android Studio templates, its probably targeting the arm64-v8a but your .so may be targeting armeabi-v7a for example.

There is 2 way to solve this problem:

  1. build your native libraries for each ABI your app support.
  2. change your app to target older ABI that your .so built against.

Choice 2 is dirty but I think you probably have more interested in:

change your app's build.gradle

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

You could just change ABI to use older builds:

defaultConfig {
...


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

You should also use deprecated NDK by adding this line to gradle.properties:

android.useDeprecatedNdk=true
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "x86", "armeabi", "mips"
}
}

Just add these line in build.gradle app level