Android Studio 插件开发实战——获取当前Activity名称

前言

在上篇文章 Android Studio 插件开发入门 中实现了在IntelliJ IDEA中点击一个菜单按钮弹出对话框。

在这里插入图片描述
在这里插入图片描述

本文在上文的基础上介绍如何编写一个IDE插件,实现获取App当前画面的Activity名称,文中有些内容是直接延用上篇文章内容,如有不明白的地方可以查看上一篇文章。

1. adb 获取当前Activity名称

ADB命令

adb shell "dumpsys window | grep mCurrentFocus"

adb 信息

 mCurrentFocus=Window{cead29 u0 com.tencent.mm/com.tencent.mm.ui.LauncherUI}

信息内容

  • 微信Package Nmae:com.tencent.mm
  • 聊天界面Activiy Name:com.tencent.mm.ui.LauncherUI

2. 引入Android插件库

首先 build.gradle文件中引入Android插件库并同步。

intellij {        
  plugins 'android'     
}

然后在 plugin.xml 文件中添加Android插件依赖。

    <depends>com.intellij.modules.platform</depends>
    //依赖Android 插件
    <depends>org.jetbrains.android</depends>

如果不在 plugin.xml 中添加上述代码,运行插件时会出现如下异常

Caused by: java.lang.ClassNotFoundException:
org.jetbrains.android.sdk.AndroidSdkUtils PluginClassLoader

3. 插件开发

完成前面的工作后,只需要在 AnAction.actionPerformed 方法中执行 adb shell 命令,然后将信息在对话框中显示即可实现想要的功能。

在此先简单介绍下,需要用到的几个类。

  • com.intellij.openapi.project:表示IntelliJ项目对象
  • com.android.ddmlib.IDevice:表示Android 设备对象
  • com.android.ddmlib.AndroidDebugBridge

3.1 获取已连接的设备

class ADBAction : AnAction() {
    override fun actionPerformed(e: AnActionEvent) {
        val project: Project = e.project ?: error("project is error")
        val device: IDevice = getConnectedDevice(project) ?: error("no connected device")
        //展示已连接的设备信息
        MessageDialog(device.name, device.abis.toString()).show()
    }

    /**
     * 对象获取当前连接的设备
     */
    private fun getConnectedDevice(project: Project): IDevice? {
        //获取所有以连接的设备
        val devices: List<IDevice> =
            AndroidSdkUtils.getDebugBridge(project)?.devices?.asList() ?: return null
        //如果设备数量大于1 则让用户选择一个设备
        if (devices.size > 1) {
            val facet = AndroidUtils.getApplicationFacets(project).firstOrNull() ?: return null
            //选择设备,并返回值
            return DeviceSelectionUtils.chooseRunningDevice(
                facet,
                TargetDeviceFilter.UsbDeviceFilter(),
                DeviceCount.SINGLE
            )?.firstOrNull()
        } else {
            return devices.firstOrNull()
        }
    }
}

运行程序,查看效果

设备信息

3.2 执行adb Shell 命令

获取了连接的设备信息,在通过设备的 device.executeShellCommand() 方法执行shell命令即可。
executeShellCommand
可以看到该方法需要传入一个 IShellOutputReceiver 用于接收 shell 命令的输出日志,通过该类我们可以将输出的信息日志信息解析并展示出来。

自定义 IShellOutputReceiver 。

    class ADBMessageReceiver : MultiLineReceiver() {
        //记录所有信息
        private var messageLines: MutableList<String> = ArrayList()
        override fun processNewLines(strings: Array<out String>) {
            messageLines.addAll(strings)
        }

        override fun isCancelled(): Boolean = false

        //输出日志接收完成后 回调此方法
        override fun done() {
            //拼接字符串
            val message =
                if (messageLines.isEmpty())
                    "No message"
                else
                    messageLines.joinToString(separator = "")

            /**
             * message格式:mCurrentFocus=Window{cead29 u0 com.tencent.mm/com.tencent.mm.ui.LauncherUI}
             */
            val array = message.split("/")
            if (array.size == 2) {
                val packageName = array[0].split(" ").last()
                val activityName = array[1].replace("}", "")
                MessageDialog(packageName, activityName).show()
            } else {
                Messages.showMessageDialog(message, "adb title", Messages.getInformationIcon())
            }
        }
    }

执行shell命令

    override fun actionPerformed(e: AnActionEvent) {
        val project: Project = e.project ?: error("project is error")
        val device: IDevice = getConnectedDevice(project) ?: error("no connected device")
        //执行 shell 命令
        val shell = "dumpsys window | grep mCurrentFocus"
        device.executeShellCommand(shell,ADBMessageReceiver())
    }

查看效果
当前Activity

3.3 完善UI效果

功能实现后,修改一下对话框的画面显示,比如 OK/Cancel 按钮,Lable的文本显示,大小等等。

修改MyMessageDialog.form
在这里插入图片描述

修改自定义的 MessageDialog

class MessageDialog(
    private val packageName: String,
    private val activityName: String
) : DialogWrapper(true) {
    init {
        init()
    }

    override fun createCenterPanel(): JComponent? {
        return MyMessageDialog().apply {
            textPackageName.text = packageName
            textActivityName.text = activityName
        }.root
    }
    //重写创建对话框按钮的方法,只显示一个关闭按钮
    override fun createActions(): Array<Action> {
        val action = cancelAction.apply { putValue(DEFAULT_ACTION, true) }
        return arrayOf(action)
    }
}

最终效果
插件最终效果
通过上述方式,可以编写很多很多与 adb 相关的插件,例如通过adb查看app启动时间等等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章