美文网首页
Kotlin书写动态代理method.invoke(iam, *

Kotlin书写动态代理method.invoke(iam, *

作者: vpractical | 来源:发表于2018-11-27 17:44 被阅读0次

    [TOC]

    问题

    1.动态代理使用Kotlin书写报错

    描述

        Process: com.y.hookdemo, PID: 24014
        java.lang.IllegalArgumentException: method android.app.IActivityManager$Stub$Proxy.getActivityDisplayId argument 1 has type android.os.IBinder, got java.lang.Object[]
            at java.lang.reflect.Method.invoke(Native Method)
            at com.y.hookdemo.HookUtil$HookInvocationHandler.invoke(HookUtil.kt:121)
    
    • kotlin书写:
        private class HookInvocationHandler(private val iam: Any): InvocationHandler {
    
            @Throws(Throwable::class)
            override fun invoke(proxy: Any, method: Method, args: Array<Any>): Any {
                if (method.name.contains("startActivity")) {
                    Log.e("Hook", "IActivityManager动态代理的invoke方法,伪装intent")
                    for (i in args.indices) {
                        if (args[i] is Intent) {
                            val intent = args[i] as Intent
                            val proxyIntent = Intent(mContext, ProxyActivity::class.java)
                            proxyIntent.putExtra("intent", intent)
                            args[i] = proxyIntent
                            break
                        }
                    }
                }
                return method.invoke(iam, args)
            }
        }
    

    报错在 return method.invoke(iam, args) 这一行,用java写正常执行

    • java书写:
            private class HookInvocationHandler implements InvocationHandler {
    
            private Object iam;
    
            private HookInvocationHandler(Object iam) {
                this.iam = iam;
            }
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (method.getName().contains("startActivity")) {
                    Log.e("Hook", "IActivityManager动态代理的invoke方法,伪装intent");
                    for (int i = 0; i < args.length; i++) {
                        if (args[i] instanceof Intent) {
                            Intent intent = (Intent) args[i];
                            Intent proxyIntent = new Intent(mContext, ProxyActivity.class);
                            proxyIntent.putExtra("intent", intent);
                            args[i] = proxyIntent;
                            break;
                        }
                    }
                }
                return method.invoke(iam, args);
            }
        }
    

    将java通过as转为kotlin,这行变为

    return method.invoke(iam, *args)
    

    思考

        @CallerSensitive
        // Android-changed: invoke(Object, Object...) implemented natively.
        @FastNative
        public native Object invoke(Object obj, Object... args)
                throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
    

    反射api中Method的invoke方法接收可变长参数,在java中允许数组赋值给可变长参数Object... args,Kotlin中,数组是array,可变长参数类型是vararg,类型不一致,所以method.invoke(iam, args),是两个参数,第二个参数是数组,实际方法需要多个参数,第二个参数是IBinder,所以报第一个错。
    Kotlin中数组转为可变长参数,是通过前面加*,所以as把java转为kotlin后,变为method.invoke(iam, *args),参数正确,但依旧报第二个错.

    com.y.hookdemo E/AndroidRuntime: Error reporting crash
        java.lang.IllegalStateException: method.invoke(iam, *args) must not be null
            at com.y.hookdemo.HookUtil$HookInvocationHandler.invoke(HookUtil.kt:121)
            at java.lang.reflect.Proxy.invoke(Proxy.java:913)
    

    ???

    解决

    解决毛,谷歌吹个毛的java和kotlin可以一起用,改用java写了

    kotlin书写时,返回值是Any,方法可能是没有返回值的,所以修改为Any?,然后修改

    private class HookInvocationHandler(private val iam: Any): InvocationHandler {
    
            @Throws(Throwable::class)
            override fun invoke(proxy: Any, method: Method, args: Array<Any>): Any? {
                if (method.name.contains("startActivity")) {
                    Log.e("Hook", "IActivityManager动态代理的invoke方法,伪装intent")
                    for (i in args.indices) {
                        if (args[i] is Intent) {
                            val intent = args[i] as Intent
                            val proxyIntent = Intent(mContext, ProxyActivity::class.java)
                            proxyIntent.putExtra("intent", intent)
                            args[i] = proxyIntent
                            break
                        }
                    }
                }
                val res = method.invoke(iam, *args)
                Log.e("------a1:${method.name}",args.size.toString())
                Log.e("res = ",res?.toString() + "--")
                Log.e("returnType:",method.genericReturnType.typeName)
                return if("void" == method.genericReturnType.typeName) Unit else res
            }
        }
    

    正常运行

    • 新的问题
      java书写时返回值为Object,执行没有返回值的method时,为什么可以

    相关文章

      网友评论

          本文标题:Kotlin书写动态代理method.invoke(iam, *

          本文链接:https://www.haomeiwen.com/subject/lbknqqtx.html