环境搭建
1. android studio2021.2.1
2. JDK版本1.8
一、创建一个android项目
File ——> New ——> New Project ——> Empty Activity
创建后如下图所示
二、C调用java代码过程
2.1 写java类代码
创建一个java的JNI类,写触发C代码,让C调用java的cCallJava()方法
/**
* 触发C代码让其调用cCallJava()方法
*/
public native void callbackCCallJava();
public void cCallJava(){
System.out.println("C调用到了java的方法cCallJava");
}
2.2 生成对应的C代码的头文件
(1)AS打开Terminal窗口
点击底部导航栏Terminal
(2) 用命令打开JNI类所在的目录
在Terminal窗口中输入cd app\src\main\java\com\zaq\ccalljava,按键盘Enter键
(3)用命令生成头文件
javac -encoding utf8 -h . JNI.java(注意:-encoding utf8 指定源文件编码格式,-h后面有个点, 点 前后面都有个空格,点的意思是头文件生成在当前目录下)
执行后过会会自动生成一个jni头文件com_zaq_ccalljave_JNI.h,如下图所示:
2.3 设置编译方式ndk-build相关配置
(1)在main下创建一个jni文件夹
(2) 把头文件移到jni文件夹下,删除JNI.class
(3)在jni下创建C/C++ Source File,命名为Test.c。
(4)在jni下创建文件Android.mk
Android.mk里面的内容
#表示Android.mk所在目录
LOCAL_PATH := $(call my-dir)
#CLEAR_VARS变量指向特殊 GNU Makefile,用于清除部分LOCAL_变量
include $(CLEAR_VARS)
#模块名称
LOCAL_MODULE := javacallc
#构建系统用于生成模块的源文件列表
LOCAL_SRC_FILES := Test.c
#BUILD_SHARED_LIBRARY 表示.so动态库
#BUILD_STATIC_LIBRARY 表示.a静态库
include $(BUILD_SHARED_LIBRARY)
(5)在gradle.build中的配置,生成so库文件
①android里面的defaultConfig配置
//定义ndkBuild默认配置属性
externalNativeBuild {
ndkBuild {
cppFlags ""
}
}
ndk {
// 生成指定CPU平台对应的so库文件
abiFilters "arm64-v8a"
}
②跟defaultConfig同级的配置
//定义ndkBuild对应的Android.mk路径(重要)
externalNativeBuild {
ndkBuild{
path file("src/main/jni/Android.mk")
}
}
查看so生成文件
重新Rebuild Project,即点击状态栏的 File ——> Rebuild Project
so文件的最终命名是lib+ccalljava(Android,mk文件里面的模块名称).so,即:libccalljava.so
最终生成so库文件的路径如下:
2.4 T代码的实现
(1)Test.c代码实现调用java方法
#include "com_zaq_ccalljava_JNI.h"
#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
/**
* 调用java代码中JNI类里面的public void cCallJava()
* @param env
* @param jobj
*/
JNIEXPORT void JNICALL Java_com_zaq_ccalljava_JNI_callbackCCallJava
(JNIEnv *env, jobject jobj){
// 1.得到字节码
// jclass (*FindClass)(JNIEnv*, const char*);
jclass jclazz=(*env)->FindClass(env,"com/zaq/ccalljava/JNI");
// 2.得到方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
jmethodID jmethodIDs=(*env)->GetMethodID(env,jclazz,"cCallJava", "()V");
// 3.实例化该类
// jobject (*AllocObject)(JNIEnv*, jclass);
jobject obj=(*env)->AllocObject(env,jclazz);
// 4.调用方法
// void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env,obj,jmethodIDs);// 可成功调用JNI类中的public void cCallJava()
}
(2)MainActivity调动JNI类的方法
(3)JNI类加载so文件
(4)运行安装apk,点击按钮有日志输出,说明C成功调用java方法