Jni 反射调用java静态方法

Jni 反射调用java静态方法

因为项目原因,项目中使用的是c来写的,需要在c中来设置SystemProperties,
所以需要在c中以反射的方式来设置,好在Jni支持

1.Native方法注册(使用的静态方法注册)

1.1在java中声明一个native方法

package com.liuhang.demo
public class Test{
    static {
        System.loadLibrary("Demo");
    }
    private native String Execute();
}

1.2 生成JNI方法

javac com\liuhang\demo\Test.java
javah com.liuhang.demo.Test
可以JNI	
/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class com_liuhang_demo_Test */

#ifndef _Included_com_liuhang_demo_Test
#define _Included_com_liuhang_demo_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_liuhang_demo_Test
 * Method:    Execute
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_liuhang_demo_Test_Execute
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

JNIEXPORT jstring JNICALL Java_com_liuhang_demo_Test_Execute
  (JNIEnv *, jobject) {
      return (*env)->NewStringUTF(env, '1');
};

返回String 这样编译出so库 ,引入进去即可
这样我们Execute方法就对应了起来。

2.如何反射调用

以项目中的某块代码为例

static jboolean getStatusBarState(JNIEnv *env) {
    constexpr Jchar CLASS[] = "android/os/SystemProperties";
    //Java的类的,全路径
    constexpr Jchar CLASS_GET_METHOD[] = "getBoolean";
    // 该类中的方法名
    constexpr Jchar CLASS_GET_METHOD_SIG[] = "(Ljava/lang/String;Z)Z";
    // 该方法的签名,即入参 出参
    // 查看某个方法的签名 javap -s -p XXX.class
    constexpr Jchar CLASS_GET_METHOD_KEY[] = "ro.settings.fix_statusbar";
    // 需要获取的某个属性
    // tunnel.decode ro.settings.fix_statusbar
    jclass systemPropertiesCls = nullptr;
    jmethodID systemPropertiesMothedGet = nullptr;
    jstring systemPropertiesMothedKey = nullptr;
    jboolean systemPropertiesMothedValue = false;
    if (env == nullptr)
        return true;
   		   // jni的方法 FindClass
           // jclass FindClass(const char* name)
    	   //{ return functions->FindClass(this, name); }
        if (systemPropertiesCls = (*env).FindClass(CLASS);systemPropertiesCls == nullptr)
            break;
           
           
			// jni 方法 查询静态方法
            //jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig)
    		//{ return functions->GetStaticMethodID(this, clazz, name, sig); }
        if (systemPropertiesMothedGet = (*env).GetStaticMethodID(
                    systemPropertiesCls,
                    CLASS_GET_METHOD,
                    CLASS_GET_METHOD_SIG
            );systemPropertiesMothedGet == nullptr)
            break;
            
        if (systemPropertiesMothedKey = (*env).NewStringUTF(CLASS_GET_METHOD_KEY);systemPropertiesMothedKey ==                                                                         nullptr) {
            break;
        }

  		// 获取静态方法的值 
        // jboolean    (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...);
        systemPropertiesMothedValue = (*env).CallStaticBooleanMethod(
                systemPropertiesCls,
                systemPropertiesMothedGet,
                systemPropertiesMothedKey,
                false
        );
      
    return systemPropertiesMothedValue;
}
这样就可以反射获取到相应的java方法

3.可以类比推广如何获取其他的值。

一下都是在jni.h 头文件中可以找到

 jobject     (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
 jobject     (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
 
 jobject     (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);

4.签名对应表

Java	Native	Signature
byte	jbyte	B
char	jchar	C
double	jdouble	D
float	jfloat	F
int		jint	I
short	jshort	S
long	jlong	J
boolean	jboolean	Z
void	void	V
// 数组这种格式
byte[]	jbyteArray	[B

具体的可以查看签名对应表

5 其他实现方式

可以查看Android JNI反射调用Java构造方法、成员方法和静态方法

你可能感兴趣的:(android)