JNI开发流程

Java调用C代码

  1. 在Java中声明native方法
    创建一个类,类名可以根据自己情况起,代码如下:

    package xiaojiukeji.ndk002javaforc;
    /**
     * Created by mixiaojiu on 2019/10/25.
     */
    public class JNI {
        {
            System.loadLibrary("Hello");
        }
        public native int add(int x,int y);
        public native String sayHello(String s);
        public native int[] increaseArrayEles(int[] intArray);
        public native int checkPwd(String pwd);
    }
    

    我们可以看到上面的一行代码块:

     {
    	System.loadLibrary("Hello");
     }
    

    这个Hello是指相应调用的c/c++文件,整体目录如下
    在这里插入图片描述
    注意:红色箭头指向的即是Java所要调用的C文件名称,蓝色箭头指的是头文件名称,接下类马上就会提到。
    为了项目在运行过程中能够顺利进行,在项目的build.gradle中也要进行配置
    在这里插入图片描述
    这个moduleName中的“Hello”是本次demo测试里的.c文件的名称,这里不是一成不变的,换成所使用的即可,abiFilters中所提到的这三个,是调用硬件所需的,如果不配置,会造成某些设备上无法使用。

  2. 生成头文件
    编译Java的源文件,之后通过 javah 命令导出JNI的文件
    在这里插入图片描述
    生成头文件:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class xiaojiukeji_ndk002javaforc_JNI */

#ifndef _Included_xiaojiukeji_ndk002javaforc_JNI
#define _Included_xiaojiukeji_ndk002javaforc_JNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     xiaojiukeji_ndk002javaforc_JNI
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_xiaojiukeji_ndk002javaforc_JNI_add
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     xiaojiukeji_ndk002javaforc_JNI
 * Method:    sayHello
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_xiaojiukeji_ndk002javaforc_JNI_sayHello
  (JNIEnv *, jobject, jstring);

/*
 * Class:     xiaojiukeji_ndk002javaforc_JNI
 * Method:    increaseArrayEles
 * Signature: ([I)[I
 */
JNIEXPORT jintArray JNICALL Java_xiaojiukeji_ndk002javaforc_JNI_increaseArrayEles
  (JNIEnv *, jobject, jintArray);

/*
 * Class:     xiaojiukeji_ndk002javaforc_JNI
 * Method:    checkPwd
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_xiaojiukeji_ndk002javaforc_JNI_checkPwd
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

这里需要说明一下:首先函数名的格式遵循以下规则:
Java_包名_类名_方法名。
比如:Java_xiaojiukeji_ndk002javaforc_JNI_add很明显就是Java中的add方法

  • JNIEnv * :表示一个指向JNI环境的指针,可以通过它来访问JNI提供的接口方法
  • jobject: 表示Java中的对象this
  • jint,jstring:表示Java中的数据类型
  1. 实现JNI方法
    在所调用的Hello.c中所执行的方法如下:
/
// Created by mixiaojiu on 2019/10/25.
//
#include "xiaojiukeji_ndk002javaforc_JNI.h"
#include <string.h>
JNIEXPORT jint JNICALL Java_xiaojiukeji_ndk002javaforc_JNI_add(JNIEnv *env, jobject job, jint  intA, jint intB){
    return intA+intB;
}

JNIEXPORT jintArray JNICALL Java_xiaojiukeji_ndk002javaforc_JNI_increaseArrayEles(JNIEnv *env, jobject job, jintArray intArray){
    //1.得到数组的长度
    int size = (*env)->GetArrayLength(env,intArray);
    //2.得到数组元素
    jint* array=(*env)->GetIntArrayElements(env,intArray,JNI_FALSE);
    //3.遍历数组,给每个元素加10
    int i;
    for (int i = 0; i < size; ++i) {
        *(array+i)+=10;
    }
    return intArray;
}
JNIEXPORT jint JNICALL Java_xiaojiukeji_ndk002javaforc_JNI_checkPwd(JNIEnv *env, jobject jobj, jstring str){
    //比较字符串是否相同
    char* origin = "123456";
    return 200;
}

注意引用头文件:#include "xiaojiukeji_ndk002javaforc_JNI.h",这个即是引用的生成的调用的头文件,作为桥接

  1. 生成.so文件并在Java中调用
    还记得最开始的JNI文件的代码块吗?
{
	System.loadLibrary("Hello");
}

在这个地方引用所生成的.so文件,调用就是常规的调用即可了。创建一个该实例对象,饮用该对象中的JNI方法即可。
在这里插入图片描述
在这里插入图片描述
结果正常打印输出,很明显,我们的Java调用C代码的基本流程已经执行完毕。

C调用Java代码

JNI调用Java方法的流程是先通过类名找到类,然后再根据方法名找到方法的ID,最后就可以调用这个方法了。
  1. 在 java中声明native方法,不同的是,同时也要声明一些供c调用的java代码。
package xiaojiukeji.ndk003ccalljava;

import android.util.Log;

/**
 * Created by mixiaojiu on 2019/10/25.
 */
public class JNI {
    {
        System.loadLibrary("CCallJava");
    }
    /*
    //

    * */
    public native void callbackAdd();
    public native void callbackHelloFromJava();
    public native void callbackPrintString();
    public native void callbackSayHello();

    public int add(int x,int y){
        Log.d("JNI","x=y================");
        return x+y;
    }
    public void helloFromJava(){

        Log.d("JNI","helloFromJava================");
    }
    public void printString(String str){

        Log.d("JNI","printString================"+str);
    }
    public static void sayHello(String str){
        Log.d("JNI","sayHello================"+str);
    }

}
  1. 通过javah生成头文件
  2. 重点来了啊
    在这里插入图片描述
    1处是通过反射找到代码的.class文件实例,2是实例中的被调用的方法,3处是该方法所在的签名,缺一不可,然后通过callInMethod方法调用Java中的文件即可
  3. 这样就建立起了桥接,实例调用即可
JNI jni = new JNI();
jni.callbackAdd();

文笔较差,顺着思路走下来的,哪天有空了再调整调整。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值