android ndk 动态库_百度经验,Android的NDK编译的动态库中调用第三方动态库

使用NDK直接把C/C++代码编译成动态库很简单,主要就是要把NDK配置好,以及写Android.mk文件,网上搜一下有很多教程。现在要实现在NDK编译出来的动态库中还要调用别的第三方动态库,就不知道该怎么做了。后来网上搜了很多,发现遇到跟我一样问题的人很多,但是并没有找到解决方法,帖子内容都是千篇一律,copy来copy去,根本没有可用的内容。后来在stackoverflow的网站上找到了解决办法,发现其实很简单。

先明确一下需求和遇到的问题。在我的Android项目中,要用到一个动态库test2.so,而在test2的实现部分,又需要调用到test1.so的接口。最初我是直接在test2的Android.mk文件中添加了这样一行代码:

...

LOCAL_SHARED_LIBRARY := libtest1.so

...这样编译没有问题,但是在Android工程中调用test2.so的时候就会抛出UnsatisfiedLinkError:

'06-1722:35:28.741:INFO/dalvikvm(298):Unableto dlopen(/data/data/com.foo/lib/libndkfoo.so):Cannotload library:link_image[1721]:29could not load needed library'libtest1.so 后来知道,是不能这样直接调用第三方动态库的,而是要通过预编译模块来调用。

首先声明,libtest1.so也许是别人提供给你的现成的动态库,你只需要拿来调用。但是在调用之前,你必须保证两点:

1. 别人编译这个第三方动态库时使用的编译器必须与你使用的NDK编译器一样。比如我在编译test2.so时使用的是android-ndk-r9/toolchains/arm-linux-androideabi-4.6,那边编译test1.so的编译器必须也是这个。

2. 在Android工程中要使用到的所有动态库的目标系统的ABI必须要一致。至于什么是目标系统ABI请自行百度。也就是说,不管在编译test1.so的Android.mk文件中,还是在编译test2.so时所要使用到的Android.mk文件中,以及这些文件的每一个module中,都要出现这样一句话:

TARGET_ARCH_ABI := armeabi-v7a如果这两点无法同时保证的话,那么你的test1.so和test2.so是无法编译通过的,在NDK进行编译的时候会提示你:

arm-linux-androideabi-strip: Unable to recognise the format of the input files

在以上两点得到保证之后,开始我们调用动态库的流程。

首先实现简单的test1.h和test1.cpp,因为只是测试用,简单实现即可,我的测试代码如下:

test1.h:

#ifndef TEST1

#define TEST1

#include

#include

using namespace std;

class Test1

{

public:

Test1();

~Test1();

};

#endiftest1.cpp:

#include "test1.h"

#include

Test1::Test1()

{

__android_log_print(ANDROID_LOG_INFO, "WTT", "------Print---------I'm Test1----------------");

}

Test1::~Test1()

{

}这两个文件完成以后,开始写test1的Android.mk文件:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := test1

LOCAL_SRC_FILES := test1.cpp

LOCAL_LDLIBS +=-L$(SYSROOT)/usr/lib -llog -lz

LOCAL_ALLOW_UNDEFINED_SYMBOLS := true

LOCAL_CPP_EXTENSION += .cpp

TARGET_ARCH_ABI := armeabi-v7a

include $(BUILD_SHARED_LIBRARY)Application.mk文件:

APP_STL := gnustl_static

APP_ABI := armeabi-v7a

APP_CPPFLAGS += -fexceptions

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

文件结构如上,以上4个文件全都做好之后,在终端里面执行NDK编译(前提是你的NDK编译器已经配置好):

wtt@ubuntu:~/workspace/test1/jni$  $NDK/ndk-build 执行完之后就会在目标文件夹中自动得到一个libtest1.so文件。

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

接着,我们要在test2中调用这个libtest1.so中的接口。首先实现代码部分很简单,直接调用:

test2.h

#ifndef TEST2

#define TEST2

#include

#include

using namespace std;

class Test2

{

public:

Test2();

~Test2();

};

#endiftest2.cpp

#include "test1.h"

#include "test2.h"

#include

Test2::Test2()

{

__android_log_print(ANDROID_LOG_INFO, "WTT", "------Print---------I'm Test2----------------");

Test1 *test1 = new Test1;

__android_log_print(ANDROID_LOG_INFO, "WTT", "------Print---------I'm Test2----------------");

}

Test2::~Test2()

{

}

下面是最关键的,在test2的Android.mk文件中,必须将我们所需要调用到的所有动态库声明为预编译库,且每个预编译库必须声明为独立的module。

具体做法如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := Test1

LOCAL_SRC_FILES := libtest1.so

TARGET_ARCH_ABI := armeabi-v7a

include $(PREBUILT_SHARED_LIBRARY)这里是把libtest1.so声明为一个PREBUILT_SHARED_LIBRARY,也就是预编译库。然后直接在test2的module中引用这个与编译库

include $(CLEAR_VARS)

LOCAL_MODULE := test2

LOCAL_SRC_FILES := test2.cpp

LOCAL_LDLIBS +=-L$(SYSROOT)/usr/lib -llog -lz

LOCAL_ALLOW_UNDEFINED_SYMBOLS := true

LOCAL_SHARED_LIBRARIES := Test1

LOCAL_CPP_EXTENSION += .cpp

TARGET_ARCH_ABI := armeabi-v7a

include $(BUILD_SHARED_LIBRARY)

test2的Application.mk文件与test1一致即可,没有特别要求。做完这些之后,要同时把test1的.so文件和头文件放在本目录下,最终的目录结构如下:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

接着执行$NDK/ndk-build

就会在目标目录下生成两个库文件:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

至此,我们就实现了在动态库中调用第三方动态库。

要想在Android工程中调用到NDK动态库,还需要做一系列的工作,具体做法可以百度或者谷歌,这部分内容不在我们今天讨论的问题之内。

实现之后把Android程序跑起来,可以在logcat中看到这样的输出信息:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

说明我们成功调用到动态库的接口。

参考文献:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值