Android——开发支撑工具

1.介绍

  开发过程中往往会用到一些开发的工具,仅仅在Debug模式下使用。并不将该工具打入release包中

比如:
  • 1.查看设备信息
  • 2.查看构建时间
  • 3.查看项目版本
    ...

2.开始设计

2.1.创建新的Android Library

1.添加我们buildConfigField,在我们debug环境使用

buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        //buildConfigField添加属性
        debug {
            /**
             * 参数1:字段类型
             * 参数2:字段名称
             * 参数3:返回值
             */
            buildConfigField("String","BUILD_TIME","\""+ buildTime() + "\"")
        }
    }

def buildTime(){
    //EE表示星期几
    //TimeZone表示时区
    return new Date().format("EE HH:mm:ss",TimeZone.getTimeZone("GMT+08:00"))
}

2.项目Rebuild后BuildConfig中就会出现我们添加的属性BUILD_TIME

public final class BuildConfig {
  ...
  // Fields from build type: debug
  public static final String BUILD_TIME = "星期二 16:10:26";
}
2.2.创建DebugTools类

作用:该类主要就是工具需要显示的功能,最终会通过反射获取该类方法的实现,并执行。
好处:每次需要新增一个功能,我们只需要添加一个方法即可。

/**
 * TODO:创建DebugTools工具类
 *   1.该类提供我们工具需要的一些功能方法。
 *   2.最终通过反射来获取该类中的所有方法,并执行方法内的方法体。
 *     注意:如果方法没有返回值,那么我们可以通过注解的方式来实现Tools上显示方法名称
 */
class DebugTools {
    /**
     * TODO:显示项目的构建版本号
     *   1.0.1
     */
    fun buildVersion():String{
        return "构建版本:${BuildConfig.VERSION_CODE}.${BuildConfig.VERSION_NAME}"
    }

    /**
     * TODO:显示项目的构建时间
     *  星期二 22:14:54
     */
    fun buildTime():String{
        //new date() 当我们在运行时拿到的时间。也就是这个包打出来的时间
        return "构建时间:${BuildConfig.BUILD_TIME}"
    }

    /**
     * TODO:显示项目的构建环境
     *   通过BuildConfig.Debug
     */
    fun buildEnvironment():String{
        return "构建环境:${if (BuildConfig.DEBUG) "测试环境" else "正式环境"}"
    }

    /**
     * TODO:降级Https为Http
     *   此时是需要具体的实现,并非是一个String类型的返回值,所以我们此时通过HiDebug注解来实现Tools上显示的名称。
     */
    @HiDebug(name = "一键开启Https降级",desc = "将继承Http,可以使用抓包工具明文抓包")
    fun degradeHttp(){
        //此时我们可以通过MMKV(https://github.com/Tencent/MMKV)来存储我们的baseUrl,将其修改为http的。如果需要重启应用生效,那么我们此时直接重启应用
        //...

        val content = AppGlobals.get()?.applicationContext?:return
        //获取需要启动应用的Intent的意图
        val intent = content.packageManager.getLaunchIntentForPackage(content.packageName)
        intent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        content.startActivity(intent)
        //杀死当前进程,并主动启动新的启动页,完成重启动作。
        Process.killProcess(Process.myPid())
    }
}


/**
 * TODO:注解的作用
 *  @Target:表示作用于哪里(类,方法,属性等等)FUNCTION方法
 *  @Retention:作用于什么时候,RUNTIME运行时期
 */
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class HiDebug(val name:String,val desc:String = "")
2.3.创建实现类

作用:该类主要就是弹窗显示上方定义的DebugTools中的每一个方法,通过反射获取该类方法的实现,并执行。

class DebugToolDialogFragment :AppCompatDialogFragment(){

    //通过数据类进行遍历获取类中所有方法
    private val debugTools = arrayOf(DebugTools::class.java)

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        //获取我们试图的跟布局android.R.id.content,我们可以进行修改宽高大小。
        val parent = dialog?.window?.findViewById(android.R.id.content)?:container
        val view = inflater.inflate(R.layout.hi_debug_tool,parent,false)
        //指定弹窗的宽高
        dialog?.window?.setLayout(
            (HiDisplayUtil.getDisplayWidthInPx(view.context) * 0.7f).toInt(),
            WindowManager.LayoutParams.WRAP_CONTENT)
        //设置背景圆角
        dialog?.window?.setBackgroundDrawableResource(R.drawable.shape_hi_debug_tool)
        return view
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        //设置列表项分割线
        val itemDecoration = DividerItemDecoration(view.context,DividerItemDecoration.VERTICAL)
        itemDecoration.setDrawable(
            ContextCompat.getDrawable(
                view.context,
                R.drawable.shape_hi_debug_divider)!!)


        var functions = mutableListOf()
        //获取数组元素个数
        val size = debugTools.size  
        //遍历
        for (index in 0 until size){
            //获取所有类对象
            val claz = debugTools[index]
            //实例化数组每一个元素对象
            val target = claz.getConstructor().newInstance()
            //获取类中所有方法
            val declaredMethods= target.javaClass.declaredMethods
            for (method in declaredMethods){
                var title = ""
                var desc = ""
                var enable = false
                val annotation = method.getAnnotation(HiDebug::class.java)
                //包含@HiDebug注解的方法都可以被点击
                if (annotation!=null){
                    title = annotation.name
                    desc = annotation.desc
                    enable = true
                }else{
                    method.isAccessible = true   //开启访问权限
                    title = method.invoke(target) as String
                }
                val func = DebugFunction(title,desc,method,enable,target)
                functions.add(func)
            }
        }

        recycler_view.addItemDecoration(itemDecoration)
        recycler_view.layoutManager = LinearLayoutManager(context,LinearLayoutManager.VERTICAL,false)
        recycler_view.adapter = DebugToolAdapter(functions)
    }

    inner class DebugToolAdapter(val list:List): RecyclerView.Adapter() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            //创建item
            var itemView = layoutInflater.inflate(R.layout.hi_debug_tool_item,parent,false)
            return object :RecyclerView.ViewHolder(itemView){

            }
        }


        override fun getItemCount(): Int {
            return list.size
        }

        //绑定数据
        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            val debugFunction = list[position]
            val itemTitle = holder.itemView.findViewById(R.id.item_title)
            val itemDesc = holder.itemView.findViewById(R.id.item_desc)
            itemTitle.text = debugFunction.name
            if (TextUtils.isEmpty(debugFunction.desc)){
                itemDesc.visibility = View.GONE
            }else{
                itemDesc.visibility = View.VISIBLE
                itemDesc.text = debugFunction.desc
            }

            //是否可以点击
            if (debugFunction.enable){
                holder.itemView.setOnClickListener {
                    dismiss()
                    debugFunction.invoke()
                }
            }
        }
    }

    /**
     * name:方法名称
     * desc:方法描述
     * method:方法的实体
     * enable:是否可以点击,有些返回字符串不需要点击
     * target:方法所在类的对象
     */
    data class DebugFunction(
        val name:String,
        val desc:String,
        val method:Method,
        val enable:Boolean,
        val target:Any) {

        //点击事件,通过反射就执行该方法
        fun invoke() {
            method.invoke(target)
        }
    }
}

3.使用

1.我们在主模块中添加依赖

//只有在debug下才会打入apk当中(只用于debug中)
debugImplementation project(path: ":hidebugtools" )

2.可以在任意地方调用(我是通过手机音量键)

/**
     * 监听音量键按下
     */
    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN){
            //显示弹窗,只有在Debug的情况下显示
            if (BuildConfig.DEBUG){
                //通过反射获取类
                try {
                    val clazz = Class.forName("com.yc.hidebugtool.DebugToolDialogFragment")
                    val target:DialogFragment = clazz.getConstructor().newInstance() as DialogFragment
                    target.show(supportFragmentManager,"debug_tool")
                }catch (e:ClassNotFoundException){
                    e.printStackTrace()
                }
                //正常使用
                try {
                    val target: DialogFragment = DebugToolDialogFragment()
                    target.show(supportFragmentManager, "debug_tool")
                }catch (e: ClassNotFoundException){
                    e.printStackTrace()
                }
            }
        }
        return super.onKeyDown(keyCode, event)
    }

3.总结

好处:

1.我们通过debugImplementation 只有在debug模式才会打入包中。
2.完全耦合,我们需要任意一种工具功能,我们只需要在DebugTools类中添加对应的方法,并实现。
github地址:https://github.com/HuiZaierr/DebugTools

你可能感兴趣的:(Android——开发支撑工具)