C调用Java代码 图文详解

环境搭建

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方法 

猜你喜欢

转载自blog.csdn.net/zaq977684/article/details/130742626