0
点赞
收藏
分享

微信扫一扫

Preference库:为你的应用快速搭建一个「开发者选项」

杰森wang 2021-09-30 阅读 39

前言

作为Android开发者,想必对Android系统的「开发者模式」不会陌生,因为其既是开启真机调试的必经途径,同时也提供了很多有用的选项,用以模拟不同环境来协助调试应用。那么,你有没有想过,是否也可以为你的应用增加这样一个「开发者模式」,用以模拟特定场景、快速定位问题呢?本文将为你讲解,如何使用Preference库,为你的应用快速搭建一个「开发者选项」。

知识储备

AndroidX Preference Library

该库为我们管理了页面,并负责与存储空间交互,让我们可以只关注于如何去定义设置选项

具体则是通过XML文件去定义层次架构的。

<PreferenceScreen
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <SwitchPreferenceCompat
        app:key="notifications"
        app:title="Enable message notifications"/>

    <Preference
        app:key="feedback"
        app:title="Send feedback"
        app:summary="Report technical issues or suggest new features"/>

</PreferenceScreen>

展现出来的样式如下:

让我们先了解一下常见的Preference组件:

再来了解一下这些Preference组件部分重要的属性:

通用属性:

PreferenceCategory 属性:

ListPreference / MultiSelectListPreference 属性:

如果屏幕上就有多个相关的 Preferences,可以使用PreferenceCategory进行分组:

    <PreferenceScreen         xmlns:app="http://schemas.android.com/apk/res-auto">         <PreferenceCategory             app:key="notifications_category"             app:title="Notifications">             <SwitchPreferenceCompat                 app:key="notifications"                 app:title="Enable message notifications"/>         </PreferenceCategory>         <PreferenceCategory             app:key="help_category"             app:title="Help">             <Preference                 app:key="feedback"                 app:summary="Report technical issues or suggest new features"                 app:title="Send feedback"/>         </PreferenceCategory>     </PreferenceScreen>        <PreferenceScreen
        xmlns:app="http://schemas.android.com/apk/res-auto">

        <PreferenceCategory
            app:key="notifications_category"
            app:title="Notifications">

            <SwitchPreferenceCompat
                app:key="notifications"
                app:title="Enable message notifications"/>

        </PreferenceCategory>

        <PreferenceCategory
            app:key="help_category"
            app:title="Help">

            <Preference
                app:key="feedback"
                app:summary="Report technical issues or suggest new features"
                app:title="Send feedback"/>

        </PreferenceCategory>

    </PreferenceScreen>
 

分组后的展示效果如下:

代码实践

既然是要模仿Android系统的「开发者模式」,那就干脆模仿得更彻底点。于是我们制定了通过在「关于」页面连续点击版本号,来进入调试选项界面的方案:

/**
 * 调试器
 */
object Debugger {

    /** 快速点击次数 */
    private var clickCount = 0
    /** 最后一次快速点击时间戳  */
    private var lastClickTime: Long = 0

    /**
     * 快速点击监听
     */
    fun onQuickClick(activity: AppCompatActivity) {
        val currentTime = System.currentTimeMillis()
        if (currentTime - lastClickTime < 500) {
            clickCount++
            if (clickCount > 10) {
                clickCount = 0
                DebugLoginDialogFragment.newInstance().show(activity.supportFragmentManager, "")
            }
        } else {
            clickCount = 0
        }
        lastClickTime = System.currentTimeMillis()
    }
}

当然,为了同时保证应用的安全性,我们还需要增加调试人员账号的验证步骤:

/**
 * 调试模式登录验证弹框
 */
class DebugLoginDialogFragment : DialogFragment() {

    companion object {
        fun newInstance() = DebugLoginDialogFragment()
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            isCancelable = false    // 需要对fragment同样设置cancelable

            val builder = AlertDialog.Builder(it, android.R.style.Theme_Material_Light_Dialog)

            val view = requireActivity().layoutInflater.inflate(R.layout.dialog_debug_login, null)
            val username = view.findViewById<EditText>(R.id.username)
            val password = view.findViewById<EditText>(R.id.password)

            builder.setView(view)
                .setTitle("验证身份")
                .setPositiveButton("确定",
                    DialogInterface.OnClickListener { _, _ ->

                        // TODO 具体验证方式由接入方选择
                        if ("admin" == username.text.toString()
                            && "123456" == password.text.toString()
                        ) {
                            context?.let { it -> DebugActivity.startActivity(it) }
                            return@OnClickListener
                        }

                    })
                .setNegativeButton("取消", null)
                .setCancelable(false)
            builder.create()

        } ?: throw IllegalStateException("Activity cannot be null")
    }
}

至于调试页面的搭建,Android Studio新建Activity时是提供了相应的模板的,为了达到我们“快速搭建”的目的,可以直接使用此方式:

我们重点关注root_preferences.xml文件,通过XML去定义我们的调试选项。

1.区分与调试选项交互的场景,以确定使用哪一种 Preference组件:

2.对调试选项进行分组,根据关联性划分类别:

<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">

    <PreferenceCategory app:title="线路">

        <ListPreference
            app:entries="@array/app_status"
            app:entryValues="@array/app_status_values"
            app:key="app_status"
            app:title="切换环境" />

    </PreferenceCategory>

    <PreferenceCategory app:title="日志">

        <SwitchPreference
            app:key="log_debuggable"
            app:summaryOff="已关闭,日志记录将只写入文件"
            app:summaryOn="已开启,日志记录将允许输出到屏幕"
            app:title="开启日志调试" />

        <Preference
            app:key="logcat_page"
            app:title="进入日志调试页" />

    </PreferenceCategory>

    <PreferenceCategory app:title="内置浏览器">

        <EditTextPreference
            app:key="dummy_app_version"
            app:title="修改应用版本"
            app:useSimpleSummaryProvider="true" />

    </PreferenceCategory>

</PreferenceScreen>

最终呈现出来的界面如下:

3.调用findPreference()找到指定键的调试选项,并监听选项值的的更改:

4.读取具体的选项值,执行相应的业务处理:

class DebugFragment : PreferenceFragmentCompat() {
  
 override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.root_preferences, rootKey)
        initConfigControl()
    }

    private fun initConfigControl() {
        initLineConfigControl()
        initLogConfigControl()
        initBrowserConfigControl()
    }

    private fun initLineConfigControl() {
        findPreference<ListPreference>("app_status")?.setOnPreferenceChangeListener { _, newValue ->
            val newStatus = Integer.valueOf(newValue as String)
            // TODO 切换线路业务逻辑
            true
        }
    }

    private fun initLogConfigControl() {
        findPreference<SwitchPreference>("log_debuggable")?.setOnPreferenceChangeListener { _, newValue ->
            val isDebugMode = newValue as Boolean
            // TODO 开启日志调试业务逻辑
            true
        }


        findPreference<Preference>("logcat_page")?.setOnPreferenceClickListener {
            // TODO 进入日志调试页业务逻辑
            true
        }
    }

    private fun initBrowserConfigControl() {
        findPreference<EditTextPreference>("dummy_app_version")?.setOnPreferenceChangeListener { _, newValue ->
            // TODO 修改应用版本业务逻辑
            true
        }
    }
}

以上示例代码均已上传到GitHub,感觉对你有帮助的话给个Star吧~

https://github.com/madchan/AppDeveloperOption

总结

Preference库原本是为Android应用搭建「偏好设置」页面而设计的,然而现实里却因为很难做到与应用内其他页面样式的统一而很少使用。但对于以上快速搭建「开发者选项」的需求却甚有奇效,让我们可以只关心配置变化而无需关注界面和存储。怎么样,整套流程下来确实很简单吧,跟着我一起实践下吧~

参考

https://developer.android.google.cn/guide/topics/ui/settings?hl=zh-cn

举报

相关推荐

手机开发者选项各项参数意义

0 条评论