Android JNI开发

一、什么是jni

JNI java native interface native本地 java本地接口
通过JNI可以实现java和本地代码之间相互调用
jni可以看做是翻译 实际上就是一套协议

二、如何使用jni调用c的方法

这个比较简单,先生命native 方法

public native String stringFromJNI();

三、如何在c层调用java的方法

Android开发中一般讲Java接口调用放在APP层,但是如果想对外隐藏Java接口调用,应该怎么办呢?我们可以将接口调用放在JNI层,通过反射调用所需接口,之后打包成.so库,这样既可对外隐藏所有调用细节。下面开始讲解JNI怎么调用Java方法

1.生成测试类的class文件
package com.thomas;

import android.util.Log;

/**
 * Author:yangzhikuan
 * Date:2020-08-31
 * Description:JNITestClass
 */
public class JNITestClass {
    private final static String TAG = "JNITestClass";

    public JNITestClass(){
        Log.i(TAG, "JNITestClass");
    }

    public void test(int index) {
        Log.i(TAG, "test : " + index);
    }

    public static void testStatic(String str) {
        Log.i(TAG, "testStatic : " + str);
    }

    public static class InnerClass {
        private int num;
        public InnerClass() {
            Log.i(TAG, "InnerClass");
        }

        public void setInt(int n) {
            num = n;
            Log.i(TAG, "setInt: num = " + num);
        }
    }
}


2.进入class文件目录查看方法签名

这里首先Make Project,否则不会生成Java文件对应的class文件

进入到classpath目录下:
命令: cd app/build/intermediates/classes/debug

查看外部类的签名
javap -s -p JNITestClass

查看内部类的签名
javap -s -p JNITestClass$InnerClass


4EA2504C-7B3C-47EC-8D94-C6407D52131E.png
3.c代码中调用
JNIEXPORT void JNICALL Java_com_thomas_MainActivity_JNIReflect
(JNIEnv *env, jobject thiz)
{
    //实例化Test类
    jclass testclass = (*env)->FindClass(env, "com/thomas/JNITestClass");
    //构造函数的方法名为
    jmethodID testcontruct = (*env)->GetMethodID(env, testclass, "", "()V");
    //根据构造函数实例化对象
    jobject testobject = (*env)->NewObject(env, testclass, testcontruct);

![4EA2504C-7B3C-47EC-8D94-C6407D52131E.png](https://upload-images.jianshu.io/upload_images/9005980-72d764afa7531b67.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    //调用成员方法,需使用jobject对象
    jmethodID test = (*env)->GetMethodID(env, testclass, "test", "(I)V");
    (*env)->CallVoidMethod(env, testobject, test, 1);

    //调用静态方法
    jmethodID testStatic = (*env)->GetStaticMethodID(env, testclass, "testStatic", "(Ljava/lang/String;)V");
    //创建字符串,不能在CallStaticVoidMethod中直接使用"hello world!",会报错的
    jstring str = (*env)->NewStringUTF(env, "hello world!");
    //调用静态方法使用的是jclass,而不是jobject
    (*env)->CallStaticVoidMethod(env, testclass, testStatic, str);

    //实例化InnerClass子类
    jclass innerclass = (*env)->FindClass(env, "com/thomas/JNITestClass$InnerClass");
    jmethodID innercontruct = (*env)->GetMethodID(env, innerclass, "", "()V");
    jobject innerobject = (*env)->NewObject(env, innerclass, innercontruct);

    //调用子类的成员方法
    jmethodID setInt = (*env)->GetMethodID(env, innerclass, "setInt", "(I)V");
    (*env)->CallVoidMethod(env, innerobject, setInt, 2);
}
 //调用成员方法
    jmethodID testcontruct = (*env)->GetMethodID(env, testclass, "", "()V");
  //调用静态方法
    jmethodID testStatic = (*env)->GetStaticMethodID(env, testclass, "testStatic", "(Ljava/lang/String;)V");

注意:最后一个参数需要穿对应的签名

你可能感兴趣的:(Android JNI开发)