android jni 对java层的使用

 

说明:通过JNI在c++代码中实现java层的功能,以达到实现隐藏关键函数功能或入口的问题

 

1、使用的java类

package com.yuanrenxue.course6_4;

import android.util.Log;

import androidx.annotation.NonNull;

import java.util.Random;

public class MysteryBox extends MysteryParentBox {
    private static final String TAG = "yuanrenxue->";
    private final String content;
    private boolean isOpened;
    public final int price;
    private final String brand;
    private final static int BASE_PRICE = 10;

    public MysteryBox() {
        this.price = BASE_PRICE;
        this.brand = "手办盲盒";
        this.isOpened = false;
        int random = new Random().nextInt();
        if (random % 100 == 1) {
            this.content = "隐藏款";
        } else {
            this.content = "普通款";
        }
    }

    private MysteryBox(String brand) {
        this.price = 10;
        this.brand = brand;
        this.isOpened = false;
        int random = new Random().nextInt();
        if (random % 100 == 1) {
            this.content = "隐藏款";
        } else {
            this.content = "普通款";
        }
    }

    public MysteryBox(int price) {
        this.price = price;
        this.brand = "手办盲盒";
        this.isOpened = false;
        int p = 100;
        if (price > 100) {
            p = 10;
        }

        int random = new Random().nextInt();
        if (random % p == 1) {
            this.content = "隐藏款";
        } else {
            this.content = "普通款";
        }
    }

    public MysteryBox(int price, String brand) {
        this.price = price;
        this.brand = brand;
        this.isOpened = false;
        int random = new Random().nextInt();
        if (random % 100 == 1) {
            this.content = "隐藏款";
        } else {
            this.content = "普通款";
        }
    }


    private void close() {
        isOpened = false;
    }

    public void open() {
        isOpened = true;
    }

    public String getContent() {
        if (isOpened) {
            return content;
        } else {
            return "这个盲盒没有打开哦";
        }
    }

    public String getBrand() {


        return brand;
    }

    //静态方法hook
    public static String staticMethod(String name, int price) {
        Log.d(TAG, "staticMethod: name=" + name + ", price=" + price);
        return "我是静态方法变量";
    }

    //实例方法的book
    public String instanceMethod(String name, int price) {
        Log.d(TAG, "instanceMethod:  name=" + name + ", price=" + price);
        return "我是实例方法";
    }

    //内部类的hook
    static class InnerClass {
        private String innerClassMethod(String name, int price) {
            Log.d(TAG, "innerClassMethod:  name=" + name + ", price=" + price);
            return "我是内部类方法的返回值";

        }
    }

    //调用内部类的方法
    public void callInnerClassMethod() {
        InnerClass innerClass = new InnerClass();
        Log.d(TAG, "callInnerClassMethod: " + innerClass.innerClassMethod("王五", 1000));
    }

    @NonNull
    @Override
    public String toString() {
        return "MysteryBox{" +
                "content='" + content + '\'' +
                ", isOpened=" + isOpened +
                ", price=" + price +
                ", brand='" + brand + '\'' +
                '}';
    }
}

  

2、java层的入口

package com.yuanrenxue.course6_4;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.TextView;


public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }

    public static String test = "123";

    private static final String TAG = "yuanrenxue->";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.demo();
        Log.d(TAG, "onCreate: run sucess!!");


//        test = "456";
//        TextView viewById = findViewById(R.id.iv_content);
//        viewById.setText(nativeMethod());
//        MysteryBox box1 = new MysteryBox();
//        Log.d(TAG, "onCreate: " + box1.toString());
//
//        String result1 = MysteryBox.staticMethod("张三", 200);
//        Log.d(TAG, "onCreate: " + result1);
//
//        String reslut2 = box1.instanceMethod("李四", 600);
//        Log.d(TAG, "onCreate: " + reslut2);
//
//        box1.callInnerClassMethod();
//        Log.d(TAG, "onCreate: nativeMethod = " + nativeMethod());
//        String android_id = Settings.System.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);
//        Log.d(TAG, "getContentResolver: =" + this.getContentResolver().getClass().getName());
//        Log.d(TAG, "Settings.Secure.ANDROID_ID: =" + Settings.Secure.ANDROID_ID.getClass().getName());
//
////        @SuppressLint("HardwareIds") String android_id2 = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);
//        Log.d(TAG, "onCreate: android_id->" + android_id);

//        MysteryBox box2 = new MysteryBox(1000);
//        MysteryBox box3 = new MysteryBox(1000, "测试");
//        Log.d(TAG, "onCreate: price" + box2.price);
//        Log.d(TAG, "onCreate: price" + box3.price);
    }

    private native void demo();



}

 

 

3、在c++层实现调用

#include <jni.h>
#include <string>
#include <android/log.h>

//
// Created by 15155 on 2022/11/23.
//

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "yuanrenxue->", __VA_ARGS__)


extern "C"
JNIEXPORT void JNICALL
Java_com_yuanrenxue_course6_14_MainActivity_demo(JNIEnv *env, jobject thiz) {
    // TODO: implement demo()

    __android_log_print((int) 6, "yuanrenxue->", "run here.");
    __android_log_print((int) 6, "yuanrenxue->", "current jni version %d", env->GetVersion());
//    jint version = env->GetVersion(); 获取JNI 版本
//    JNI_VERSION_1_6;
    //#define JNI_VERSION_1_1 0x00010001
    //#define JNI_VERSION_1_2 0x00010002
    //#define JNI_VERSION_1_4 0x00010004
    //#define JNI_VERSION_1_6 0x00010006
    //类操作
    //1.获取对象Class jcalss  com.yuanrenxue.course6_4  MysteryBox
    jclass mysteryBoxClass = env->FindClass("com/yuanrenxue/course6_4/MysteryBox");
    jclass clsClazz = env->GetObjectClass(mysteryBoxClass);
    jmethodID jmethodId = env->GetMethodID(clsClazz, "getSimpleName", "()Ljava/lang/String;");
    auto className = (jstring) env->CallObjectMethod(mysteryBoxClass, jmethodId);
    const char *str = env->GetStringUTFChars(className, nullptr);
    LOGD("获取对象  MysteryBox_Class_Name == %s", str);
    // 2.获取一个类的父类
    jclass parentClass = env->GetSuperclass(mysteryBoxClass);
    clsClazz = env->GetObjectClass(parentClass);
    jmethodId = env->GetMethodID(clsClazz, "getSimpleName", "()Ljava/lang/String;");
    className = (jstring) env->CallObjectMethod(parentClass, jmethodId);
    str = env->GetStringUTFChars(className, nullptr);
    LOGD("获取一个类的父类  MysteryBox_Parent_Class_Name == %s",str);
    //3.判断类型1是否可以安全的转换为类型2
    jboolean IsAssignableFrom = env->IsAssignableFrom(mysteryBoxClass, parentClass);
    LOGD("判断类型1是否可以安全的转换为类型2  mysteryBoxClass IsAssignableFrom parentClass== %d", IsAssignableFrom);

    //对象操作
    //1.不通过构造函数生成对象
    jobject mysteryBoxCObject = env->AllocObject(mysteryBoxClass);
    jmethodID toString_methodID = env->GetMethodID(mysteryBoxClass, "toString",
                                                   "()Ljava/lang/String;");
    auto mysteryBoxCObject_toString_methodID = (jstring) env->CallObjectMethod(mysteryBoxCObject,
                                                                               toString_methodID);
    str = env->GetStringUTFChars(mysteryBoxCObject_toString_methodID, nullptr);
    LOGD("不通过构造函数生成对象  mysteryBoxCObject_toString_methodID== %s", str);

    //2.通过构造函数生成对象
    jmethodID initMethod = env->GetMethodID(mysteryBoxClass, "<init>", "()V");
    jobject MysteryObject2 = env->NewObject(mysteryBoxClass, initMethod);
    toString_methodID = env->GetMethodID(mysteryBoxClass, "toString",
                                         "()Ljava/lang/String;");
    auto MysteryObject2_toString_methodID = (jstring) env->CallObjectMethod(
            MysteryObject2,
            toString_methodID);
    str = env->GetStringUTFChars(MysteryObject2_toString_methodID, nullptr);
    LOGD("通过构造函数生成对象  mysteryBoxClass, <init>, ()V== %s", str);
    //3.根据对象获取对应的类
    mysteryBoxClass = env->GetObjectClass(mysteryBoxCObject);
    clsClazz = env->GetObjectClass(mysteryBoxClass);
    jmethodId = env->GetMethodID(clsClazz, "getSimpleName", "()Ljava/lang/String;");
    className = (jstring) env->CallObjectMethod(mysteryBoxClass, jmethodId);
    str = env->GetStringUTFChars(className, nullptr);
    LOGD("根据对象获取对应的类  MysteryBox_Class_Name == %s", str);
    //4.判断某个对象是否为特定的实例
    jboolean IsInstanceOf = env->IsInstanceOf(mysteryBoxCObject, mysteryBoxClass);
    LOGD("判断某个对象是否为特定的实例 IsInstanceOf == %hhu",IsInstanceOf);

    //属性操作
    //1.获取非静态成员属性的ID mysteryBoxCObject price
    jfieldID price_filed_id = env->GetFieldID(mysteryBoxClass, "price", "I");
    //2.获取非静态成员属性的值(方法的合集)
    jint price = env->GetIntField(MysteryObject2, price_filed_id);
    LOGD("获取非静态成员属性的值 price == %d",price);
    //3.设置非静态成员属性的值(方法的合集)
    env->SetIntField(MysteryObject2, price_filed_id, 20);
    price = env->GetIntField(MysteryObject2, price_filed_id);
    LOGD("设置非静态成员属性的值 price == %d",price);
    //4.获取静态成员属性的ID MysteryBox  BASE_PRICE
    jfieldID BASE_PRICE_filed_id = env->GetStaticFieldID(mysteryBoxClass, "BASE_PRICE", "I");
    //5.获取静态成员属性的值
    jint static_price = env->GetStaticIntField(mysteryBoxClass, BASE_PRICE_filed_id);
    LOGD("获取静态成员属性的值  BASE_PRICE == %d",static_price);
    //6.设置静态成员属性的值
    env->SetStaticIntField(mysteryBoxClass, BASE_PRICE_filed_id, 666);
    static_price = env->GetStaticIntField(mysteryBoxClass, BASE_PRICE_filed_id);
    LOGD("设置静态成员属性的值 BASE_PRICE == %d",static_price);

    //方法的操作  getContent
    //1.获取非静态方法id
    jmethodID getContentmethid = env->GetMethodID(mysteryBoxClass, "getContent",
                                                  "()Ljava/lang/String;");
    //2.调用非静态方法
    auto getContent = (jstring) env->CallObjectMethod(MysteryObject2, getContentmethid);
    str = env->GetStringUTFChars(getContent, nullptr);
    LOGD("调用非静态方法 getContent == %s",str);
    //3.获取静态方法id  staticMethod
    jmethodID staticMethodID = env->GetStaticMethodID(mysteryBoxClass, "staticMethod",
                                                      "(Ljava/lang/String;I)Ljava/lang/String;");
    //4.调用静态方法
    jstring jstring1 = env->NewStringUTF("hell word!");
    auto callstatic = (jstring) env->CallStaticObjectMethod(mysteryBoxClass, staticMethodID,
                                                            jstring1, 30);
    str = env->GetStringUTFChars(callstatic, nullptr);
    LOGD("调用静态方法 callstatic == %s", str);

/*
 * 2022-12-06 01:34:45.102 6536-6536/com.yuanrenxue.course6 D/yuanrenxue->: onCreate: run sucess!!
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: run here.
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: current jni version 65542
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取对象  MysteryBox_Class_Name == MysteryBox
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取一个类的父类  MysteryBox_Parent_Class_Name == MysteryParentBox
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 判断类型1是否可以安全的转换为类型2  mysteryBoxClass IsAssignableFrom parentClass== 1
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 不通过构造函数生成对象  mysteryBoxCObject_toString_methodID== MysteryBox{content='null', isOpened=false, price=0, brand='null'}
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 通过构造函数生成对象  mysteryBoxClass, <init>, ()V== MysteryBox{content='普通款', isOpened=false, price=10, brand='手办盲盒'}
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 根据对象获取对应的类  MysteryBox_Class_Name == MysteryBox
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 判断某个对象是否为特定的实例 IsInstanceOf == 1
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取非静态成员属性的值 price == 10
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 设置非静态成员属性的值 price == 20
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取静态成员属性的值  BASE_PRICE == 10
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 设置静态成员属性的值 BASE_PRICE == 666
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 调用非静态方法 getContent == 这个盲盒没有打开哦
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 D/yuanrenxue->: staticMethod: name=hell word!, price=30
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 调用静态方法 callstatic == 我是静态方法变量
 */
}

  

4、小结

   通过这样的方式在c++层实现了对java的检测和功能调用

 

posted @ 2022-12-08 02:44  山水无期  阅读(58)  评论(0编辑  收藏  举报