JNI = Java native interface
也就是java的本地接口 指的是利用C/C++这样的贴近底层的语言
1. 为什么要利用C/C++
1. C/C++语言的高效率 比如对一堆数据进行排序 C/C++的效率毫无疑问是要超过java的
2. 复用C/C++的代码 类似ffmpeg webrtc这样的媒体框架 在需要用到的时候是绕不开的也不可能造这种规模的轮子
3. 避免app源码被反编译破解(不太了解 带过)
2. 如何使用
常见的使用模式也就是将需要使用的第三方C/C++库编译成so动态库 然后通过一个封装类来调用其中的接口
也就是 native-lib.cpp -> xxx.so
然后将native-lib.cpp编译为native-lib.so 供给java类调用
java端一般用一个类来封装本地方法
class javaNativeWraper {
static {
System.loadlibrary("native-lib");
}
public static native int xxx_fun();
}
native关键字修饰表示这是一个本地方法 声明成静态方法和静态加载 不实例化封装类也可以使用接口
使用中遇到的几个问题的总结
- cmake找不到第三方so
由于是在androidstudio中开发apk 使用jni一般是通过cmake引入
过程中发现cmake经常找不到C/C++ so库
摸索了一个引入方法是: 以引入rockchip mpp库为例
截取部分cmake脚本
# CMKAE_SOURCE_DIR 也就是cmake脚本所在目录 cpp是我工程中cpp代码所在目录
set(src_dir ${CMAKE_SOURCE_DIR}/src/main/cpp)
# 生成给java调用的so
add_library(native-lib SHARED ${src_dir}/native-lib.cpp)
# 引入mpp库
add_library(mpp SHARED IMPORTED)
set_target_properties(mpp PROPERTIES IMPORTED_LOCATION ${src_dir}/libmpp.so)
target_link_libraries(native-lib mpp)
出现类似 Java.IO.Exception这样的编译错误
尝试Build->Clean project再编译app运行时找不到so
虽然编译时链接了so 但是so并不会被打包到apk中 所以运行时会出现dlopen动态库失败的报错
在main目录(也就是包含java目录的那个目录)创建jniLibs文件夹
mkdir jniLibs/armeabi/
把libmpp.so放入armeabi文件夹下
同时修改 app目录下的build.gradle
android {
compileSdkVersion 26
buildToolsVersion "26.0.0"
defaultConfig {
applicationId "com.example.root.mpp_android_demo"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
}
}
#添加ndk字段 生成armeabi
ndk {
abiFilters 'armeabi'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
简单做法
在实际应用中发现一个简单的做法
在java代码的同级目录下设置c++代码
至于库 创建java代码的同级jniLibs目录 把需要链接的库都放这里
这样 不需要再额外配置gradle 非常方便