1、写jni工具类:
2、生成jni头文件:
在最新的jdk中,javah指令被移除,使用javac -h 指令代替,两者存在差异,javac -h指令包括两个步骤:javac生成x x x.class文件和javah生成jni头文件。javac操作的对象是java源文件,如上图中,java文件全称为:JniUtil.java,则在terminal中通过命令行找到JniUtil.java,通过命令:javac -h jni JniUtil.java 生成jni头文件; 命令中第三个参数为生成的文件夹名。执行成功之后可以在执行命令的根目录下找到一个jni文件夹,其中存在JniUtil.h头文件。
3、编写Android.mk
Android.mk文件主要用于静/动态库生成,文件内容如下:
LOCAL_PATH := $(call my-dir) //每个Android.mk文件必须以定义开始。它用于在开发tree中查找源文件。宏my-dir则由Build System 提供。返回包含Android.mk目录路径。
include $(CLEAR_VARS) //CLEAR_VARS变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx。例如LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES等等。但不是清理LOCAL_PATH。这个清理是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能便面相互影响。
LOCAL_MODULE := jni-utils //LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格。Build System 会自动添加适当的前缀和后缀。例如,demo,要生成动态库,则生成libdemo.so。但请注意:如果模块名字被定义为libabd,则生成libabc.so。不再添加前缀。
LOCAL_SRC_FILES := jniutil_JniUtil.cpp //这行代码表示将要打包的C/C++源码。不必列出头文件,build System 会自动帮我们找出依赖文件。缺省的C++ 源码的扩展名为.cpp。
include $(BUILD_SHARED_LIBRARY) //BUILD_SHARED_LIBRARY是Build System提供的一个变量,指向一个GUN Makefile Script。它负责收集自从上次调用include $(CLEAR_VARS)后的所有
//LOCAL_xxxxinx。并决定编译什么类型
//BUILD_STATIC_LIBRARY:编译为静态库
//BUILD_SHARED_LIBRARY:编译为动态库
//BUILD_EXECUTABLE:编译为Native C 可执行程序
//BUILD_PREBUILT:该模块已经预先编译
LOCAL_SRC_FILES对应的参数是后续cpp文件的文件名,即jni源文件,不需要写头文件,只需要写cpp/c文件名称即可,因为在环境配置好之前,android studio中编写c/cpp文件如同在txt中编写一样,不太友好,所以把cpp文件的编写留在最后。
4、修改app中的build.gradle文件:
在defaultConfig块中添加ndk块:
ndk{
moduleName "jni-utils"
}
在android代码块中添加externalNativeBuild 和 sourceSets.main块:
externalNativeBuild {
ndkBuild{
path 'src/main/java/jniuitl/jni/Android.mk'
}
}
sourceSets.main{
jni.srcDirs = []
}
demo的build.gradle文件如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "realsee.androidresearch"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk{
moduleName "jni-utils"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
ndkBuild{
path 'src/main/java/jniuitl/jni/Android.mk'
}
}
sourceSets.main{
jni.srcDirs = []
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
5、makeProject并编写cpp文件
执行makeProject,在jni文件夹中创建.cpp文件,引入对应头文件,即可进行代码编写,demo的cpp文件如下:
#include "jniuitl_JniUtil.h"
JNIEXPORT jstring JNICALL Java_jniuitl_JniUtil_getStart
(JNIEnv *env, jclass){
return env->NewStringUTF("let's start here");
}
.h文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jniuitl_JniUtil */
#ifndef _Included_jniuitl_JniUtil
#define _Included_jniuitl_JniUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: jniuitl_JniUtil
* Method: getStart
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_jniuitl_JniUtil_getStart
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
ending.
--------------------------------------------补充------------------------------------------------
如果在ndk中无法解析iostream 和namespace std,在android.mk中添加如下两句话:
LOCAL_C_INCLUDES := $(NDK_ROOT)/sources/cxx-stl/stlport/stlport
LOCAL_LDLIBS := $(NDK_ROOT)/sources/cxx-stl/stlport/libs/armeabi/libstlport_static.a