Android平台下JNI调用第三方so库
转载:http://www.2cto.com/kf/201608/535654.html
在研究了几天JNI后,在自己生成的so库中调用第三方so库时遇到问题,解决之后特意整理、记录一下。
首先说一下在网上查找资料时,对于调用第三方so库,有人说有两种方法:
1. 对于so库的API符合JNI格式(即使用javah指令生成的头文件中那种格式),可以在java代码中声明它对应的native方法,直接调 用。
比如,jni方法名为:jstringJNICALLJava_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv *,jobject); (即前缀 Java+包名+类名+方法名)
那么这个方法名就是在java中声明的native方法名:publicnative String stringFromJNI();
2. 对于so库的API不符合JNI格式,需要自己编写c/c++源文件,在该源文件实现自己的JNI格式native函数,在JNI函数中调用第三方so库的函数,再在java中调用自己实现的JNI格式的native方法。这种方法更加灵活。
一、下图是我的项目JniDemo目录:
导入的两个第三方库是:libhello.so、libhello-jni.so
自己从源文件myhello.c编译生成的库是:libmyhello.so
java中调用native方法代码如下:
布局就一个TextView 组件 ,不再介绍。
二、源文件的编写
在使用javah生成头文件后,要在源文件中使用include“xxxx.h”引入头文件。如果头文件不在jni根目录下,还要在Android.mk中使用
LOCAL_C_INCLUDES:=(相对于jni目录的)包含头文件的目录路径
来声明一下,否则报错找不到头文件。
然后实现自己声明的native方法,再在其中调用第三方库的函数。
具体代码如下:
三、Android.mk,Application.mk配置
Android.mk用来配置各个模块如何编译,如下:
Application.mk用来配置目标编译ABI(应用二进制接口),如arm64-v8a、armeabi、armeabi-v7a、mips、mips64、x86、x86_64。
以armeabi-v7a为例,如下:
1
|
APP_ABI := armeabi-v7a #表示 编译目标 ABI(应用二进制接口)
|
四、在终端使用NDK编译jni目录
如果看到所有库都install到了libs目录,没有报错,就编译成功了.
补充:下面结合我遇到过的编译错误,解析一下原因及解决手段:
前提说明:在自己的编译生成的动态库中依赖了第三方so库(编译时第三方库不会再次编译,而是直接拷贝到libs中,
所以一般是在编译依赖了第三方库的自己的动态库时报的错)
(每次用NDK重新编译,最好删除之前生成的编译结果so库和obj目录)
(1)报错error:undefined reference to'Java_com_example_hellojni_HelloJni_stringFromJNI'
collect2:error: ld returned 1 exit status
网上有人说LOCAL_ALLOW_UNDEFINED_SYMBOLS:= true就可以编译过,但这是治标不治本,运行时依然报错。
错误原因:so库在生成时,如果Application.mk声明一个变量APP-ABI:=xxx,会生成不同平台下的so库,而且编译时64位平台的so库无法在32位平台上被链接,这才报了这个解决依赖链接时找不到库中方法的问题,所以虽然Android.mk中指明了是PREBUILT_SHARED_LIBRARY的so库,但不被链接还是找不到库中API的。
解决方法:获取so库时最好要取得相应版本的库(armeabi-v7a与armeabi都是32位,一般情况下应该互相兼容,但不兼容64位的arm64-v8a)。
(2)报错 error adding symbols:File in wrong format
collect2:error: ld returned 1 exit status
(ld是链接操作)
错误原因:如果Application.mk中APP-ABI:=的目标编译平台版本为64位,而实际导入的so库版本是32位,就会不识别该so库(wrong format)。
解决方法:在Application.mk(如果没有,创建)中,把APP-ABI:=xxx的目标编译版本降低点,如armeabi-v7a、armeabi这些32位等等,使之与实际导入so库匹配
整理思路:(可以在终端中,使用$file xxx.so指令查看动态库是32位还是64位。)
接下来我通过对比不同so库与编译目标ABI来进行解析:
前提准备:在自己由源文件编译的动态库中,假设依赖调用了两个第三方so库 a.so(准备了各个ABI版本)和b.so(只有版本为armeabi的)。
1. 第三方a.so库版本arm64-v8a,(不创建Application.mk)默认目标编译版本(默认是armeabi版本):
报错:Fileformat not recognized
原因:默认的目标编译版本为32位,比第三方a.so库的64位低,识别不了a.so库。
2. 第三方a.so库版本arm64-v8a,Application.mk中目标编译版本APP-ABI:= armeabi-v7a
报错:Fileformat not recognized
原因:目标编译版本是32位,比第三方64位的a.so库低,识别不了64位a.so库。
3.第三方a.so库版本armeabi-v7a,Application.mk中目标编译版本APP-ABI:= arm64-v8a
报错:erroradding symbols: File in wrong format
原因:目标编译版本是64位比32位的第三方so库高,a.so或b.so被认为文件格式错误。
4. 第三方a.so库版本armeabi-v7a,Application.mk中目标编译版本APP-ABI:= armeabi-v7a
结果:版本匹配,NDK编译正常,armeabi-v7a兼容armeabi版本的b.so,app运行正常
5. 第三方a.so库版本armeabi,Application.mk中目标编译版本APP-ABI:= armeabi-v7a
结果:版本匹配,NDK编译正常,armeabi-v7a与armeabi互相兼容,app运行正常
6. 第三方a.so库版本arm64-v8a,Application.mk中目标编译版本APP-ABI:= arm64-v8a
报错:erroradding symbols: File in wrong format
原因:目标编译版本高于b.so,所以在解决32位的b.so的依赖时报错,但64位的a.so编译正常。
总结:
调用第三方so库时要先查看文件ABI版本,根据32或64位的相应ABI版本去定义Application.mk中目标编译版本APP-ABI。当然最好都是同一种版本,避免出现不识别、不兼容。
五、运行APP遇到的问题
补充:
我的demo是可以直接运行并调用第三方so库的,但在实际项目中还是遇到了loadLibrary()找不到so库的问题,报了下面的异常:
Couldn't load CloudService from loader dalvik.system.PathClassLoader[
DexPathList[[zip file "/data/app/com.example.demo-1.apk"],
nativeLibraryDirectories=[/data/app-lib/com.example.cameraframedatademo-1,
/vendor/lib,
/system/lib]]]: findLibrary returned null
解决方法: 既然是从DexPathList、nativeLibraryDirectories路径中找不到so库文件,那就手动push到对应目录下。我这里是把所有第三方库都adb push 到了设备的system/lib
目录下(如果需要且支持64位so库,请push到system/lib64目录下),这样项目调用最终会在system/lib目录下找到so库(由于push到了系统文件夹下,其他应用也可以调用喽)。
Android平台下JNI调用第三方so库相关推荐
- Android 平台下Cordova 调用Activity插件开发
首先建立一个包名为package com.JiajiaCy.CallActivity; package com.JajaCy.CallActivity;import org.apache.cordov ...
- Android如何调用第三方SO库
问题描述:Android如何调用第三方SO库: 已知条件: SO库为Android版本连接库(*.so文件),并提供了详细的接口说明: 已了解解决方案: 1.将SO文件直接放到libs/armeabi ...
- 【走过巨坑】android studio对于jni调用及运行闪退无法加载库的问题解决方案
[走过巨坑]android studio对于jni调用及运行闪退无法加载库的问题解决方案 参考文章: (1)[走过巨坑]android studio对于jni调用及运行闪退无法加载库的问题解决方案 ( ...
- arch linux arm下载_linux系统下编译给android JNI调用的Gmssl库
编译给android JNI调用的Gmssl库的方法,网络上并不多.按照叶大强(CSDN账号:hkNaruto)写的<GmSSL Android NDK编译 (版本95c0dba>的帖子编 ...
- Android平台下Dalvik层hook框架ddi的研究
通过adbi,可以对native层的所有代码进行hook.但对于Android系统来说,这还远远不够,因为很多应用都还是在Dalvik虚拟机中运行的. 那么,有没有什么办法可以对Dalvik虚拟机中跑 ...
- 【Android NDK 开发】NDK 交叉编译 ( Ubuntu 中交叉编译动态库 | Android Studio 中配置使用第三方动态库 )
文章目录 I . 动态库 与 静态库 II . 编译动态库 III. Android Studio 使用第三方动态库 IV . Android Studio 关键代码 V . 博客资源 I . 动态库 ...
- ffmpeg实战教程(八)Android平台下AVfilter 实现水印,滤镜等特效功能
ffmpeg实战教程(八)Android平台下AVfilter 实现水印,滤镜等特效功能 ffmpeg实战教程(七)Android CMake avi解码后SurfaceView显示 本篇我们在此基础 ...
- android平台下OpenGL ES 3.0给图片添加黑白滤镜
OpenGL ES 3.0学习实践 android平台下OpenGL ES 3.0从零开始 android平台下OpenGL ES 3.0绘制纯色背景 android平台下OpenGL ES 3.0绘 ...
- android平台下OpenGL ES 3.0从零开始
OpenGL ES 3.0学习实践 android平台下OpenGL ES 3.0从零开始 android平台下OpenGL ES 3.0绘制纯色背景 android平台下OpenGL ES 3.0绘 ...
- android平台下OpenGL ES 3.0绘制纯色背景
OpenGL ES 3.0学习实践 android平台下OpenGL ES 3.0从零开始 android平台下OpenGL ES 3.0绘制纯色背景 android平台下OpenGL ES 3.0绘 ...
最新文章
- 解决在vue中axios请求超时的问题
- 思科asa5515端口映射_Cisco ASA端口映射
- 控件设置相对位置_惊人的Divi转换控件!
- html5 java 图片上传_java实现图片上传至服务器并显示,如何做?希望要具体的代码实现...
- python操作excel命令_python操作Excel读写(使用xlrd和xlrt)[转帖]
- E-Learning是学习系统而不是教育系统
- 计算机知识认证,[IT认证]计算机基础知识.ppt
- STM32——HAL库函数版——AD7656驱动程序
- C语言课程设计|通讯录管理系统(含完整代码)
- 转:Andriod Phone模块相关
- Intel 助力移动云百万 IOPS 云硬盘,打造极速云存储体验
- 视觉中国图片编码_学习编码第14天的应用视觉设计第4部分
- 六、常用的sql语句
- Compensating-Transaction模式
- 1. 设计数据库结构
- 蓝牙核心协议学习 -- 基带协议(Baseband)
- 权益证明问题 —— Proof of Stake FAQ
- Java秒杀系统实战系列~JMeter压力测试重现秒杀场景中超卖等问题
- android如何设置图标,Android APP如何设置显示图标
- 3GPP R18确定27个研究项目,看看包含哪些?
热门文章
- 计算机高程知识点,测量学复习基本知识点(全).doc
- The APR based Apache Tomcat Native library which allows optimal performance in......
- 浅析携程智能客服机器人实现
- Android和风SDK,Android 和风天气SDK获取天气
- windows系统常用命令
- 图片转ascii字符画C语言,将图片转为ASCII字符画
- 电脑网线/水晶头的连接方法(A类,B类)
- [转]大规模服务设计部署经验谈
- ESP8266_CH340G串口自动下载固件库原理
- win10 1607 密匙