【问题标题】:Android NDK - Error Linking Shared library and JNI WrapperAndroid NDK - 链接共享库和 JNI Wrapper 时出错
【发布时间】:2019-01-31 20:17:51
【问题描述】:

我正在尝试在不同的构建机器上链接我使用 NDK-Standalone 工具链生成的共享库。然后使用那个特定的 .so 我把它放在 Android Studio 上。从那里我使用 javah 创建了一个jni.h 文件,然后帮助我为函数调用编写了.c JNI。

按照这个例子How do I compile any native (C, C++) library using NDK in the form of shared libraries

ndk-build 确实可以编译并且似乎可以正常工作,但是尝试在手机上运行应用程序时出现错误

static { 
    System.loadLibrary("testLib")
}

说找不到testLib.so,即使它是生成的并且在libs/armeabi-v7a/testLib.so目录中

当前错误:

 01-31 14:41:53.779 19024-19024/com.jolopy.testing_02 E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.jolopy.testing_02, PID: 19024
        java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.jolopy.testing_02-2/base.apk"],nativeLibraryDirectories=[/data/app/com.jolopy.testing_02-2/lib/arm64, /vendor/lib64, /system/lib64]]] couldn't find "testLib.so"
            at java.lang.Runtime.loadLibrary(Runtime.java:367)
            at java.lang.System.loadLibrary(System.java:1076)
            at com.jolopy.testing_02.TestLib.<clinit>(TestLib.java:6)
            at com.jolopy.testing_02.MainActivity.onCreate(MainActivity.java:18)

我是如何构建.so 文件的:

arm-linux-androideabi-gcc -c -fPIC testLib.c -o test.o

arm-linux-androideabi-gcc test.o -o testing.so

从那里我使用javah 编写了一个JNI 包装类,它生成了testing_Android.h 文件。从那里生成了 testing_Android.c JNI 包装器,我用它来调用我的 testLib.c 库中的函数:

#include "testLib.h"
//Including Machine Generated Header
#include "testing_Android.h"
#include <stdio.h>

JNIEXPORT void JNICALL Java_com_jolopy_testing_102_TestLib_testinglib_1Initialize
  (JNIEnv *env, jobject obj){
    (void)env;
    (void)obj;

    testing_Initialize();
}


JNIEXPORT jint JNICALL Java_com_jolopy_testing_102_TestLib_testinglib_1Get_1Count
  (JNIEnv *env, jobject obj){
    (void)env;
    (void)obj;

    return(testing_Get_Count());
}


JNIEXPORT jint JNICALL Java_com_jolopy_testing_102_TestLib_testinglib_1Get_1CurrentName
  (JNIEnv *env, jobject obj, jlong ptr, jint x){
    (void)env;
    (void)obj;

    return (testing_Get_CurrentName((char *)ptr , (int)x));

}

从那里我在 Android 的 jni 文件夹中有 5 个文件,这是我运行 ndk-build 命令的位置:

 testing.so | testing_Android.h | testing_Android.c | Application.mk | Android.mk

Android.mk:

LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := testLib
LOCAL_SRC_FILES := testing.so
LOCAL_EXPORT_C_INCLUDES := testing_Android.c
include $(PREBUILT_SHARED_LIBRARY)

Application.mk:

APP_PLATFORM := android-19
APP_ABI := armeabi-v7a

您可能会看到我看不到的任何建议或错误,我们将不胜感激。

-干杯!

【问题讨论】:

  • 您的应用在 64 位设备上运行,并且它有一些其他(最有可能是第三方库)具有 64 位版本的本机组件。直到最近,最佳实践还是从 APK 中删除所有 64 位二进制文​​件。如今,Google 要求 PlayStore 中的所有应用程序都支持本机 64 位。因此,解决方法是在 armeabi-v7aarm64-v8a 两种风格中构建和打包您的 libtestlib.so
  • 我猜你修改了实际的文件名,因为 lib 前缀对于 Android 正确打包和安装你的应用程序至关重要。
  • @AlexCohn 这是问题之一,但最终让我得到了正确的答案!

标签: android c android-ndk java-native-interface


【解决方案1】:

下面改

APP_ABI := armeabi-v7a 

APP_ABI := arm64-v8a

因为根据您的错误日志,您的设备是 arm64 ABI。


如果你正在开始一个新的 Android NDK 项目,我建议你从 Android Studio + CMake 工具链开始,这里是我个人基于 Android Studio 和 CMake 的 JniExample 项目:

【讨论】:

  • 可能,特别是如果应用程序应该在 API 19 上运行,Application.mk 中的 APP_ABI 应该同时列出 APP_ABI := armeabi-v7a arm64-v8a
  • @shizhen | @Alex Cohn 当我第一次开始这个项目时,我记得使用 Android.mk + Application.mk 这就是我坚持使用它而不是 cmake 的原因。至于那个变化仍然没有,我回顾了我的目录,似乎 ndk-build 只是在 libs 中创建 arm64-v8a .so 文件。即使 APP_ABI := all 。以及为什么它只会创建 arm64-v8a 而没有其他的原因?这可能是因为我形成初始库的方式吗?
  • [arm64-v8a] 预构建:testing.so libs/arm64-v8a/testing.so [x86_64] 预构建:测试。所以 libs/x86_64/testing.so /home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux -android-strip:无法识别输入文件/home/user/Desktop/Testing_02/app/libs/x86_64/testing.so' make: *** [/home/user/Desktop/Testing_02/app/libs/x86_64/testing.so] Error 1 make: *** Deleting file /home/user/Desktop/Testing_02/app/libs/x86_64/testing.so'的格式
【解决方案2】:

我没有使用 ndk 独立工具链,而是在我的构建机器上使用了 ndk-build,然后生成了我需要的 libs 文件。从那里我添加了包含以下内容的 libs 文件:

  1. arm64-v8a
  2. armeabi-v7a
  3. x86
  4. x86_64

进入我的 src>main>jniLibs 下的 Android 目录,然后存储所有文件并将命令添加到我的应用程序 build.gradle:

sourceSets.main{
        jniLibs.srcDir 'src/main/jniLibs'
    }

为了让 ndk-build 正常工作,我必须包含 jniWrapper.c 文件。

Android.mk:

LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := testing
LOCAL_SRC_FILES := jniWrapper.c \
                    testLib.c
include $(BUILD_SHARED_LIBRARY)

Application.mk(我用“all”进行测试,但不需要):

APP_PLATFORM := android-23
APP_ABI := all

我知道这是一种变通解决方案,但由于某种原因,我无法确定工具链是否正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-27
    相关资源
    最近更新 更多