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的检测和功能调用