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


90

我想使用另一个 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)

====更新=====

我还尝试在项目根目录下创建一个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。此后,ndk-build生成armeabi /和armeabi-v7a /目录(文件夹中有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"

3
您将图书馆直接放在下面libs/?您可能需要为每个要支持的目标ABI创建一个子目录(armeabi,armeabi-v7a,x86,mips等),并将适当的.so文件放置在每个子目录中(即,为armeabi构建的.so文件进入了libs/armeabi/,等等)。
迈克尔

@Michael,我只是想念在我的帖子中,实际上把它放在libs / armeabi /下
user842225 2014年

检查libcalculate.so是否确实在打包过程中被拾取了-尝试使用例如unzip -l package.apk,或将apk重命名为.zip并使用某些应用程序将其打开。如果不存在,则打包时出了点问题(您的IDE是否注意到文件夹在那里,是否需要刷新项目?)。
mstorsjo 2014年

@mstorsjo,我解压缩了apk包,在lib /下有libcalculate.so
user842225 2014年

1
您不需要Android.mk或任何与编译相关的文件。只要把这样的文件在其根据子目录喜欢这里jniLibs:github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/...
保罗Woitaschek

Answers:


173

要找出原因(并可能同时解决问题),可以执行以下操作:

  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

  • lib / CPU_ABI内部最终的APK

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

其中CPU_ABI是以下任意一项:armeabi,armeabi-v7a,arm64-v8a,x86,x86_64,mips,mips64。根据您要针对的体系结构以及您的库进行编译而定。

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


3
太棒了,谢谢!我正在使用Android Studio,并且我的jni版本已复制到libs而不是jniLibs。
2014年

4
关于需要全套的最后说明对我来说至关重要。那是我的问题,谢谢!
本·特伦格罗夫

对于本7节:您是说.so在安装到设备上后可能会从APK中更改吗?如果是这样,系统是否有可能破坏.so文件?
jayatubi

5
精彩!在我非常奇怪的情况下,我使用的是第三方库集(OpenCV-armeabi文件夹中),当我通过Gradle添加另一个第三方库时,这些库停止加载。事实证明,第二个库不支持ARMv5或6,并且通过包含第二个库,我的OpenCV库变得不可见(尽管它们实际上在那)。关于全套的观点为我提供了线索-重命名armeabi文件夹并将其命名为armeabi -v7a解决了该问题(因为我现在不支持ARM 5或6 ...)。邪恶的问题!
2015年

1
查找将lib文件(* .so)放在哪里的另一种方法是运行应用程序并使用以下命令打印nativeLibraryDir:System.out.println(getApplicationContext()。getApplicationInfo()。nativeLibraryDir),目录名称也将为您提供ABI。
David Rauca

19

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

jniLibs.srcDirs = ['libs']

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


2
在build.gradle文件中的“ sourceSets”是什么?
Ashana.Jackol '16


12

就我而言,我必须排除通过gradle编译源并设置libs path

android {

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

这也为我解决了问题,我在armeabi-v7a和x86文件夹中添加了armeabi的文件,但是我不确定是否有必要。
dokam_scotland

8

发生此错误的原因是,您的应用程序和链接到的本机库之间的ABI不匹配。换句话说,您的应用和您.so的目标是不同的ABI。

如果您使用最新的Android Studio模板创建应用,则该应用可能定位到,arm64-v8a但您.so可能定位armeabi-v7a了例如。

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

  1. 为您的应用支持的每个ABI构建本地库。
  2. 更改您的应用程序以定位您.so针对其构建的较旧的ABI 。

选择2很脏,但我认为您可能对以下内容更感兴趣:

更改您应用的 build.gradle

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

如果我的应用在日食中该怎么办?这个问题来了,当我同一个定制的应用程序迁移从6到9

6

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

因此,如果您有一个文件libmyfablib.so,则需要调用:

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

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


就是这样 由于某些未知原因,Android不会安装文件名不是以“ lib”开头的库,即使它们存在于软件包中也是如此。走吧...
George Y.

我在哪里可以在项目中检查?我的意思是我System.loadLibrary在代码中哪里可以找到这行
aleksandrbel,

谢谢。这有帮助!
Riskhan

5

这是Android 8更新。

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

/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-> 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;
}

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目录中部署库。


仅在本节末尾。
Alex

2

您可以更改ABI以使用旧版本:

defaultConfig {
    ...

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

您还应该通过将以下行添加到来使用已弃用的NDK gradle.properties

android.useDeprecatedNdk=true

0

请添加所有支持

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

1
您能更具体地做什么吗?
EFrank

您项目中的.so文件。您应该支持arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64。当我这样做时,它运作良好。
Lion耿

-1

以我的经验,在armeabi-v7a移动版中,当apk中同时存在armeabi和armeabi-v7a目录时,armeabi目录中的.so文件将不会链接,尽管armeabi中的.so文件将在如果不存在armeabi-v7a,则使用相同的armeabi-v7a移动版。


-1

实际上,您不能只将.so文件放入中/libs/armeabi/并用加载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)

来源:有关预建的Android NDK文档

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.