这篇内容适合哪些人:
1、Android研发有一定的安卓基础并且想要学习JNI编程的人员
文章最后附Demo
工程目录结构:

本章内容概要
1、基于CMake ,NDK
2、配置CMake
3、定义JNI 接口类(用于交互jni)
4、编写JNI层的被调用方法
5、JNI 生成 so 库
6、编译运行
一、CMake 下载:

二、CMake配置
1、在build.gradle 文件下指定CMakeLists.txt 的路径
//指定你的CMakeLists文件的位置
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
2、指定生成的so库类型(按需配置)
externalNativeBuild {
cmake {
cppFlags ""
abiFilters 'armeabi-v7a'
}
}
三、定义JNI 接口类(用于交互jni)

四、编写JNI层的被调用方法
目标:实现一个简单的jni函数sum(int a, int b),返回a+b的结果。一个稍微复杂点的jni函数twoSum(int nums[], int target),实现的是leetcode上的一个题目TwoSum,内容是给定数组及目标数字,返回符合目标数字的2个数的下标(数组类型)
1、首先建立一个demo.h
该文件作为c++的头文件,声明要实现的函数
#ifndef JNIDEMO_DEMO_H
#define JNIDEMO_DEMO_H
#endif //JNIDEMO_DEMO_H
class Demo{
public:
Demo();
int sum(int a,int b);
int *twoSum(int nums[],int target);
};
2、建立demo.cpp文件实现算法。
该文件实现头文件声明的函数。
#include <cstring>
#include "demo.h"
Demo::Demo() {
}
int Demo::sum(int a, int b) {
return a + b;
}
int* Demo::twoSum(int nums[], int target) {
int length = sizeof(nums);
if (length < 2){
return nullptr;
}
int *result = nullptr;
for (int i = 0; i < length; i++){
for (int j = i + 1; j < length; j++){
if (nums[i] + nums[j] == target){
result = new int[2];
result[0] = i;
result[1] = j;
break;
}
}
}
return result;
}
3、创建demo-lib.cpp文件
这个文件里面放的是我们的jni代码,暂时还不用写先,因为现在不想手动写jni函数名,至于为什么叫demo-lib(.cpp文件名加-lib),一句话,官方推荐命名格式以及样例也是这样命名的。
4、修改CMakeLists.txt
跟之前native-lib文件一样,新加的库使用add_library指令。我们直接复制native-lib的add_library添加到下面,将native-lib改成我们的demo-lib.cpp(即第3点创建的jni代码文件)。
a、先添加库,用add_library(...)

b、将我们新增的库依赖进去

c、配置一个so库输出的路径
在CMakeLists.txt内
#设置生成的so动态库最后输出的路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI})
至此,CMakeLists.txt的修改就完成了,下面我们来编写jni层的代码。
在demo.cpp文件内编写被调用的方法:
注意点:
1、jni方法的命名
2、c++中的twoSum函数需要传递一个数组,而java的数组是不能直接作为参数传递给c++函数的,因此需要Jni作一层转换
最终实现:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <cstring>
#include <malloc.h>
#include "demo.cpp"
/* Header for class com_albert_demo_util_NativeMethodSum */
#ifndef _Included_com_albert_demo_util_NativeMethodSum
#define _Included_com_albert_demo_util_NativeMethodSum
#ifdef __cplusplus
extern "C" {
#endif
/****
*
* 将Java数组转化成C++ 指针数组
*/
jint * getIntArrayFromJava(JNIEnv *env,jintArray j_array){
jint *c_array;
jint arr_len;
arr_len = (*env).GetArrayLength(j_array);
c_array = (jint*)malloc(sizeof(jint) * arr_len);
//初始化
memset(c_array,0,sizeof(jint)*arr_len);
//获取数组
c_array = (*env).GetIntArrayElements(j_array,NULL);
return c_array;
}
/*
* Class: com_albert_demo_util_NativeMethodSum
* Method: sum
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_albert_demo_util_NativeMethodSum_sum
(JNIEnv *, jclass, jint a, jint b){
Demo demo = Demo();
jint result = demo.sum(a,b);
return result;
}
/*
* Class: com_albert_demo_util_NativeMethodSum
* Method: twoSum
* Signature: ([II)I
*/
JNIEXPORT jintArray JNICALL Java_com_albert_demo_util_NativeMethodSum_twoSum
(JNIEnv *env, jobject, jintArray nums, jint target){
Demo demo = Demo();
jint *result = demo.twoSum(getIntArrayFromJava(env,nums),target);
if (result == nullptr){
return nullptr;
}
// C++返回的数组为指针形式,也不能直接返回给java,所以通过Jni复制一个jintArray数组返回给java
jintArray array = (*env).NewIntArray(2);
(*env).SetIntArrayRegion(array,0,2,result);
return array;
}
#ifdef __cplusplus
}
#endif
#endif
五、JNI 生成 so 库
工程clean、build 即可生成so库
六、编译运行

本文参考:
疯一样的雨博主的Android Jni开发-基础配置篇(CMake)
疯一样的雨博主的Android Jni开发-实战篇(CMake)
网友评论