HTQ_QQ
 Introduction:  高仿腾讯 QQ 的一款 IM 软件,在界面上几乎与腾讯 QQ 一模一样,目前只实现了发送文本与表情的功能
 Tags:  
QQ-IM-聊天-腾讯-listview-下拉刷新-侧滑删除-slidingmenu-基于 C++模板函数与 Fluent API 设计的 JNI 反射库,极大的简化 JNI 反射调用。
设计目标
弱化数据类型概念,强化操作意图
在执行中间任何操作的时候无需关心数据类型,内部会依据传入的参数签名自动调用对应数据类型的原 JNI 函数,只需要在最终进行 get 操作与 set 操作时通过泛型指定数据类型
在执行中间操作时只需关注操作意图,即:
- 对什么操作:on
 - 操作什么:构造函数用 construct,域用 field,静态域用 staicField,函数调用用 call,静态函数调用用 staticCall
 - 最终目的:获取值用 get,修改值用 set
 
功能特性
基于 OOD 设计的 Fluent API:
int intField = Reflect::on(env, object).field("intField", "I").get<jint>(); // 获取 Filed Reflect::on(env, object).field("intField", "I").set<jint>(1); // 设置 Field jobject object = Reflect::on(env, "tech/huqi/jnioor/Sample").construct("()V").get<jobject>(); // 调用构造函数 jstring content = Reflect::on(env, object).call("toString","()Ljava/lang/String;").get<jstring>(); // 调用 toString 函数
完善的判空与异常检测逻辑
当执行 JNI 函数的 GetFieldID,GetMethodID,CallXxxMethod,CallStaticXxxMethod 调用时,如果获取的域,方法,调用的方法不存在时会抛出异常导致程序奔溃
这在对一些非官方系统(如非安卓原生,java 原生)的类进行 JNI 调用时很常见,比如 Xposed 检测,如果你的代码运行在一个未安装 Xposed 框架的机器上,那么关于 Xposed 的域,方法操作都会出现异常导致崩溃。所以一个健壮稳定的 JNI 调用一般类似这样:
jclass jcls_Sample = env->FindClass("tech/huqi/jnioor/Sample"); if (jcls_Sample != NULL) { jmethodID jmid_init = env->GetMethodID(jcls_Sample, "<init>", "()V"); if (jmid_init != NULL) { jobject job_Sample = env->NewObject(jcls_Sample, jmid_init); if (job_Sample != NULL) { jfieldID jfid_intField = env->GetFieldID(jcls_Sample, "intField", "I"); if (jfid_intField != NULL) { int intField = env->GetIntField(job_Sample, jfid_intField); // ...... 省略后续其他逻辑 } else { checkAndClearException(env);// 检测并清理异常 } } else { checkAndClearException(env);// 检测并清理异常 } } else { checkAndClearException(env);// 检测并清理异常 } } else { checkAndClearException(env);// 检测并清理异常 } env->DeleteLocalRef(jcls_Sample); // 释放局部引用即对三方框架的类进行 JNI 调用时进行判空或异常检测后再进行下一步操作,如果为空进行异常检测并清理,如果中间产生了一些临时局部引用,还需要释放局部引用。但这样做代码结构嵌套太深,不利于阅读与后期维护,虽然这种嵌套可以采用 goto 语句来避免
现在有了这个库,只需要这样就包含了上述代码的功能:
jobject object = Reflect::on(env, "tech/huqi/jnioor/Sample").construct("()V").get<jobject>(); if(object!=NULL){ int intField = Reflect::on(env, object).field("intField", "I").get<jint>(); }
示例
(以下示例基于文档最后的 Sample 类进行操作)
  // 获取非态域
  int intField = Reflect::on(env, object).field("intField", "I").get<jint>();
  long longField = Reflect::on(env, object).field("longField", "J").get<jlong>();
  float floatField = Reflect::on(env, object).field("floatField", "F").get<jfloat>();
  double doubleField = Reflect::on(env, object).field("doubleField", "D").get<jdouble>();
  jstring stringField = Reflect::on(env, object).field("stringField",
                                                           "Ljava/lang/String;").get<jstring>();
   // 获取静态域
   int staticIntField = Reflect::on(env, clazz).staticField("staticIntField",
                                                               "I").get<jint>();
   long staticLongField = Reflect::on(env, clazz).staticField("staticLongField",
                                                                 "J").get<jlong>();
   float staticFloatField = Reflect::on(env, clazz).staticField("staticFloatField",
                                                                   "F").get<jfloat>();
   double staticDoubleField = Reflect::on(env, clazz).staticField("staticDoubleField",
                                                                     "D").get<jdouble>();
   jstring staticStringField = Reflect::on(env, clazz).staticField("staticStringField",
                                                                      "Ljava/lang/String;").get<jstring>();
   // 设置非静态域
   Reflect::on(env, object).field("intField", "I").set<jint>(1);
   Reflect::on(env, object).field("longField", "J").set<jlong>(1);
   Reflect::on(env, object).field("floatField", "F").set<jfloat>(1.0f);
   Reflect::on(env, object).field("doubleField", "D").set<jdouble>(1.0);
   Reflect::on(env, object).field("stringField", "Ljava/lang/String;").set<jobject>(
              env->NewStringUTF("modify stringField value"));
   // 设置静态域
   Reflect::on(env, clazz).staticField("staticIntField", "I").set<jint>(1);
   Reflect::on(env, clazz).staticField("staticLongField", "J").set<jlong>(1);
   Reflect::on(env, clazz).staticField("staticFloatField", "F").set<jfloat>(1.0f);
   Reflect::on(env, clazz).staticField("staticDoubleField", "D").set<jdouble>(1.0);
   Reflect::on(env, clazz).staticField("staticStringField","Ljava/lang/String;").set<jobject>(
              env->NewStringUTF("modify staticStringField value"));
   // 调用构造函数
   jobject object = Reflect::on(env, clazz).construct("()V").get<jobject>();
   // 调用函数
   jstring content = Reflect::on(env, object).call("toString","()Ljava/lang/String;").get<jstring>();
Sample 类
public class Sample {
    private static final String TAG = "JniReflectSample";
    private int intField = 0;
    private static int staticIntField = 0;
    private long longField = 0;
    private static long staticLongField = 0;
    private float floatField = 0.1f;
    private static float staticFloatField = 0.1f;
    private double doubleField = 0.1;
    private static double staticDoubleField = 0.1;
    private String stringField = "this is a non-static String";
    private static String staticStringField = "this is a static String";
    public static native void nativePrint();
    public int getIntField() {
        return intField;
    }
    public long getLongField() {
        return longField;
    }
    public float getFloatField() {
        return floatField;
    }
    public double getDoubleField() {
        return doubleField;
    }
    public String getStringField() {
        return stringField;
    }
    @Override
    public String toString() {
        return "Sample{" +
                "intField=" + intField +
                ", longField=" + longField +
                ", floatField=" + floatField +
                ", doubleField=" + doubleField +
                ", stringField='" + stringField + '\'' +
                ", staticIntField=" + staticIntField +
                ", staticLongField=" + staticLongField +
                ", staticFloatField=" + staticFloatField +
                ", staticDoubleField=" + staticDoubleField +
                ", staticStringField='" + staticStringField + '\'' +
                '}';
    }
}
