在应用程序中使用外部静态库(NDK)

时间:2013-12-05 10:45:53

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

我最近开始使用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'undeclared



编辑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)将旧项目中的.h文件(com_example_fibonaccinative_FibLib.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。它有两个项目(Cleaned version to reduce size)。

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

2 个答案:

答案 0 :(得分:4)

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

LOCAL_SHARED_LIBRARIES :=libcom_example_fibonaccinative_FibLib.so

您尝试将静态库作为共享库包含在内,看起来像是使用以前的共享库条目作为参考的偶然漏洞:)。

在此之后,Android makefile仍然要求您实际为外部库创建模块。

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 :(得分:1)

当您将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");
    }

}