【问题标题】:Use external static library in application (NDK)在应用程序中使用外部静态库 (NDK)
【发布时间】:2013-12-22 06:25:45
【问题描述】:

我最近开始使用 NDK,但遇到了一个问题。我基本上想在我的应用程序中使用外部静态库(.so)。这是我到目前为止所尝试的。

创建库

1) 在Java类中用native关键字添加方法

public native static void FibNR ();

2) 在终端导航到项目文件夹并运行以下命令

    mkdir jni
    javah -jni -classpath bin/classes/ -d jni/ com.example.fibonaccinative.FibLib

3) 刷新工程,添加生成的H文件对应的C文件。

4)在JNI文件夹中创建一个Android.mk文件,在里面添加如下代码

LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    OPENCV_LIB_TYPE :=STATIC
    LOCAL_SRC_FILES := com_example_fibonaccinative_FibLib.c
    LOCAL_MODULE := com_example_fibonaccinative_FibLib
    include $(BUILD_SHARED_LIBRARY)

5) 使用以下命令构建代码

/Developer/android-ndk-r9b/ndk-build all

上述步骤成功执行,我还可以查看 c 代码的结果。现在我想创建一个新应用程序并将生成的 .so 文件 (com_example_fibonaccinative_FibLib.so) 用于其中。为此,我执行以下操作

使用库

按照上面的步骤 1、2 和 3 进行新应用程序

4)在JNI文件夹中创建一个Android.mk文件,在里面添加如下代码

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCV_LIB_TYPE :=STATIC
LOCAL_SRC_FILES := com_example_usingstaticlibrary_LibraryTest.c
LOCAL_MODULE := com_example_usingstaticlibrary_LibraryTest
LOCAL_SHARED_LIBRARIES :=libcom_example_fibonaccinative_FibLib.so
LOCAL_LDLIBS := -L$(SYSROOT)/usr -llog
include $(BUILD_SHARED_LIBRARY)

5) 使用以下命令构建代码

/Developer/android-ndk-r9b/ndk-build all

我不确定下一步该做什么。我认为我需要将库的函数调用到 com_example_usingstaticlibrary_LibraryTest.c 中。但是这样做会给我一个错误提示

'com_example_fibonaccinative_FibLib' 未声明



编辑 1:

1) 在项目 2 中(我想使用预建共享库 (.so))我将库复制到“jni”文件夹中

2) 使用以下文本更改了 Android.mk 文件。

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := libcom_example_fibonaccinative_FibLib
LOCAL_SRC_FILES := libcom_example_fibonaccinative_FibLib.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := com_example_usingstaticlibrary_LibraryTest
LOCAL_SHARED_LIBRARIES := libcom_example_fibonaccinative_FibLib
LOCAL_SRC_FILES := com_example_usingstaticlibrary_LibraryTest.c
include $(BUILD_SHARED_LIBRARY)

3) 将旧项目 (com_example_fibonaccinative_FibLib.h) 中的 .h 文件添加到“jni”文件夹中

4) 将 com_example_usingstaticlibrary_LibraryTest.c 的源代码更改为

#include "com_example_usingstaticlibrary_LibraryTest.h"
#include "com_example_fibonaccinative_FibLib.h"

JNIEXPORT jlong JNICALL Java_com_example_usingstaticlibrary_LibraryTest_callLibraryFunction
(JNIEnv *env, jclass class) {
    Java_com_example_fibonaccinative_FibLib_fibNR(env, class, 500l);
    return -500l;
}

清理/构建导致以下错误

undefined reference to 'Java_com_example_fibonaccinative_FibLib_fibNR'


编辑 2:

参考this我已经编辑了Android.mk如下

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := com_example_fibonaccinative_FibLib
LOCAL_SRC_FILES := libcom_example_fibonaccinative_FibLib.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := com_example_usingstaticlibrary_LibraryTest
LOCAL_SRC_FILES := com_example_usingstaticlibrary_LibraryTest.c
LOCAL_SHARED_LIBRARIES := com_example_fibonaccinative_FibLib
include $(BUILD_SHARED_LIBRARY)

NDK 构建命令编译代码没有错误。尝试加载库时出现以下错误

Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Lcom/example/usingstaticlibrary/LibraryTest

当我删除 LOCAL_SHARED_LIBRARIES := com_example_fibonaccinative_FibLib 时,它可以正常工作,但我无法使用 Prebuilt 共享库的任何功能。



编辑 3:

我尝试了更多的东西,包括@jcm 的建议,但没有任何效果。我现在附上source code。它有两个项目(清理版本以减小大小)。

  1. FibonacciNative:包含第一个项目。
  2. UsingStaticLibrary:包含第二个项目。我打算将第一个项目的预建共享库用于第二个项目。

【问题讨论】:

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


    【解决方案1】:

    你说你想包含一个预编译的静态库.a,但是你引用的文件是一个共享库.so。如果你仍然想包含一个静态库,这里有解决方案和解释:

    LOCAL_SHARED_LIBRARIES :=libcom_example_fibonaccinative_FibLib.so
    

    您正在尝试将 static 库作为共享库包含在内,这看起来像是使用上一个共享库条目作为参考的意外失误:)。

    在此之后,Android makefiles 仍然需要您实际为外部库创建一个模块。

    include $(CLEAR_VARS)
    LOCAL_MODULE    := com_example_fibonaccinative_FibLib
    LOCAL_SRC_FILES := com_example_fibonaccinative_FibLib.a
    include $(PREBUILT_STATIC_LIBRARY)
    

    然后你可以简单地将其添加为依赖项:

    LOCAL_STATIC_LIBRARIES := com_example_fibonaccinative_FibLib
    

    但是,如果您实际上是在尝试包含外部共享库。您需要将以上内容更改为以下内容:

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

    并将其作为共享库包含在内。

    LOCAL_SHARED_LIBRARIES := com_example_fibonaccinative_FibLib
    

    希望我能帮上忙!

    免责声明:我实际上并没有尝试编译示例,只是参考我的知识和快速研究。

    参考资料: Android NDK: Static library used is different than precompiled library specified

    【讨论】:

    • 感谢您的精彩解释。你帮助我理解了很多我之前忽略的基本知识。我已经用您解释的更改更新了帖子。你能看到“编辑1”并纠正我吗..
    • Java_com_kochartech_fibonaccinative_FibLib_fibNR 是项目 1 中作为原生函数创建的函数。
    • 如果您不想附加实际上属于库 (.so) 的头文件。您应该在 include $(PREBUILT_SHARED_LIBRARY) 之前添加 LOCAL_EXPORT_C_INCLUDES := com_kochartech_usingstaticlibrary_LibraryTest.h 。这将导致其他库(将模块作为依赖项)自动在其构建中包含头文件。
    • 您还应该阅读此answer,了解有关 .so 文件位置的更多详细信息。现在我想到了,这似乎是你错误的实际原因(有点仓促阅读)。祝你好运! JNI 的体验不是很愉快。
    • 我阅读了您在其他几个博客中指出的答案,但没有任何结果。请检查“编辑 2”
    【解决方案2】:

    由于您将 libcom_example_fibonaccinative_FibLib.so 作为 LibraryTest 的共享库,在您的 java 静态方法中,您应该在加载 LibraryTest 之前加载它:

    System.loadlibrary(com_example_fibonaccinative_FibLib);
    System.loadLibrary(LibraryTest);
    

    更新:

    检查您的代码后,LibraryTest.java 应如下所示:

    package com.kochartech.usingstaticlibrary;
    
    public class LibraryTest {
    
        public native static long callLibraryFunction();
    
        static {
            System.loadLibrary("com_kochartech_fibonaccinative_FibLib");
            System.loadLibrary("com_kochartech_usingstaticlibrary_LibraryTest");
        }
    
    }
    

    【讨论】:

    • @Sahil 我修改了我告诉你的内容,你的代码正在运行。请检查更新。
    猜你喜欢
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    • 2013-02-06
    • 1970-01-01
    • 2017-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多