天天看點

Kotlin書寫動态代理method.invoke(iam, *args) must not be null

文章目錄

    • 問題
      • 1.動态代理使用Kotlin書寫報錯
        • 描述
        • 思考
        • 解決

問題

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)
           

第二個參數變為*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)
           

思考

@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)

,參數正确,但依舊報第二個錯.

???

解決

解決毛,谷歌吹個毛的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時,為什麼可以