Android Jni开发-实战篇(CMake)

本例demo下载地址:JniDemo下载

简介

上篇介绍了Android Studio中CMake简单配置jni开发。不清楚的可以看
Android Jni开发-基础配置篇(CMake)

如果不想麻烦的话直接在示例Jni代码native-lib.cpp中添加自己的业务逻辑即可。但是这样当代码一多了的时候不好扩展也不好管理,因此这次来实践添加自己的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代码文件)。
在这里插入图片描述
然后往连接库的指令添加这个库的声明。
在这里插入图片描述
至此,CMakeLists.txt的修改就完成了,就是这样简单。

5、添加java native方法接口
上篇示例中java native方法接口是直接声明在MainActivity中的,为方便管理,我们建立一个专门的Jni接口包用来管理所有的java native方法集合,为跟demo-lib.cpp对应,我们创建一个Java的Demo接口类。
在这里插入图片描述
在这里插入图片描述
这里使用Android Studio的好处就体现出来了,java native方法接口未有相应的jni函数接口是会标红提醒的,因为我们的demo-lib.cpp未添加任何代码,所以这里标红了。因此也可以根据这个来判断jni命名是否写正确,不正确的话会标红提醒。

6、编写jni函数名
为解决上面的标红提醒,我们来编写jni函数名。我们知道jni函数名是有一定格式的,不熟悉的朋友可能会觉得jni函数名很难写,但是如果熟悉了是可以直接对照java native方法手动编写对应jni代码函数,毕竟写错了也没关系,会标红提醒的。这里推荐使用java命令为我们自动生成jni代码,毕竟函数一多,手写很累的。

(1) 打开windows的cmd命令(当然也可以使用Android Studio自带的Terminal控制台),切换到Demo.java这个native 方法接口类的路径。然后使用javac Demo.java将该类转换为.class文件。
在这里插入图片描述
可以发现,执行后报了一个错,这是由编码格式不对造成的,因为我们这个类的注释里面使用了中文。虽然可以更改编码格式解决,但是为了减少不必要的麻烦,最好在这个接口类中不要出现中文。我们把类里面的中文注释改成英文再试试。
在这里插入图片描述
可以发现,这次不报错了。
这时可以发现Demo.java的目录下多了个Demo.class文件。
在这里插入图片描述

(2)接着切换回工程的java目录下,使用javah -classpath . -jni + 包名 + 文件名生成.h文件(命令中-jni前面的点是必要的)。windows切换上级目录使用cd…命令。
在这里插入图片描述
执行完成后,可以在java目录下看到一个以包名+文件名的.h文件,里面即写好了Demo.java对应的jni函数名称代码。
在这里插入图片描述
这个文件的内容如下所示:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class mhwang_com_jni_Demo */

#ifndef _Included_mhwang_com_jni_Demo
#define _Included_mhwang_com_jni_Demo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     mhwang_com_jni_Demo
* Method:    sum
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_mhwang_com_jni_Demo_sum
  (JNIEnv *, jobject, jint, jint);

/*
* Class:     mhwang_com_jni_Demo
* Method:    twoSum
* Signature: ([II)[I
*/
JNIEXPORT jintArray JNICALL Java_mhwang_com_jni_Demo_twoSum
  (JNIEnv *, jobject, jintArray, jint);

#ifdef __cplusplus
}
#endif
#endif

可以看到,文件里面已经写好Demo.java里面方法相对应的jni函数名了。

(3) 这时把生成的.h文件里面的内容复制粘贴到我们之前创建的demo-lib.cpp文件里面,jni代码里面的命名部分就完成了。
当写好jni函数名后,你会发现Demo.java里面的代码也不再是红色了,说明Demo.java里面的方法能正确调用jni的函数了。
在这里插入图片描述

7、实现jni调用C++函数
先实现sum()这个比较简单的jni函数,我们先把函数的参数补上,然后调用demo.cpp里面的Demo对象的sum()方法进行计算。由于这里使用了demo.cpp里面的类Demo,因此需要在头文件引用demo.cpp文件。
在这里插入图片描述
在这里插入图片描述
在MainActivity调用一下,然后我们来运行一下看看:
在这里插入图片描述
调用成功了。接下来实现twoSum()调用。c++中的twoSum函数需要传递一个数组,而java的数组是不能直接作为参数传递给c++函数的,因此需要Jni作一层转换。具体的jni转换函数如下:

/***
* 将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;
}

这里使用了一些C++内置函数,因此需要在jni头文件中引入。

#include <cstring>
#include <malloc.h>

然后在jni函数中直接调用该函数转换成指针形式传递给C++函数中:
在这里插入图片描述
在MainActivity中调用:
在这里插入图片描述

运行结果如下:
在这里插入图片描述

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值