开发中经常会用到so库,大多是调用第三方的so库,偶尔也需要自己封装一个so库给别人调用,这边就记录一下开发so库的一个过程.
首先我们这边是在Android Studio中开发的,所以仅描述在Android环境下开发过程,当然也可以用其他工具开发.
目录
1.第一步新建项目,配置需要的工具
2.新建C++文件,编写代码
3.so库的类型
4.打包非JNI标准so库
5.打包符合JNI标准so库
6.打包完成
我们就先新起一个项目,创建项目的时候选择Native C++选项,新建完成之后有些地方还需要手动配置一下,例如NDK.对于so库不了解的同学大多数应该都没有安装本地NDK.这边给大家看下怎么安装,
在settings中选择SDK选项,往下拉会有NDK的列表,在这边可以选择需要下载的NDK版本.
然后我们找到项目的local.properties文件,这边加上一行,我这边用的是20.1.5948944版本,至于各位自己用什么版本,按照自己刚刚安装的版本填写就可以了,路径是NDK的下载路径.
如果这项已经存在了就不需要手动添加了.
在src/main/cpp目录下新建C++文件
新建的时候最好加上头文件,后面会用到.
然后我们打开CMakeLists.txt文件,在add_library中添加我们刚刚新建的文件,只要加cpp文件就可以了(头文件不需要加)
这时候我们就可以开始编写C++代码了,我们就写个最简单的功能,两个整数求和.
这时我们so库中需要的功能已经写完了.
对于安卓开发而言,so库有两种,第一种是不符合JNI标准的so库,第二种是JNI标准的so库
先来解释下什么是JNI,JNI全名: Java Native Interface,意思是Java本地接口
Java本身是不可以直接调用C++代码的,需要依靠JNI来调用C++代码
两种有什么区别呢
第一种不符合JNI标准的,需要提供so库和对于的头文件,这种写的时候方便,调用起来麻烦.
第二种符合JNI标准的so库,写的时候麻烦,调用起来方便.
至于需要哪种,各位自己看着办
这类so库需要生成两种文件,一个是so库,还有一个是头文件,就是把外界需要调用的函数名和类暴露出来.
如果是这种so库,我们现在就可以直接打包了
Android Studio左上角选择Build->Clean Project,先把项目生成的一些缓存文件清理一下,然后选择Rebuild Project,把项目重构一下
可以看到,在app->build->intermediates->cmake->debug->obj下有几个文件夹,这里面全是so库,这几个文件夹各不相同,可以全部复制过去,(如果不想全部复制,可以选择需要的ABI,怎么选择ABI?这个自己百度)
这边so库的名称和CmakeLists.txt中project("sodemo")是对应的.
注意,这类so库还需要头文件,要不然外面访问不到so库中的函数,头文件是哪个呢,就是这边的TestSo.h文件,直接复制出去即可.
总结一下就是需要给两类文件,一个是各个ABI对应的so库,一个就是头文件.
打包符合JNI标准的so库就有点麻烦了,需要自己手写JNI,
首先我们打开项目中自己生成的native-lib.cpp文件,这里面其实一开始是写了一个JNI函数的,我们可以依照那个写一个,
这边可以看到语法比较奇怪,我们挨个看一下
extern "C" JNIEXPORT jint JNICALL,这边是JNI固定语法,主要是jint,这个是就是我们返回的数据类型.
然后就是下面的函数名Java_com_example_sodemo_NativeTestSo_addition,这边com_example_sodemo就是包名,哪个的包名呢,就是NativeTestSo.java的包名,意思就是NativeTestSo.java这个类,要放在com/example/sodemo下面,这个是一定的,不能乱写
然后addition,这个就是NativeTestSo.java中对应的方法名,Java代码中调用的方法名
然后看到带了几个参数,JNIEnv *env, jobject , jint num1,jint num2,前两个JNIEnv *env, jobject是固定的,不用管,主要看后面两个,这两个就是NativeTestSo.java中addition方法传进来的两个参数.
简单组合一下就是
extern "C" JNIEXPORT 返回数据类型 JNICALL Java_包名_类名_方法名(JNIEnv *env, jobject,形参1,形参2...){}
然后按照上面打包so库的步骤执行一下,在app->build->intermediates->cmake->debug->obj就会出现直接可以用的so库了
有一种额外的情况,就是我这的这段C++代码,不需要打包成so库给别人用,只在这个项目中使用
这时候就不需要像上面一样去打包so库了,直接新建一个Java类
这边注意看圈红的地方,全都是上文中第5条里提到的注意点,一个字母都不能错,我这边的包名和类目都是前面一篇中指定的,各位要替换成自己的
然后就可以直接调用啦
可以看到,我这边已经调用成功了.
C++编写、生成、调用so库详解(二)