【问题标题】:Replacing Native Attributes with New Invocation Handler用新的调用处理程序替换本机属性
【发布时间】:2026-01-17 13:40:01
【问题描述】:

我想用从上一个问题收到的新调用处理程序替换本机覆盖方法。它在 setOnClickListener 崩溃,因为我不知道需要在 createProxyInstance 方法主体中返回什么作业。根据要求,针对此请求提出了一个新问题。请参考2年前的上一个问题。返回代理实例 jobject 接收到 setOnClickListener 的错误参数错误。 https://*.com/posts/comments/124247982?noredirect=1

Java

class MyInvocationHandler implements InvocationHandler {
    private long cfunc;
    MyInvocationHandler(long cfunc) { this.cfunc = cfunc; }
    @Override
    public native Object invoke(Object proxy, Method method, Object[] args);
}

class Activity extends Service {
    Object getProxy (MyInvocationHandler mih) {
        ClassLoader classLoader = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                return super.loadClass(name);
            }
        };
        return java.lang.reflect.Proxy.newProxyInstance(classLoader, new Class[] { }, mih);
    }
}

C++

typedef jobject (*CFunc)(JNIEnv *env, jobject obj, jobject proxy, jobject method, jobjectArray args);
extern "C" jobject Java_com_app_core_MyInvocationHandler_invoke(JNIEnv *env, jobject obj, jobject proxy, jobject method, jobjectArray args) {
    jclass cls_myIH = env->GetObjectClass(obj);
    jfieldID fld_myIH_cfunc = env->GetFieldID(cls_myIH, "cfunc", "J");
    CFunc cfunc = (CFunc)env->GetLongField(obj, fld_myIH_cfunc);
    cfunc(env, obj, proxy, method, args);
    return nullptr;
}

jobject createProxyInstance(JNIEnv *env, jclass cls, CFunc cfunc) {
    jclass cls_IH = env->FindClass("com/app/core/MyInvocationHandler");
    jmethodID cst_IH = env->GetMethodID(cls_IH, "<init>", "(J)V");
    jobject myIH = env->NewObject(cls_IH, cst_IH, (jlong)cfunc);

    jclass klass2 = env->FindClass("com/app/core/Activity");
    jmethodID method2 = env->GetMethodID(klass2, "getProxy", "(Lcom/app/core/MyInvocationHandler;)Ljava/lang/Object;");
    env->CallObjectMethod(continuedContext, method2, myIH);
}

jobject aa (JNIEnv *env, jobject obj, jobject proxy, jobject method, jobjectArray args) {
    __android_log_print(ANDROID_LOG_ERROR, "TEST", "SUCCESS");
}

void setListeners() {
    klass = env->FindClass("android/view/View");
    method = env->GetMethodID(klass, "setOnClickListener", "(Landroid/view/View$OnClickListener;)V");
    klass = env->FindClass("android/view/View$OnClickListener");
    env->CallVoidMethod(imageView, method, createProxyInstance(env, klass, &aa));
}

【问题讨论】:

  • 您创建一个新的类加载器而不是获取与您的Activity 关联的类加载器是否有特定原因? (Activity.class.getClassLoader())
  • 更多了解它。另一个我知道它不会伤害任何东西。

标签: android java-native-interface


【解决方案1】:

createProxyInstance 的返回值显然必须是对 getProxy 的调用,但您遗漏了一些重要的东西:setOnClickListener 需要一个实现 android/view/View$OnClickListener 接口的对象。

你已经把这个类传给createProxyInstance,所以你只需要把它传给getProxy

getProxy 更改为以下内容:

Object getProxy (MyInvocationHandler mih, Class<?> target) {
    ClassLoader classLoader = this.getClass().getClassLoader();
    return java.lang.reflect.Proxy.newProxyInstance(classLoader, new Class[] { target }, mih);
}

并修改createProxyInstance如下:

jobject createProxyInstance(JNIEnv *env, jclass cls, CFunc cfunc) {
    jclass cls_IH = env->FindClass("com/app/core/MyInvocationHandler");
    jmethodID cst_IH = env->GetMethodID(cls_IH, "<init>", "(J)V");
    jobject myIH = env->NewObject(cls_IH, cst_IH, (jlong)cfunc);

    jclass klass2 = env->FindClass("com/app/core/Activity");
    jmethodID method2 = env->GetMethodID(klass2, "getProxy", "(Lcom/app/core/MyInvocationHandler;Ljava/lang/Class;)Ljava/lang/Object;");
    return env->CallObjectMethod(continuedContext, method2, myIH, cls);
}

【讨论】:

  • 我的日志显示,但在调用方法后崩溃。并没有真正展示它到底是怎样的。
  • 我不明白你的评论。
  • 我在自己做的CFunc类型方法里面加了一个日志。当我单击我的图像时它显示,但后来它崩溃了。这显示在日志CheckJNI::DeleteRef 中。调用方法在错误堆栈中是最后一个。
  • 你真的希望任何人都能从错误的一句话描述中调试你的问题吗?
  • 好吧,当我得到代码时,我希望它被测试而不是我做所有的测试。您之前在另一个问题中的答案没有完整填写,让我来挑选点。我对这种类型的工作很陌生,希望能得到出色的工作/协助。