说明:通过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的检测和功能调用