一、配置JNI开发环境
1.在Android studio 的SDK Tools里面下载NDK 和CMake,并配置ndk的环境变量。
2.在local.properties添加配置ndk路径
sdk.dir=D\:\\software_install\\Android\\sdk
ndk.dir=D\:\\software_install\\Android\\sdk\\ndk //这里要添加自己的ndk路径,记得不要直接复制粘贴就完事。
3.在gradle.properties中添加
android.useDeprecatedNdk=true //表示兼容老的ndk版本
二、编写Java代码
1.新建TestJni类
package com.zzq.testjni.jni;
public class TestJni {
public native void add(int a,int b);
public native String getString();
}
2.生成.h头文件
(1)利用javac命令生成TestJni.class文件
javac TestJni.java //在TestJni.java文件所在目录执行此命令
(2)利用javah命令生成.h头文件
javah -classpath . -jni com.zzq.testjni.jni.TestJni
注意:这个命令必须在TestJni类包名的前一级目录下执行,如TestJni.java的完整路径名是
D:\workspace\0920\AndroidPerformanceMonitor-master\TestJNI\app\src\main\java\com\zzq\testjni\jni\TestJni.java
后面的com\zzq\testjni\jni是TestJni的包名,则此命令就需要在java目录下执行。
执行成功后会生成如下com_zzq_testjni_TestJni.h头文件。
头文件类容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_zzq_testjni_jni_TestJni */
#ifndef _Included_com_zzq_testjni_jni_TestJni
#define _Included_com_zzq_testjni_jni_TestJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_zzq_testjni_jni_TestJni
* Method: add
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_com_zzq_testjni_jni_TestJni_add
(JNIEnv *, jobject, jint, jint);
/*
* Class: com_zzq_testjni_jni_TestJni
* Method: getString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_zzq_testjni_jni_TestJni_getString
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
这里面有对应我们在TestJni.java中写的两个方法的函数。
JNIEXPORT void JNICALL Java_com_zzq_testjni_jni_TestJni_add
(JNIEnv *, jobject, jint, jint);
JNIEXPORT jstring JNICALL Java_com_zzq_testjni_jni_TestJni_getString
(JNIEnv *, jobject);
这里的JNIEnv 可以理解为java中的上下文,jobject就是调用这个函数的对象。
三、生成so库
1.利用Clion创建一个C++ library的项目
2.将上面生成的com_zzq_testjni_TestJni.h文件拷贝到这个项目
这时,应该会报找不到jni.h文件的错误,这时需要到jdk的安装目录\jdk\include下面找到该文件,复制过来,并将#include <>的尖括号改为“”即可。
扩展:
#include <> 表示引入的系统头文件
#include "" 表示引入的自己的头文件
这时应该还有JNIEXPORT关键字报红,我们再把\jdk\include\win32下面的jni_md.h文件拷贝到项目里面去
3.新建同名的.c文件(com_zzq_testjni_TestJni.c),来实现.h文件里面定义的函数。
-
在加入com_zzq_testjni_TestJni.c里面加入以下代码,与com_zzq_testjni_TestJni.h文件建立关联。
#include "com_zzq_testjni_jni_TestJni.h"
-
在加入com_zzq_testjni_TestJni.c里面加入以下代码,实现com_zzq_testjni_jni_TestJni_getString函数
JNIEXPORT jstring JNICALL Java_com_zzq_testjni_jni_TestJni_getString (JNIEnv * env, jobject jobject1){ return (*env)->NewStringUTF(env,"我是C定义的String"); }
4.配置CMakeLists.txt文件
add_library(mathlib SHARED com_zzq_testjni_jni_TestJni.h com_zzq_testjni_jni_TestJni.c)
- mathlib 为自定义库的名称
- SHARED 表示这个是共享库
- com_zzq_testjni_jni_TestJni.h 、com_zzq_testjni_jni_TestJni.c 这是这个库的代码。
5.然后直接build project 就会生成如下文件
这里的.dll文件就是动态链接库。但只能在windows 环境下用,如果想在Android环境下使用,还需要用.so库。
简单介绍下so库的简单编译流程,后面会单独出详细教程。
(1) 在linux环境 的ubuntu系统里面 安装ndk,配置ndk环境
(2) 把第三方库的源码拉下来
(3) 官网看下有没有提供编译脚本build.sh或者是readme.txt或者是configure.
(4) 编译.so库
四、知识问答
1.JNIEnv是什么?
JNIEnv是一个线程相关的结构体,该结构体代表了Java在本线程的执行环境,通过JNIEnv的实例对象可以调用Java代码