1,环境准备下载的ndk
2,android studio 配置ndk
第一种方式配置
local.properties
sdk.dir=D\:\\installtool\\sdk\\sdk
ndk.dir=D\:\\tools\\android\\android-ndk-r10d-windows\\android-ndk-r10d
第二种方式配置
快捷键F4 弹出项目结构对话框,选择ndk目录
3,在项目的src/main创建jni目录
jni 目录里面创建Android.mk和后面这个文件不要Application.mk也是可以
Android.mk 里面有需要编译的c/c++源文件,模块的名字要正确,这里的模块名字就是在java。loadLibrary时候需要的
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := JniTest
LOCAL_SRC_FILES := math.cpp
include $(BUILD_SHARED_LIBRARY) //表明是动态库
配置项目里的build.gradle
关键的有ndk和sourceSets 设置jni加载文件目录
ndk 是在defaultConfig 里面配置
moduleName第一个模块名字
ldLibs 在jni里面打印android log 日志
abiFilters 编译生成的平台类型
这里配置了,所以在Android.mk里面就不用配置加载日志,还有Application.mk 配置编译生成平台,如果配置了,build.gradle 的优先级也是最高的
4,创建jni的java的类
这里有2个native 方法,通过静态块加载动态so文件
package com.framework.ui.activity;
public class MathJNI {
static {
System.loadLibrary("JniTest");
}
public native String get();
public native void set(String name);
}
5,通过javah 生成c/c++的头部文件
javah在jdk的bin目录下面
这里的目录只能到debug下面,如果在其他目录会生成头文件失败
生成的头文件
com_framework_ui_activity_MathJNI.h 包名+类名
第二种方式
在app/src/main/java 通过命令生成 目录也只能到这里 ,目录在包里面就不行了
头文件生成了,就是为了实现头文件的方法,相当与java里面额接口定义了,要实现接口
6,在jni创建.c/.cpp文件名字随便
生成的头部文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_framework_ui_activity_MathJNI */
#ifndef _Included_com_framework_ui_activity_MathJNI
#define _Included_com_framework_ui_activity_MathJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_framework_ui_activity_MathJNI
* Method: get
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_framework_ui_activity_MathJNI_get
(JNIEnv *, jobject);
/*
* Class: com_framework_ui_activity_MathJNI
* Method: set
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_framework_ui_activity_MathJNI_set
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
把生成的头部文件内容复制到,.c/.cpp的文件里面
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <stdio.h> //导入文件
/* Header for class com_framework_ui_activity_MathJNI */
#include <android/log.h>//导入android日
#define TAG "my-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型
#ifndef _Included_com_framework_ui_activity_MathJNI
#define _Included_com_framework_ui_activity_MathJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_framework_ui_activity_MathJNI
* Method: get
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_framework_ui_activity_MathJNI_get
(JNIEnv *env, jobject jObj){
return env->NewStringUTF("Hello From JNI!");
}
/*
* Class: com_framework_ui_activity_MathJNI
* Method: set
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_framework_ui_activity_MathJNI_set
(JNIEnv *env, jobject jObj, jstring jstr) {
char *str = (char*)env->GetStringUTFChars(jstr,NULL);
LOGD("########## i = %s", str);
}
#ifdef __cplusplus
}
#endif
#endif
拷贝过来的时候需要修改的 方法加上{}括号,把参数改了正确,应为头部里面的定义的方法只有类型,没有类型的名字,在实现里面全部不全。
android 运行调用的结果
@Override
protected void initViewAndEvent() {
TLog.d(TAG_LOG, new MathJNI().get());
new MathJNI().set("test");
}
07-05 05:07:16.126 17678-17678/com.framework D/com.framework.ui.activity.FirstActivity: FirstActivity.java (31) initViewAndEvent: Hello From JNI!
07-05 05:07:16.126 17678-17678/com.framework D/my-jni: ########## i = test
在windows 上面会出现这个错误
Error:Execution failed for task ‘:app:compileDebugNdk’.
通过在jni目录创建一个空的utils.c或者utils.cpp都可以,编译就能通过了
jni的java对应的数据类型表 图来自android开发艺术探索