<strong>
</strong>
本章讲解so层怎么修改java层的变量,以及so层调用java层的方法,直接上代码.
package JNIEnvMethod;
public class JniDemo {
static {
System.load(
"F:\\HelloJava_Code_AndroidDecompilation\\_(一)Decompilation_testJNI\\libs\\lib_(一)JNIEnvMethods.dll");
}
String name = "~~";
String sex = "~~";
String age = "~~";
//
public static void main(String[] args) {
JniDemo mJniDemo = new JniDemo();
mJniDemo.BxlCPPMethod("My decompilation");
System.out.println("name:" + mJniDemo.name + "; sex:" + mJniDemo.sex + "; age:" + mJniDemo.age);
mJniDemo.awaitSoInvoke("java");
}
native void BxlCPPMethod(String jstr);
public void awaitSoInvoke(String param1) {
System.out.println(String.format("我被%s运行了", param1));
}
}
c++代码:
#include "jni.h"
//#include <string>
#include "JNIEnvMethod_JniDemo.h"
/** 本章解析:
*
* 本章内存比较简单,主要是说的
* 1.java字符串怎么转c++字符串
* 2.c++访问java层的全局变量
* 3.c++调用java层的方法
*
* 主要牵涉的方法有:
* Get***ID:获取方法 / 变量ID(需要对应的clazz/名字/签名)
* getObjectClass:其实也可以这样写:env->FindClass("JNIEnvMethod.JniDemo"); 其实就是一个反射!
* Call**Method: 调用java层方法
*
* jclass: 可以想成是java里面的反射, 通过他可以获取到该类里面所有的成员变量/方法, 但是不能对该变量/方法做任何的操作!为什么?因为你没有对象!没有实例!而方法的对象是谁?是jobject!
* jobject: 上面其实已经说了,jobject是java层的对象,谁调用谁对象!通过getobjectclass/findclass可获取到jclass,在结合jobject是不是就可以对参数对象实现调用 修改了?
*
* 方法签名:什么是方法签名?这么说吧,这个东西不用理解,死记就行,看多了就记住了.如果逆向过apk,应该就很好记,smail语法随处可见这东西
* 打个几个比方来说:(Ljava/lang/String;)V : 括号里面的"Ljava/lang/String;"说明方法的有一个参数String, "V"说明方法的返回值是void
* (Ljava/lang/String;)Ljava/lang/String; : 括号里面的"Ljava/lang/String;"说明方法的有一个参数String, "V"说明方法的返回值是String
* 可以这么想,方法签名就是 方法参数和方法返回值的一组特殊字符串,参数签名就是参数的类型!
* 签名对应表:boolean : Z
* char : c
* byte : B
* short : S
* int : I
* long : J
* float : F
* double : D
*
*
*/
/**
* 参数一:env 代表的是java环境!,可以想成是一个数组,里面装的全是方法,
* 参数二:obj 代表的是java层调用者的对象,谁调用的这个so,obj就代表谁的对象
* 参数三:jstr代表的是java层第一个参数
* 参数四:这里其实是没有参数四的. 如果有,它代表的是java层的第二个参数.
* 参数五:同上!
*/
JNIEXPORT void JNICALL Java_JNIEnvMethod_JniDemo_BxlCPPMethod(JNIEnv *env,
jobject obj, jstring jstr) {
/** 一:GetStringUTFChars方法:jstr转cstr并输出
*
*/
jsize jstrLength = env->GetStringLength(jstr);
const char *cstr = env->GetStringUTFChars(jstr, NULL);
printf("str:%s; length:%ld", cstr, jstrLength);
/** 二:获取java的全局变量并修改
*
* GetObjectClass:类似getClass();
* getXXXID类方法:此类方法可以获取java层的信息(全局变量 方法),其中参数三是字段签名,签名在最后讲;可以想成放射获取
*/
//修改字段name的值为caijincheng
jfieldID name = env->GetFieldID(env->GetObjectClass(obj), "name",
"Ljava/lang/String;");
char new_name[40] = "CaiJinCheng";
jstring nameValue = env->NewStringUTF(new_name);
env->SetObjectField(obj, name, nameValue);
//修改sex的字段为N
jfieldID sex = env->GetFieldID(env->GetObjectClass(obj), "sex",
"Ljava/lang/String;");
char new_sex[40] = "N";
jstring sexValue = env->NewStringUTF(new_sex);
env->SetObjectField(obj, sex, sexValue);
//设置age的字段为26
jfieldID age = env->GetFieldID(env->GetObjectClass(obj), "age",
"Ljava/lang/String;");
char new_age[40] = "26";
jstring ageValue = env->NewStringUTF(new_age);
env->SetObjectField(obj, age, ageValue);
/** 三.获取java层方法,并调用
*
* GetMethodID: 通过方法class/方法名/方法签名来获取java层方法的id.
* CallVoidMethod:通过方法id 和 class对象来调用java层的方法;
*/
jmethodID jawaitSoInvoke = env->GetMethodID(env->GetObjectClass(obj),
"awaitSoInvoke", "(Ljava/lang/String;)V");
char new_param[] = "c++";
jstring param1 = env->NewStringUTF(new_param);
env->CallVoidMethod(obj, jawaitSoInvoke, param1);
}
为了方便.上面的代码并没有在android环境上写,而是用的java环境,其实是一样的,或者说一模一样.