All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.didichuxing.doraemonkit.plugin.classtransformer.CommClassTransformer.kt Maven / Gradle / Ivy

Go to download

DoKit is an efficiency platform for the entire life cycle of general front-end product research and development.

There is a newer version: 3.7.11
Show newest version
package com.didichuxing.doraemonkit.plugin.classtransformer

import com.didichuxing.doraemonkit.plugin.*
import com.didichuxing.doraemonkit.plugin.extension.SlowMethodExt
import com.didiglobal.booster.annotations.Priority
import com.didiglobal.booster.kotlinx.asIterable
import com.didiglobal.booster.transform.TransformContext
import com.didiglobal.booster.transform.asm.ClassTransformer
import com.didiglobal.booster.transform.asm.className
import com.google.auto.service.AutoService
import org.objectweb.asm.Label
import org.objectweb.asm.Opcodes.*
import org.objectweb.asm.tree.*

/**
 * ================================================
 * 作    者:jint(金台)
 * 版    本:1.0
 * 创建日期:2020/5/14-18:07
 * 描    述:wiki:https://juejin.im/post/5e8d87c4f265da47ad218e6b
 * 修订历史:
 * ================================================
 */
//@Priority(0)
//@AutoService(ClassTransformer::class)
class CommClassTransformer : AbsClassTransformer() {


    private val SHADOW_URL =
        "com/didichuxing/doraemonkit/aop/urlconnection/HttpUrlConnectionProxyUtil"
    private val DESC = "(Ljava/net/URLConnection;)Ljava/net/URLConnection;"


    /**
     * 转化
     */
    override fun transform(context: TransformContext, klass: ClassNode): ClassNode {

        if (onCommInterceptor(context, klass)) {
            return klass
        }


        val className = klass.className
        val superName = klass.formatSuperName

//        if (className.contains("didihttp")) {
//            "${context.projectDir.lastPath()}==className===>$className".println()
//        }

        //查找DoraemonKitReal&pluginConfig方法并插入指定字节码
        if (className == "com.didichuxing.doraemonkit.DoKitReal") {
            //插件配置
            klass.methods?.find {
                it.name == "pluginConfig"
            }.let { methodNode ->
                "${context.projectDir.lastPath()}->insert map to the DoKitReal pluginConfig succeed".println()
                methodNode?.instructions?.insert(createPluginConfigInsnList())
            }
            //三方库信息注入
            klass.methods?.find {
                it.name == "initThirdLibraryInfo"
            }.let { methodNode ->
                "${context.projectDir.lastPath()}->insert map to the DoKitReal initThirdLibraryInfo succeed".println()
                methodNode?.instructions?.insert(createThirdLibInfoInsnList())
            }
        }

        //gps字节码操作
        if (DoKitExtUtil.commExt.gpsSwitch && DoKitExtUtil.DOKIT_GPS_MOCK_INCLUDE) {
            //系统 gpsStatus hook
            klass.methods.forEach { method ->
                method.instructions?.iterator()?.asIterable()
                    ?.filterIsInstance(MethodInsnNode::class.java)?.filter {
                        it.opcode == INVOKEVIRTUAL &&
                            it.owner == "android/location/LocationManager" &&
                            it.name == "getGpsStatus" &&
                            it.desc == "(Landroid/location/GpsStatus;)Landroid/location/GpsStatus;"
                    }?.forEach {
                        "${context.projectDir.lastPath()}->hook LocationManager#getGpsStatus method  succeed in : ${className}_${method.name}_${method.desc}".println()
                        method.instructions.insert(
                            it,
                            MethodInsnNode(
                                INVOKESTATIC,
                                "com/didichuxing/doraemonkit/gps_mock/location/GpsStatusUtil",
                                "wrap",
                                "(Landroid/location/GpsStatus;)Landroid/location/GpsStatus;",
                                false
                            )
                        )
                    }
            }

            //插入高德地图定位相关字节码
            if (className == "com.amap.api.location.AMapLocationClient") {
                //设置监听器
                klass.methods?.find {
                    it.name == "setLocationListener"
                }.let { methodNode ->
                    "${context.projectDir.lastPath()}->hook amap map  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
                    methodNode?.instructions?.insert(createAmapLocationInsnList())
                }

                //反注册监听器
                klass.methods?.find {
                    it.name == "unRegisterLocationListener"
                }.let { methodNode ->
                    "${context.projectDir.lastPath()}->hook amap map  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
                    methodNode?.instructions?.getMethodExitInsnNodes()?.forEach {
                        methodNode.instructions.insertBefore(
                            it,
                            createAmapLocationUnRegisterInsnList()
                        )
                    }
                }

                //代理getLastKnownLocation
                klass.methods?.find {
                    it.name == "getLastKnownLocation"
                }.let { methodNode ->
                    "${context.projectDir.lastPath()}->hook AMapLocationClient getLastKnownLocation  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
                    methodNode?.instructions?.insert(createAMapClientLastKnownLocation())
                }

            }
            //插入高德 地图定位相关字节码
//            if (className == "com.amap.api.maps.AMap") {
//                //设置LocationSource代理
//                klass.methods?.find {
//                    it.name == "setLocationSource"
//                }.let { methodNode ->
//                    "${context.projectDir.lastPath()}->hook amap map LocationSource  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
//                    methodNode?.instructions?.insert(createAmapLocationSourceInsnList())
//                }
//            }

            //插入高德地图导航相关字节码
            if (className == "com.amap.api.navi.AMapNavi") {
                //设置监听器
                klass.methods?.find {
                    it.name == "addAMapNaviListener"
                }.let { methodNode ->
                    "${context.projectDir.lastPath()}->hook amap map navi  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
                    methodNode?.instructions?.insert(createAmapNaviInsnList())
                }
//
//                //反注册监听器
                klass.methods?.find {
                    it.name == "removeAMapNaviListener"
                }.let { methodNode ->
                    "${context.projectDir.lastPath()}->hook amap map navi  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
                    methodNode?.instructions?.getMethodExitInsnNodes()?.forEach {
                        methodNode.instructions.insertBefore(
                            it,
                            createAmapNaviUnRegisterInsnList()
                        )
                    }
                }
            }


            //插入腾讯地图相关字节码
            if (className == "com.tencent.map.geolocation.TencentLocationManager") {
                //持续定位和单次定位
                klass.methods?.filter {
                    it.name == "requestSingleFreshLocation" || it.name == "requestLocationUpdates"
                }?.forEach { methodNode ->
                    "${context.projectDir.lastPath()}->hook tencent map  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
                    methodNode?.instructions?.insert(createTencentLocationInsnList())
                }


                //反注册监听器
                klass.methods?.find {
                    it.name == "removeUpdates"
                }.let { methodNode ->
                    "${context.projectDir.lastPath()}->hook tencent map  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
                    methodNode?.instructions?.getMethodExitInsnNodes()?.forEach {
                        methodNode.instructions.insertBefore(
                            it,
                            createTencentLocationUnRegisterInsnList()
                        )
                    }
                }
            }

            //插入百度地图相关字节码
            if (className == "com.baidu.location.LocationClient") {
                //拦截注册监听器
                klass.methods?.filter {
                    it.name == "registerLocationListener"
                        && (it.desc == "(Lcom/baidu/location/BDLocationListener;)V" || it.desc == "(Lcom/baidu/location/BDAbstractLocationListener;)V")
                }?.forEach { methodNode ->
                    "${context.projectDir.lastPath()}->hook baidu map  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
                    if (methodNode.desc == "(Lcom/baidu/location/BDLocationListener;)V") {
                        methodNode?.instructions?.insert(createBDLocationListenerInsnList())
                    } else if (methodNode.desc == "(Lcom/baidu/location/BDAbstractLocationListener;)V") {
                        methodNode?.instructions?.insert(createBDLocationAbsListenerInsnList())
                    }
                }


                //反注册监听器
                klass.methods?.find {
                    it.name == "unRegisterLocationListener" && it.desc == "(Lcom/baidu/location/BDLocationListener;)V"
                }.let { methodNode ->
                    "${context.projectDir.lastPath()}->hook baidu map  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
                    methodNode?.instructions?.getMethodExitInsnNodes()?.forEach {
                        methodNode.instructions.insertBefore(
                            it,
                            createBDLocationUnRegisterInsnList()
                        )
                    }
                }


                //反注册监听器
                klass.methods?.find {
                    it.name == "unRegisterLocationListener" && it.desc == "(Lcom/baidu/location/BDAbstractLocationListener;)V"
                }.let { methodNode ->
                    "${context.projectDir.lastPath()}->hook baidu map  succeed: ${className}_${methodNode?.name}_${methodNode?.desc}".println()
                    methodNode?.instructions?.getMethodExitInsnNodes()?.forEach {
                        methodNode.instructions.insertBefore(
                            it,
                            createBDAbsLocationUnRegisterInsnList()
                        )
                    }
                }
            }
        }


        //网络 OkHttp&didi platform aop
        if (DoKitExtUtil.commExt.networkSwitch) {
            //hook OkhttpClient
            if (className == "okhttp3.OkHttpClient") {
                klass.methods?.find {
                    it.name == "" && it.desc != "()V"
                }.let {
                    "${context.projectDir.lastPath()}->hook OkhttpClient  succeed: ${className}_${it?.name}_${it?.desc}".println()
                    it?.instructions
                        ?.iterator()
                        ?.asIterable()
                        ?.filterIsInstance(FieldInsnNode::class.java)
                        ?.filter { fieldInsnNode ->
                            fieldInsnNode.opcode == PUTFIELD
                                && fieldInsnNode.owner == "okhttp3/OkHttpClient"
                                && fieldInsnNode.name == "networkInterceptors"
                                && fieldInsnNode.desc == "Ljava/util/List;"
                        }?.forEach { fieldInsnNode ->
                            it.instructions.insert(fieldInsnNode, createOkHttpClientInsnList())
                        }
                }
            }

            //didi platform 判断是否引入了dokit-rpc模块
            if (className == "didihttp.DidiHttpClient" && DoKitExtUtil.commExt.didinetSwitch && DoKitExtUtil.HAS_DOKIT_RPC_MODULE) {
                klass.methods?.find {
                    it.name == "" && it.desc != "()V"
                }.let {
                    "${context.projectDir.lastPath()}->hook DidiHttpClient  succeed: ${className}_${it?.name}_${it?.desc}".println()
                    it?.instructions
                        ?.iterator()
                        ?.asIterable()
                        ?.filterIsInstance(FieldInsnNode::class.java)
                        ?.filter { fieldInsnNode ->
                            fieldInsnNode.opcode == PUTFIELD
                                && fieldInsnNode.owner == "didihttp/DidiHttpClient"
                                && fieldInsnNode.name == "networkInterceptors"
                                && fieldInsnNode.desc == "Ljava/util/List;"
                        }
                        ?.forEach { fieldInsnNode ->
                            it.instructions.insert(
                                fieldInsnNode,
                                createDidiHttpClientInsnList()
                            )
                        }
                }
            }


            //hook tcp 支持tcp消息hook
            if (className == "com.didi.daijia.tcp.message.MessageSender") {
                klass.methods?.find {
                    it.name == "sendMessage" && it.desc == "(Ljava/lang/String;)Z"
                }.let {
                    "${context.projectDir.lastPath()}->hook tcp MessageSender succeed: ${className}_${it?.name}_${it?.desc}".println()
                    val first = it?.instructions?.first
                    if (first != null) {
                        it.instructions.insert(first, createMessageSenderHookInsnList())
                    }
                }
            }
            if (className == "com.didi.daijia.tcp.message.MessageReceiver") {
                klass.methods?.find {
                    it.name == "channelRead" && it.desc == "(Ljava/lang/Object;)V"
                }.let {
                    "${context.projectDir.lastPath()}->hook tcp MessageReceiver succeed: ${className}_${it?.name}_${it?.desc}".println()
                    val first = it?.instructions?.first
                    if (first != null) {
                        it.instructions.insert(first, createMessageReceiverHookInsnList())
                    }
                }
            }


            //webView 字节码操作
            if (DoKitExtUtil.commExt.webViewSwitch) {
                //普通的webview
                klass.methods.forEach { method ->
                    method.instructions?.iterator()?.asIterable()
                        ?.filterIsInstance(MethodInsnNode::class.java)?.filter {
                            if ("loadUrl".equals(it.name)) {
                                "hook loadUrl() all ${className} ^${superName}^${it.owner} :: ${it.name} , ${it.desc} ,${it.opcode}".println()
                            }
                            (it.opcode == INVOKEVIRTUAL || it.opcode == INVOKESPECIAL) &&
                                it.name == "loadUrl" &&
                                (it.desc == "(Ljava/lang/String;)V" || it.desc == "(Ljava/lang/String;Ljava/util/Map;)V") &&
                                isWebViewOwnerNameMatched(it.owner)
                        }?.forEach {
                            "${context.projectDir.lastPath()}->hook WebView#loadurl method  succeed in :  ${className}_${method.name}_${method.desc} | ${it.owner}".println()
                            if (it.desc == "(Ljava/lang/String;)V") {
                                method.instructions.insertBefore(
                                    it,
                                    createWebViewInsnList()
                                )
                            } else {
                                val size = method.localVariables.size
                                val insn = with(InsnList()) {
                                    add(VarInsnNode(ASTORE, size + 1))
                                    add(VarInsnNode(ASTORE, size))
                                    add(InsnNode(DUP))
                                    add(
                                        MethodInsnNode(
                                            INVOKESTATIC,
                                            "com/didichuxing/doraemonkit/aop/WebViewHook",
                                            "inject",
                                            "(Ljava/lang/Object;)V",
                                            false
                                        )
                                    )
                                    add(VarInsnNode(ALOAD, size))
                                    add(
                                        MethodInsnNode(
                                            INVOKESTATIC,
                                            "com/didichuxing/doraemonkit/aop/WebViewHook",
                                            "getSafeUrl",
                                            "(Ljava/lang/String;)Ljava/lang/String;",
                                            false
                                        )
                                    )
                                    add(VarInsnNode(ALOAD, size + 1))
                                    this
                                }
                                method.instructions.insertBefore(it, insn)
                            }

                        }
                }
            }

            // url connection
            klass.methods.forEach { method ->
                method.instructions?.iterator()?.asIterable()
                    ?.filterIsInstance(MethodInsnNode::class.java)?.filter {
                        it.opcode == INVOKEVIRTUAL &&
                            it.owner == "java/net/URL" &&
                            it.name == "openConnection" &&
                            it.desc == "()Ljava/net/URLConnection;"
                    }?.forEach {
                        "${context.projectDir.lastPath()}->hook URL#openConnection method  succeed in : ${className}_${method.name}_${method.desc}".println()
                        method.instructions.insert(
                            it,
                            MethodInsnNode(INVOKESTATIC, SHADOW_URL, "proxy", DESC, false)
                        )
                    }
            }

        }


        //hook Androidx的ComponentActivity
        if (className != "com.didichuxing.doraemonkit.aop.mc.DoKitProxyActivity" && superName == "android.app.Activity") {
            createComponentActivitySuperActivityImpl(klass)
        }


        //hook androidx的AppCompatDelegateImpl
//        if (className == "androidx.appcompat.app.AppCompatDelegate") {
//            klass.methods?.filter {
//                it.name == "create"
//                        && (it.desc == "(Landroid/app/Activity;Landroidx/appcompat/app/AppCompatCallback;)Landroidx/appcompat/app/AppCompatDelegate;"
//                        || it.desc == "(Landroid/app/Dialog;Landroidx/appcompat/app/AppCompatCallback;)Landroidx/appcompat/app/AppCompatDelegate;"
//                        || it.desc == "(Landroid/content/Context;Landroid/view/Window;Landroidx/appcompat/app/AppCompatCallback;)Landroidx/appcompat/app/AppCompatDelegate;"
//                        || it.desc == "(Landroid/content/Context;Landroid/app/Activity;Landroidx/appcompat/app/AppCompatCallback;)Landroidx/appcompat/app/AppCompatDelegate;")
//            }?.asIterable()
//                ?.forEach { methodNode ->
//                    //操作方法
//                    val typeInsnNodes = methodNode.instructions
//                        ?.iterator()
//                        ?.asIterable()
//                        ?.filterIsInstance(TypeInsnNode::class.java)
//                    //操作New指令
//                    typeInsnNodes?.filter {
//                        it.opcode == NEW && it.desc == "androidx/appcompat/app/AppCompatDelegateImpl"
//                    }?.forEach {
//                        "${context.projectDir.lastPath()}->hook ${klass.name}-${methodNode.name}-${it.opcode}-${it.desc} succeed".println()
//                        methodNode.instructions.insertBefore(
//                            it,
//                            createNewDoKitAppCompatDelegateImplInsnList()
//                        )
//                    }
//
//                    //操作方法
//                    val methodInsnNodes = methodNode.instructions
//                        ?.iterator()
//                        ?.asIterable()
//                        ?.filterIsInstance(MethodInsnNode::class.java)
//
//                    methodInsnNodes?.filter {
//                        //"${context.projectDir.lastPath()}->hook AppCompatDelegate create matched ${it.opcode}  ${it.ownerClassName}  ${it.name}".println()
//                        it.opcode == INVOKESPECIAL
//                                && it.ownerClassName == "androidx.appcompat.app.AppCompatDelegateImpl"
//                                && it.name == ""
//                    }?.forEach {
//                        //"${context.projectDir.lastPath()}->hook AppCompatDelegate create  method succeed".println()
//                        "${context.projectDir.lastPath()}->hook ${klass.name}-${methodNode.name}-${it.owner}-${it.name}-${it.desc} succeed".println()
//                        methodNode.instructions.insert(
//                            it,
//                            MethodInsnNode(
//                                INVOKESPECIAL,
//                                "androidx/appcompat/app/DoKitAppCompatDelegateImpl",
//                                "",
//                                "(Landroidx/appcompat/app/AppCompatDelegate;)V",
//                                false
//                            )
//                        )
//                    }
//                }
//        }

        //hook 所有的view的事件
//        klass.methods?.forEach { methodNode ->
//            if (methodNode.name == "onClick" && methodNode.desc == "(Landroid/view/View;)V") {
//                val insnList = with(InsnList()) {
//                    add(VarInsnNode(ALOAD, 1))
//                    add(
//                        MethodInsnNode(
//                            INVOKESTATIC,
//                            "com/didichuxing/doraemonkit/aop/mc/DoKitListenerHelper",
//                            "hookViewClickListener",
//                            "(Landroid/view/View;)V",
//                            false
//                        )
//                    )
//                    this
//                }
//                methodNode.instructions.insert(insnList)
//            }
//        }


        // hook 所有的View
//        if (className != "com.didichuxing.doraemonkit.aop.mc.DoKitProxyView" && superName == "android.view.View") {
//            createViewImpl(klass)
//        }

        // hook 所有的ViewGroup
//        if (className != "com.didichuxing.doraemonkit.aop.mc.DoKitProxyViewGroup" && superName == "android.view.ViewGroup") {
//            createViewGroupImpl(klass)
//        }

//        if (className == "androidx.appcompat.app.AppCompatDelegateImpl") {
//            //插件配置
//            klass.methods?.find {
//                it.name == "onCreateView" && it.desc == "(Landroid/view/View;Ljava/lang/String;Landroid/content/Context;Landroid/util/AttributeSet;)Landroid/view/View;"
//            }.let { method ->
//                method?.instructions?.iterator()?.asIterable()
//                    ?.filterIsInstance(MethodInsnNode::class.java)?.filter {
//                        it.opcode == INVOKEVIRTUAL &&
//                                it.owner == "androidx/appcompat/app/AppCompatDelegateImpl" &&
//                                it.name == "createView" &&
//                                it.desc == "(Landroid/view/View;Ljava/lang/String;Landroid/content/Context;Landroid/util/AttributeSet;)Landroid/view/View;"
//                    }?.forEach {
//                        "${context.projectDir.lastPath()}->hook AppCompatDelegateImpl onCreateView method succeed".println()
//                        method.instructions.insert(
//                            it,
//                            MethodInsnNode(
//                                INVOKESTATIC,
//                                "com/didichuxing/doraemonkit/aop/mc/AppCompatDelegateImplProxy",
//                                "onCreateView",
//                                "(Landroid/view/View;)Landroid/view/View;",
//                                false
//                            )
//                        )
//                    }
//            }
//        }

        return klass
    }

    private fun isWebViewOwnerNameMatched(ownerName: String): Boolean {
        return ownerName == "android/webkit/WebView" ||
            ownerName == "com/tencent/smtt/sdk/WebView" ||
            ownerName.contentEquals("WebView") ||
            ownerName == DoKitExtUtil.WEBVIEW_CLASS_NAME
    }


    /**
     * 创建pluginConfig代码指令
     */
    private fun createPluginConfigInsnList(): InsnList {
        //val insnList = InsnList()
        return with(InsnList()) {
            //new HashMap
            add(TypeInsnNode(NEW, "java/util/HashMap"))
            add(InsnNode(DUP))
            add(MethodInsnNode(INVOKESPECIAL, "java/util/HashMap", "", "()V", false))
            //保存变量
            add(VarInsnNode(ASTORE, 0))
            //获取第一个变量
            //put("dokitPluginSwitch",true)
            add(VarInsnNode(ALOAD, 0))
            add(LdcInsnNode("dokitPluginSwitch"))
            add(InsnNode(if (DoKitExtUtil.dokitPluginSwitchOpen()) ICONST_1 else ICONST_0))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "java/lang/Boolean",
                    "valueOf",
                    "(Z)Ljava/lang/Boolean;",
                    false
                )
            )
            add(
                MethodInsnNode(
                    INVOKEINTERFACE,
                    "java/util/Map",
                    "put",
                    "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                    true
                )
            )
            add(InsnNode(POP))

            //put("gpsSwitch",true)
            add(VarInsnNode(ALOAD, 0))
            add(LdcInsnNode("gpsSwitch"))
            add(InsnNode(if (DoKitExtUtil.commExt.gpsSwitch) ICONST_1 else ICONST_0))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "java/lang/Boolean",
                    "valueOf",
                    "(Z)Ljava/lang/Boolean;",
                    false
                )
            )
            add(
                MethodInsnNode(
                    INVOKEINTERFACE,
                    "java/util/Map",
                    "put",
                    "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                    true
                )
            )
            add(InsnNode(POP))

            //put("networkSwitch",true)
            add(VarInsnNode(ALOAD, 0))
            add(LdcInsnNode("networkSwitch"))
            add(InsnNode(if (DoKitExtUtil.commExt.networkSwitch) ICONST_1 else ICONST_0))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "java/lang/Boolean",
                    "valueOf",
                    "(Z)Ljava/lang/Boolean;",
                    false
                )
            )
            add(
                MethodInsnNode(
                    INVOKEINTERFACE,
                    "java/util/Map",
                    "put",
                    "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                    true
                )
            )
            add(InsnNode(POP))

            //put("bigImgSwitch",true)
            add(VarInsnNode(ALOAD, 0))
            add(LdcInsnNode("bigImgSwitch"))
            add(InsnNode(if (DoKitExtUtil.commExt.bigImgSwitch) ICONST_1 else ICONST_0))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "java/lang/Boolean",
                    "valueOf",
                    "(Z)Ljava/lang/Boolean;",
                    false
                )
            )
            add(
                MethodInsnNode(
                    INVOKEINTERFACE,
                    "java/util/Map",
                    "put",
                    "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                    true
                )
            )
            add(InsnNode(POP))

            //put("methodSwitch",true)
            add(VarInsnNode(ALOAD, 0))
            add(LdcInsnNode("methodSwitch"))
            add(InsnNode(if (DoKitExtUtil.dokitSlowMethodSwitchOpen()) ICONST_1 else ICONST_0))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "java/lang/Boolean",
                    "valueOf",
                    "(Z)Ljava/lang/Boolean;",
                    false
                )
            )
            add(
                MethodInsnNode(
                    INVOKEINTERFACE,
                    "java/util/Map",
                    "put",
                    "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                    true
                )
            )
            add(InsnNode(POP))


            //put("methodStrategy",0)
            add(VarInsnNode(ALOAD, 0))
            add(LdcInsnNode("methodStrategy"))
            add(InsnNode(if (DoKitExtUtil.SLOW_METHOD_STRATEGY == SlowMethodExt.STRATEGY_STACK) ICONST_0 else ICONST_1))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "java/lang/Integer",
                    "valueOf",
                    "(I)Ljava/lang/Integer;",
                    false
                )
            )
            add(
                MethodInsnNode(
                    INVOKEINTERFACE,
                    "java/util/Map",
                    "put",
                    "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                    true
                )
            )
            add(InsnNode(POP))

            //将HashMap注入到DokitPluginConfig中
            add(VarInsnNode(ALOAD, 0))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/aop/DokitPluginConfig",
                    "inject",
                    "(Ljava/util/Map;)V",
                    false
                )
            )

            this
        }

        //return insnList

    }


    /**
     * 创建pluginConfig代码指令
     */
    private fun createThirdLibInfoInsnList(): InsnList {
        //val insnList = InsnList()
        return with(InsnList()) {
            //new HashMap
            add(TypeInsnNode(NEW, "java/util/HashMap"))
            add(InsnNode(DUP))
            add(MethodInsnNode(INVOKESPECIAL, "java/util/HashMap", "", "()V", false))
            //保存变量
            add(VarInsnNode(ASTORE, 0))
            DoKitExtUtil.THIRD_LIB_INFOS.forEach { thirdLibInfo ->
                add(VarInsnNode(ALOAD, 0))
                add(LdcInsnNode(thirdLibInfo.variant))
                add(LdcInsnNode(thirdLibInfo.fileSize.toString()))

                add(
                    MethodInsnNode(
                        INVOKEINTERFACE,
                        "java/util/Map",
                        "put",
                        "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
                        false
                    )
                )
                add(InsnNode(POP))
            }


            //将HashMap注入到DokitPluginConfig中
            add(VarInsnNode(ALOAD, 0))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/aop/DokitThirdLibInfo",
                    "inject",
                    "(Ljava/util/Map;)V",
                    false
                )
            )

            this
        }

        //return insnList

    }


    /**
     * 创建Amap地图代码指令
     */
    private fun createAmapLocationInsnList(): InsnList {
        return with(InsnList()) {
            //在AMapLocationClient的 setLocationListener 方法之中插入自定义代理回调类
            add(TypeInsnNode(NEW, "com/didichuxing/doraemonkit/gps_mock/map/AMapLocationListenerProxy"))
            add(InsnNode(DUP))
            //访问第一个参数
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESPECIAL,
                    "com/didichuxing/doraemonkit/gps_mock/map/AMapLocationListenerProxy",
                    "",
                    "(Lcom/amap/api/location/AMapLocationListener;)V",
                    false
                )
            )
            //对第一个参数进行重新赋值
            add(VarInsnNode(ASTORE, 1))
            this
        }

    }

    /**
     * 创建Amap地图导航代码指令
     */
    private fun createAmapNaviInsnList(): InsnList {
        return with(InsnList()) {
            //在AMapNavi的addAMapNaviListener方法之中插入自定义代理回调类
            add(TypeInsnNode(NEW, "com/didichuxing/doraemonkit/gps_mock/map/AMapNaviListenerProxy"))
            add(InsnNode(DUP))
            //访问第一个参数
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESPECIAL,
                    "com/didichuxing/doraemonkit/gps_mock/map/AMapNaviListenerProxy",
                    "",
                    "(Lcom/amap/api/navi/AMapNaviListener;)V",
                    false
                )
            )
            //对第一个参数进行重新赋值
            add(VarInsnNode(ASTORE, 1))
            this
        }

    }


    /**
     * 创建Amap LocationSource代码指令
     */
    private fun createAmapLocationSourceInsnList(): InsnList {
        return with(InsnList()) {
            //在AMapNavi的addAMapNaviListener方法之中插入自定义代理回调类
            add(TypeInsnNode(NEW, "com/didichuxing/doraemonkit/gps_mock/map/AMapLocationSourceProxy"))
            add(InsnNode(DUP))
            //访问第一个参数
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESPECIAL,
                    "com/didichuxing/doraemonkit/gps_mock/map/AMapLocationSourceProxy",
                    "",
                    "(Lcom/amap/api/maps/LocationSource;)V",
                    false
                )
            )
            //对第一个参数进行重新赋值
            add(VarInsnNode(ASTORE, 1))
            this
        }

    }

    /**
     * 创建AMapLocationClient#LastKnownLocation 字节码替换
     */
    private fun createAMapClientLastKnownLocation(): InsnList {
        return with(InsnList()) {
            add(VarInsnNode(ALOAD, 0))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/gps_mock/map/AMapLocationClientProxy",
                    "getLastKnownLocation",
                    "(Lcom/amap/api/location/AMapLocationClient;)Lcom/amap/api/location/AMapLocation;",
                    false
                )
            )
//            add(VarInsnNode(ASTORE, 1))
//            add(VarInsnNode(ALOAD, 1))
            add(InsnNode(ARETURN))
            this
        }

    }

    /**
     * 创建Amap地图UnRegister代码指令
     */
    private fun createAmapLocationUnRegisterInsnList(): InsnList {
        return with(InsnList()) {
            //访问第一个参数
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/gps_mock/map/ThirdMapLocationListenerUtil",
                    "unRegisterAmapLocationListener",
                    "(Lcom/amap/api/location/AMapLocationListener;)V",
                    false
                )
            )
            this
        }

    }

    /**
     * 创建Amap地图 Navi UnRegister代码指令
     */
    private fun createAmapNaviUnRegisterInsnList(): InsnList {
        return with(InsnList()) {
            //访问第一个参数
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/gps_mock/map/ThirdMapLocationListenerUtil",
                    "unRegisterAmapNaviListener",
                    "(Lcom/amap/api/navi/AMapNaviListener;)V",
                    false
                )
            )
            this
        }

    }


    /**
     * 创建tencent地图代码指令
     */
    private fun createTencentLocationInsnList(): InsnList {
        return with(InsnList()) {
            //在AMapLocationClient的setLocationListener方法之中插入自定义代理回调类
            add(
                TypeInsnNode(
                    NEW,
                    "com/didichuxing/doraemonkit/gps_mock/map/TencentLocationListenerProxy"
                )
            )
            add(InsnNode(DUP))
            //访问第一个参数
            add(VarInsnNode(ALOAD, 2))
            add(
                MethodInsnNode(
                    INVOKESPECIAL,
                    "com/didichuxing/doraemonkit/gps_mock/map/TencentLocationListenerProxy",
                    "",
                    "(Lcom/tencent/map/geolocation/TencentLocationListener;)V",
                    false
                )
            )
            //对第二个参数进行重新赋值
            add(VarInsnNode(ASTORE, 2))

            this
        }

    }


    /**
     * 创建Tencent地图UnRegister代码指令
     */
    private fun createTencentLocationUnRegisterInsnList(): InsnList {
        return with(InsnList()) {
            //访问第一个参数
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/gps_mock/map/ThirdMapLocationListenerUtil",
                    "unRegisterTencentLocationListener",
                    "(Lcom/tencent/map/geolocation/TencentLocationListener;)V",
                    false
                )
            )
            this
        }

    }


    /**
     * 创建百度地图代码指令
     */
    private fun createBDLocationListenerInsnList(): InsnList {
        return with(InsnList()) {
            //在LocationClient的registerLocationListener方法之中插入自定义代理回调类
            add(TypeInsnNode(NEW, "com/didichuxing/doraemonkit/gps_mock/map/BDLocationListenerProxy"))
            add(InsnNode(DUP))
            //访问第一个参数
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESPECIAL,
                    "com/didichuxing/doraemonkit/gps_mock/map/BDLocationListenerProxy",
                    "",
                    "(Lcom/baidu/location/BDLocationListener;)V",
                    false
                )
            )
            //对第一个参数进行重新赋值
            add(VarInsnNode(ASTORE, 1))

            this
        }

    }

    /**
     * 创建百度地图代码指令
     */
    private fun createBDLocationAbsListenerInsnList(): InsnList {
        return with(InsnList()) {
            //在LocationClient的registerLocationListener方法之中插入自定义代理回调类
            add(TypeInsnNode(NEW, "com/didichuxing/doraemonkit/gps_mock/map/BDAbsLocationListenerProxy"))
            add(InsnNode(DUP))
            //访问第一个参数
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESPECIAL,
                    "com/didichuxing/doraemonkit/gps_mock/map/BDAbsLocationListenerProxy",
                    "",
                    "(Lcom/baidu/location/BDAbstractLocationListener;)V",
                    false
                )
            )
            //对第一个参数进行重新赋值
            add(VarInsnNode(ASTORE, 1))
            this
        }
    }


    /**
     * 创建百度地图UnRegister代码指令
     */
    private fun createBDLocationUnRegisterInsnList(): InsnList {
        return with(InsnList()) {
            //访问第一个参数
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/gps_mock/map/ThirdMapLocationListenerUtil",
                    "unRegisterBDLocationListener",
                    "(Lcom/baidu/location/BDLocationListener;)V",
                    false
                )
            )
            this
        }

    }

    /**
     * 创建百度地图UnRegister代码指令
     */
    private fun createBDAbsLocationUnRegisterInsnList(): InsnList {
        return with(InsnList()) {
            //访问第一个参数
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/gps_mock/map/ThirdMapLocationListenerUtil",
                    "unRegisterBDLocationListener",
                    "(Lcom/baidu/location/BDAbstractLocationListener;)V",
                    false
                )
            )
            this
        }

    }

    /**
     * 创建百度地图代码指令
     */
    private fun createBaiduLocationInsnList(): InsnList {
        return with(InsnList()) {
            //在AMapLocationClient的setLocationListener方法之中插入自定义代理回调类
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/gps_mock/map/BDLocationUtil",
                    "proxy",
                    "(Lcom/baidu/location/BDLocation;)Lcom/baidu/location/BDLocation;",
                    false
                )
            )
            //对第一个参数进行重新赋值
            add(VarInsnNode(ASTORE, 1))
            this
        }

    }

    /**
     * 创建OkhttpClient一个数构造函数指令
     */
    private fun createOkHttpClientInsnList(): InsnList {
        return with(InsnList()) {
            //插入application 拦截器
            add(VarInsnNode(ALOAD, 0))

            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/aop/OkHttpHook",
                    "addDoKitIntercept",
                    "(Lokhttp3/OkHttpClient;)V",
                    false
                )
            )
            this
        }

    }

    /**
     * 创建OkhttpClient一个数构造函数指令
     */
    private fun createMessageSenderHookInsnList(): InsnList {
        return with(InsnList()) {
            //插入application 拦截器
            val l0= LabelNode()
            add(l0)
            add(VarInsnNode(ALOAD, 0))
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/tcp/ability/MessageSenderHook",
                    "hookSendMessage",
                    "(Lcom/didi/daijia/tcp/message/MessageSender;Ljava/lang/Object;)Z",
                    false
                )
            )
            val l1= LabelNode()
            add(JumpInsnNode(IFEQ,l1))
            val l2= LabelNode()
            add(l2)
            add(InsnNode(ICONST_1))
            add(InsnNode(IRETURN))
            add(l1)
            add(FrameNode(F_SAME,0,null,0,null))
            this
        }

    }
    /**
     * 创建OkhttpClient一个数构造函数指令
     */
    private fun createMessageReceiverHookInsnList(): InsnList {
        return with(InsnList()) {
            //插入application 拦截器
            val l0= LabelNode()
            add(l0)
            add(VarInsnNode(ALOAD, 0))
            add(VarInsnNode(ALOAD, 1))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/tcp/ability/MessageReceiverHook",
                    "hookChannelRead",
                    "(Lcom/didi/daijia/tcp/message/MessageReceiver;Ljava/lang/Object;)Z",
                    false
                )
            )
            val l1= LabelNode()
            add(JumpInsnNode(IFEQ,l1))
            val l2= LabelNode()
            add(l2)
            add(InsnNode(RETURN))
            add(l1)
            add(FrameNode(F_SAME,0,null,0,null))
            this
        }

    }

    /**
     * 创建OkhttpClient一个数构造函数指令
     */
    private fun createDidiHttpClientInsnList(): InsnList {
        return with(InsnList()) {
            //插入application 拦截器
            add(VarInsnNode(ALOAD, 0))

            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/foundation/net/rpc/http/DidiHttpHook",
                    "addRpcIntercept",
                    "(Ldidihttp/DidiHttpClient;)V",
                    false
                )
            )
            this
        }

    }

    /**
     * 创建webView函数指令集
     * 参考:https://www.jianshu.com/p/7d623f441bed
     */
    private fun createWebViewInsnList(): InsnList {
        return with(InsnList()) {
            //复制栈顶的2个指令 指令集变为 比如 aload 2 aload0 / aload 2 aload0
            add(InsnNode(DUP2))
            //抛出最上面的指令 指令集变为 aload 2 aload0 / aload 2  其中 aload 2即为我们所需要的对象
            add(InsnNode(POP))
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/aop/WebViewHook",
                    "inject",
                    "(Ljava/lang/Object;)V",
                    false
                )
            )
            add(
                MethodInsnNode(
                    INVOKESTATIC,
                    "com/didichuxing/doraemonkit/aop/WebViewHook",
                    "getSafeUrl",
                    "(Ljava/lang/String;)Ljava/lang/String;",
                    false
                )
            )
            this
        }
    }


    /**
     * 创建new DoKitAppCompatDelegateImpl指令集
     */
    private fun createNewDoKitAppCompatDelegateImplInsnList(): InsnList {
        return with(InsnList()) {
            add(TypeInsnNode(NEW, "androidx/appcompat/app/DoKitAppCompatDelegateImpl"))
            add(InsnNode(DUP))
            this
        }
    }


    /**
     * 重置ComponentActivity的父类
     */
    private fun createComponentActivitySuperActivityImpl(klass: ClassNode) {
        /**
         * 修改继承的父类
         */
        klass.superName = "com/didichuxing/doraemonkit/aop/mc/DoKitProxyActivity"
    }


    /**
     * 重置View的父类
     */
    private fun createViewImpl(klass: ClassNode) {
        /**
         * 修改继承的父类
         */
        klass.superName = "com/didichuxing/doraemonkit/aop/mc/DoKitProxyView"
    }


    /**
     * 重置ViewGroup的父类
     */
    private fun createViewGroupImpl(klass: ClassNode) {
        /**
         * 修改继承的父类
         */
        klass.superName = "com/didichuxing/doraemonkit/aop/mc/DoKitProxyViewGroup"
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy