本例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_Hclass 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中调用:

运行结果如下:

Android Jni开发-实战篇(CMake)相关推荐

  1. android 串口开发第二篇:利用jni实现android和串口通信

    一:串口通信简介 由于串口开发涉及到jni,所以开发环境需要支持ndk开发,如果未配置ndk配置的朋友,或者对jni不熟悉的朋友,请查看上一篇文章,android 串口开发第一篇:搭建ndk开发环境以 ...

  2. Android JNI开发入门与实战

    简介: 涉及到一些算法或者底层驱动的时候,往往需要使用jni来开发.现在官方推荐使用CMake工具来开发jni. 使用CMake开发Jni其实挺简单的,要求不高的话只需要简单配置一下就可以使用了. 配 ...

  3. Android JNI开发入门之二

    在上一篇文章<Android JNI开发入门之一>中,我介绍了Android应用程序(APK)怎样通过JNI调用Native C实现的共享库.本文将进一步介绍Android应用程序通过JN ...

  4. 《Android Studio开发实战 从零基础到App上线(第2版)》出版后记

    2015年11月23日,鄙人在csdn发表了第一篇技术文章,掐指一算距今已有三年.遥想当年开写博客,只是为了总结经验同时分享出来,后来机缘巧合受到出版社编辑邀请并出了书,完全是无心插柳的结果.当初写作 ...

  5. 《Android Studio开发实战 从零基础到App上线》源码运行问题解答

    本书提供了所有章节的完整源码下载,自上市以来陆续收到读者的意见反馈,现将与源码有关的问题汇总归类如下,方便更多的朋友解决源码运行过程中发现的问题: 一.打开本书源码时,出现"Plugin w ...

  6. 《Android Studio开发实战 从零基础到App上线》第一版的资源下载和内容勘误

    资源下载 下面是<Android Studio开发实战 从零基础到App上线>(第一版)一书用到的工具和代码资源: 1.本书使用的Android Studio版本为2.2.3,因为Andr ...

  7. 《Android Studio开发实战 从零基础到App上线(第2版)》资源下载和内容勘误

    资源下载 下面是<Android Studio开发实战 从零基础到App上线(第2版)>一书用到的工具和代码资源: 1.本书使用的Android Studio版本为3.2,最新的安装包可前 ...

  8. Android NFC开发实战详解

    Android NFC开发实战详解 Android开发实战详解NFC国内第一本AndroidNFC开发书籍带你开启AndroidNFC开发的神秘之旅大综合案例帮助读者快速进入实战角色:WiFi快速连接 ...

  9. 微信小程序|开发实战篇之一

    开发实战篇之一 前言 1.通用方法的封装 2.数据获取方法的封装 2.1 抽离classic.js中的request()方法 2.2 组件数据传递 3.movie组件的创建 3.1 组件代码开发 3. ...

  10. 微信小程序|开发实战篇之request请求(单个、多个参数,json对象,header)

    开发实战篇之request请求 前言 1.发送单个.多个参数的request 2.发送JSON对象的request 3.发送header的request 前言 小程序发送网络请求常会遇到的问题: 请求 ...

最新文章

  1. LeetCode Reverse Linked List II
  2. ImportError: No module named babel.dates
  3. oracle db-link 分布式数据库网络配置协议错误,Oracle学习(18)【DBA向】:分布式数据库...
  4. android 字符串特殊字符转义
  5. linux将文件的第二列求和,awk实现第一列相乘,第二列求和,并相加 - 米扑博客...
  6. php camp,Byte Camp
  7. 线程编程(thread programming)介绍
  8. 卷积层、池化层和全连接层 区别和作用
  9. 利用Python网络爬虫抓取韩寒博客推荐第一篇(urllib的简单使用与Beautifulsoup实战,i/o编程)
  10. 中国智慧园区标准化白皮书 附下载
  11. 台式计算机睡眠快捷键,电脑如何设置快捷方式迅速进入睡眠的状态?
  12. 【Java】P1957 口算练习题—(洛谷OJ)
  13. 第一次基因数据处理从集群到数据处理结果---构建菌群物种丰度的图谱
  14. html让登录框3d,CSS3实现3D旋转动态显示登录注册
  15. css b加粗怎么用,CSS去掉b加粗和strong加粗标签样式.doc
  16. 识别喜欢开发的程序员
  17. error LNK2005: _DllMain@12 已经在 MSVCRTD.lib(dllmain.obj) 中定义
  18. outlook导出邮件(.msg)读取和解析
  19. 开发者工具绕过前端debuger
  20. k8s存储PV与PVC使用详解

热门文章

  1. 从架构设计到系统实施-基于.NET 3.0的全新企业应用之基于WCF的系统服务
  2. LinkedList的源码分析(基于jdk1.8)
  3. Inferred type 'S' for type parameter 'S' is not within its bound;
  4. jQuery图片预加载(延迟加载)之插件Lazy Load
  5. python 基础语法梳理(二)
  6. MVC模式在Java Web应用程序中的实现
  7. CROC 2016 - Elimination Round Mischievous Mess Makers
  8. PostgreSQL 的 window函数
  9. 服务器互相备份不同步_94爱分享拍了拍你,这款好用的数据同步备份软件千万不要错过!...
  10. python-opencv 角点检测的 FAST 算法