栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android 基于 DroidAssist 插件实现无埋点

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android 基于 DroidAssist 插件实现无埋点

DroidAssist

DroidAssist (源码) 是一个轻量级的 Android 字节码编辑插件,基于 Javassist 对字节码操作,根据 xml 配置处理 class 文件,以达到对 class 文件进行动态修改的效果。和其他 AOP 方案不同,DroidAssist 提供了一种更加轻量,简单易用,无侵入,可配置化的字节码操作方式,你不需要 Java 字节码的相关知识,只需要在 Xml 插件配置中添加简单的 Java 代码即可实现类似 AOP 的功能,同时不需要引入其他额外的依赖。

使用方式

DroidAssist 适用于 Android Studio 工程 application model 或者 library model,使用 DroidAssist 需要接入 DroidAssist 插件并编写专有配置文件。
在 root project 的 build.gradle 里添加:

dependencies {
    classpath "com.didichuxing.tools:droidassist:1.1.1"
}

注意:目前似乎只在 jcenter 有发布,所以需要在 repositories 里添加 jcenter() 。

在需要处理的 model project 的 build.gradle 里添加:

apply plugin: 'com.didichuxing.tools.droidassist'
droidAssistOptions {
    config file("droidassist.xml"),file("droidassist2.xml") //插件配置文件(必选配置,支持多配置文件)
}
埋点配置 1、埋点代码 ViewInject.kt
package com.example.droidassisttest

import android.app.Activity
import android.content.DialogInterface
import android.os.SystemClock
import android.util.Log
import android.view.View
import android.widget.CompoundButton
import android.widget.RadioGroup
import android.widget.SeekBar
import androidx.fragment.app.Fragment


object ViewInject {
    private const val TAG = "ViewInject"

    @JvmStatic
    fun injectClick(view: View) {
        Log.d(TAG, "injectClick on $view")
    }

    @JvmStatic
    fun injectDialogClick(dialog: DialogInterface, which: Int) {
        Log.d(TAG, "injectDialogClick on $dialog: $which")
    }

    @JvmStatic
    fun injectGroupCheckedChanged(radioGroup: RadioGroup, which: Int) {
        Log.d(TAG, "injectGroupCheckedChanged on $radioGroup: $which")
    }

    @JvmStatic
    fun injectSeekClick(seekBar: SeekBar) {
        Log.d(TAG, "injectSeekClick on $seekBar")
    }

    @JvmStatic
    fun injectCheckedChanged(button: CompoundButton, value: Boolean) {
        Log.d(TAG, "injectCheckedChanged on $button: $value")
    }

    @JvmStatic
    fun injectActivityOnResume(activity: Activity) {
        Log.d(TAG, "injectActivityonResume $activity")
        activity.window.decorView.setTag(R.id.activity_resume_tag, SystemClock.uptimeMillis())
    }

    @JvmStatic
    fun injectActivityOnPause(activity: Activity) {
        val pauseTime = SystemClock.uptimeMillis()
        val resumeTime =
            (activity.window.decorView.getTag(R.id.activity_resume_tag) as? Long) ?: pauseTime
        Log.d(TAG, "injectActivityonPause $activity time=${pauseTime - resumeTime}")
    }

    @JvmStatic
    fun injectFragmentOnResume(fragment: Fragment) {
        Log.d(TAG, "injectFragmentonResume $fragment")
    }

    @JvmStatic
    fun injectFragmentOnPause(fragment: Fragment) {
        Log.d(TAG, "injectFragmentonPause $fragment")
    }

    @JvmStatic
    fun injectFragmentOnResume(fragment: android.app.Fragment) {
        Log.d(TAG, "injectFragmentonResume $fragment")
    }

    @JvmStatic
    fun injectFragmentOnPause(fragment: android.app.Fragment) {
        Log.d(TAG, "injectFragmentonPause $fragment")
    }
}
2、埋点 xml 配置表

路径为 DroidAssistTest/app/droidassist.xml
记得在 xml 头部添加 https://github.com/didi/DroidAssist/blob/master/docs/droidassist.dtd 的内容,为了方便编写配置文件,在 IDE 中能自动提示。

]>

    
        
            *
            androidx.*
            
            
        
    

    
        
            
                void android.view.View$OnClickListener.onClick(android.view.View)
            
            
                {com.example.droidassisttest.ViewInject.injectClick($1);}
            
        
        
            
                void
                android.content.DialogInterface$OnClickListener.onClick(android.content.DialogInterface,int)
            
            
                {com.example.droidassisttest.ViewInject.injectDialogClick($1,$2);}
            
        
        
            
                void
                android.widget.RadioGroup$OnCheckedChangeListener.onCheckedChanged(android.widget.RadioGroup,int)
            
            
                {com.example.droidassisttest.ViewInject.injectGroupCheckedChanged($1,$2);}
            
        
        
            
                void
                android.widget.SeekBar$OnSeekBarChangeListener.onStopTrackingTouch(android.widget.SeekBar)
            
            
                {com.example.droidassisttest.ViewInject.injectSeekClick($1);}
            
        
        
            
                void
                android.widget.CompoundButton$OnCheckedChangeListener.onCheckedChanged(android.widget.CompoundButton,boolean)
            
            
                {com.example.droidassisttest.ViewInject.injectCheckedChanged($1,$2);}
            
        

        
            
            
                void androidx.fragment.app.FragmentActivity.onResume()
            
            
                {com.example.droidassisttest.ViewInject.injectActivityonResume(this);}
            
        
        
            
            
                void androidx.fragment.app.FragmentActivity.onPause()
            
            
                {com.example.droidassisttest.ViewInject.injectActivityonPause(this);}
            
        
    

3、使用样例 布局文件 activity_main.xml



    
Activity 代码 MainActivity.kt
package com.example.droidassisttest

import android.content.DialogInterface
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.CompoundButton
import android.widget.RadioGroup
import android.widget.SeekBar
import androidx.appcompat.app.alertDialog
import androidx.appcompat.app.AppCompatActivity
import com.example.droidassisttest.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val dialogBuilder = alertDialog.Builder(this@MainActivity).apply {
            setCancelable(true)
            setTitle("alertDialog Test")
            setPositiveButton("Ok", object : DialogInterface.OnClickListener {
                override fun onClick(dialog: DialogInterface?, which: Int) {
                    Log.d(TAG, "$dialog: onClick $which")
                }
            })
        }

        binding.run {
            
            buttonView.setOnClickListener(object : View.OnClickListener {
                override fun onClick(v: View) {
                    Log.d(TAG, "$v: onClick")
                }
            })

            showDialog.setOnClickListener {
                dialogBuilder.show()
            }

            
            switchView.setOnCheckedChangeListener(object : CompoundButton.OnCheckedChangeListener {
                override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
                    Log.d(TAG, "$buttonView isChecked=$isChecked")
                }
            })

            
            radioGroup.setOnCheckedChangeListener(object : RadioGroup.OnCheckedChangeListener {
                override fun onCheckedChanged(group: RadioGroup?, checkedId: Int) {
                    Log.d(TAG, "$group checkedId=$checkedId")
                }
            })

            seekbarView.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                override fun onProgressChanged(
                    seekBar: SeekBar,
                    progress: Int,
                    fromUser: Boolean
                ) {
                    Log.d(TAG, "$seekBar onProgressChanged progress=$progress")
                }

                override fun onStartTrackingTouch(seekBar: SeekBar) {
                    Log.d(TAG, "$seekBar onStartTrackingTouch")
                }

                override fun onStopTrackingTouch(seekBar: SeekBar) {
                    Log.d(TAG, "$seekBar onStopTrackingTouch")
                }
            })
        }
    }
}
Log 输出
D/ViewInject: injectActivityonResume com.example.droidassisttest.MainActivity@1a24434
D/ViewInject: injectClick on com.google.android.material.button.MaterialButton{42efbfd VFED..C.. ...P.... 355,151-725,277 #7f080064 app:id/button_view}
D/ViewInject: injectDialogClick on androidx.appcompat.app.alertDialog@c607c20: -1
D/ViewInject: injectCheckedChanged on androidx.appcompat.widget.SwitchCompat{3b12a95 VFED..C.. ...P..ID 477,706-603,832 #7f080198 app:id/switch_view}: true
D/ViewInject: injectGroupCheckedChanged on android.widget.RadioGroup{42a6f5b V.E...... .......D 0,983-1080,1235 #7f080150 app:id/radio_group}: 1
D/ViewInject: injectSeekClick on androidx.appcompat.widget.AppCompatSeekBar{3677909 VFED..... ...P.... 278,1386-803,1433 #7f08016e app:id/seekbar_view}
4、注意事项

对于需要自动埋点的地方,不支持使用 Java 或者 kotlin 的 lambda 表达式,否则不会自动埋点。
比如:

buttonView.setOnClickListener(object : View.OnClickListener {
    override fun onClick(v: View) {
        Log.d(TAG, "$v: onClick")
    }
}

不能用 lambda 表达式代替:

buttonView.setOnClickListener {
    Log.d(TAG, "$it: onClick")
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/737642.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号