关于CMake:从androidStudio2.2版本开始,可以用cmake方式创建jni工程。

打开androidStudio之后按照以下步骤:
1)File-New-New Project , 注意勾选支持c++。然后一路next一直到finish。

CXIMAGE支持android studio_java

 

2)我这里出现一个编译问题;(如果没遇到这个问题,跳过此步骤)

CXIMAGE支持android studio_方法名_02

 

这个是因为新创建的工程,没有默认的NDK配置;配一下即可。操作如下:
右键工程名,选open Module Setting 打开这个:

CXIMAGE支持android studio_c/c++_03

然后注意红色标记。配置好你的NDK路径,我用的是14b这个版本。
点OK,然后androidStudio会自动编译。

3)观察一下自动生成的这些代码;

CXIMAGE支持android studio_移动开发_04

这里有一个自动生成的MainActivity.java 红色标记的地方,就是调用的JNI。

下面的System.loadLibrary就是加载名为native-lib.so的引擎文件(cmake方式下,在工程中看不到这个文件,但是编译出来的apk是有的)

上面的native方法,就是在java代码中声明,jni层有这么一个方法的实现。

左边画圈圈的 ,点一下

CXIMAGE支持android studio_c/c++_05

(或者鼠标放在方法名上面,按住ctrl,点鼠标左键),就能直接索引到cpp文件中,这个方法的具体实现。如下图。

CXIMAGE支持android studio_android_06

 

第一次看到这个文件可能有点陌生,下面贴出重要代码的注解;



#include <jni.h>
#include <string>

extern "C" //这一句,表示,按照C的方式去编译,如果不加这句,可能导致找不到这个方法
JNIEXPORT jstring JNICALL //这一句,表示,返回值是一个java的string,至于JNIEXPORT ,JNICALL都是JNI的语法
Java_test_hank_com_jni1011_MainActivity_stringFromJNI( // 这句,表示这个是实现JAVA类中的一个方法,java类的全名是test.hank.com.
//jni1011.MainActivity,方法名为stringFromJNI
JNIEnv *env,//指针对象
jobject /* this */) {
std::string hello = "Hello from C++";//创建string 对象,std::的写法,std是c++标准库,两个冒号之后,加上string,是说这个类是c++标准库内的string类。用这个类来创建一个string对象
return env->NewStringUTF(hello.c_str());//返回值 ,由于env是指针对象,所以要用->来调用方法,NewStringUTF() 构建一个UTF编码的字符串
}



运行工程,就能看到界面中间显示一行字符串“Hello from C++”;这行字符串明显来自jni层。
android给我们创建示例工程的时候,只告诉我们怎么用java调用jni。但是jni回调java的过程,需要我们手动修改代码。

4)手动修改代码,来实现jni层调用c++层的代码;

1-新建一个java类:JavaCaller.java ,并创建一个方法,表示这个就是让jni层去调用的方法。


CXIMAGE支持android studio_java_07

 

2-jni调用java某个对象的方法,也要遵循面向对象的方式,必须有该对象的引用才行。所以我们要先传递一个对象到jni层。
看代码。
在java层,新建一个native方法,setJavaObject,参数为JavaCaller类的一个对象。

CXIMAGE支持android studio_移动开发_08

 

鼠标放在方法名上,按住alt+enter,就会提示,创建一个jni方法,作为这个native的实现。
选择创建该方法,(这里有个坑,自动生成的这个方法,没有extern "C" 导致编译通不过,大概原因就是加了extern "C",就表示用c的方式去编译,jni对接的应该还是c,所以要加上extern "C")
然后写代码调用这个setJavaObject方法。
接下来继续进入jni层,这里,我们的目的是jni层调用java类的某个方法。
所以,要在jni中写代码来使用传递进来的这个java对象。
代码如下,有每个步骤的详细注解:

CXIMAGE支持android studio_方法名_09

这样的话,调用过程就执行完毕了。
执行代码,就会发现,日志中有这一行。
10-11 04:23:51.112 4254-4254/test.hank.com.jni1011 D/hankzhou: param:这里能不能放中文? - param2:真的可以放中文耶

这个就是我们在JavaCaller.java test方法中打印的日志。说明,jni回调java的方法成功。

至此,AndroidStudio - cMake方式开发jni的示例就完成了。

但是,有两点需要说明一下。

1)java的类型 转化为jni的类型存在有规律的转化(观察一下java层的native方法,以及jni层的c方法,两者的参数列表。有关联,但是写法大不相同)


CXIMAGE支持android studio_c/c++_10

 

很抽象?那么看图吧。
这是java的:

CXIMAGE支持android studio_c/c++_11

 

这是jni的:

CXIMAGE支持android studio_方法名_12

 

jni前面的两个是干啥的暂时不知,但是很明显能看到3个参数都是string,到了jni这里,就变成了jstring,这就是所谓写法上的转化。

2) jni回调java对象的某个方法,也是有类型转换的;

CXIMAGE支持android studio_java_13

还是看图:
java的方法:

CXIMAGE支持android studio_c/c++_14


jni中用反射创建该方法:

CXIMAGE支持android studio_方法名_15

 

这里的实参,test 是方法名,保持一致。
形参以及返回值,必须完全对应,这里就有一个类型转换了。
先看最后这个V,对应test方法的返回值void。
前面的两个 Ljava/lang/String; 对应两个string。(多个参数,分号分隔)
这里是void和string,那么如果是其他类型呢?参见了上面的表格。

 

以上就是cMake方式开发jni的入门级指导。更复杂的,以后再写。