彻底摆脱数据线——远程ADB调试小工具开发过程记录

5,387 阅读5分钟

前排提示

本文中所描述工具只在ROOT过的设备上有效,如果不感兴趣的朋友可以点赞后退出了,也可以去github给我点个星星,源码地址在这里

写在开始前

每次重启测试机都要连接usb才能开始远程adb调试,真麻烦,能不能弄一个软件点一下就能开始远程调试呢?

如果对什么是adb远程调试不熟悉的朋友,可以搜索下adb tcpip 5555这条命令

为了解决每次重启都要连接一次电脑的问题,经过了大量的网络搜索,终于解决了这个问题。

本文记录了从提出问题到解决问题的全过程。

提问环节

  • 1.为什么要做这个工具?

    adb提供的远程调试工具不香吗,为什么还要没事找事折腾半天来做这个工具

  • 2.怎么实现不连接Usb启动adb的远程连接模式?

    通过往常的经验来看,各种实现远程调试的插件都需要连接一次usb,看起来不用usb好像不太现实,但是经过调研,确实是可以的

  • 3.找到方法了之后,执行哪些命令才能达到我们的目的?

    看似简单的几行命令,到了Android手机上怎么就老跑不通呢

    ** 带着上面这几个问题,我们开始今天的探索吧**

为什么

博主有一台很棒的测试机,它叫小6,小6有很多优点,速度快,体积小,操作简单。 既然小6如此优秀,为什么还会有这篇博客呢,其实小6有一个致命问题,电池不耐用,毕竟已经退役成测试机了嘛。

每次博主要远程调试的时候,小6都需要重新连一次电脑,对于一个电脑只有两个usb口的博主来说,这个过程非常的痛苦,特别是小6的电池又不耐用,每天晚上都会自动关机睡一觉。

所以博主我想,能不能把连电脑这一个步骤转移到手机上执行呢,看着命令也挺简单的,只有一行

感觉我上我也行嘛,说做就做,马上来试试

 adb tcpip 5555

adb tcpip 5555 做了些什么

这是一条神奇的命令,手机开启调试模式,连上电脑之后,运行它,我们就可以用ip连接手机,不用数据线调试程序了

经过一番查找,我们发现,这条命令发送了几条命令给手机

  • 1.设置service.adb.tcp.port为5555
  • 2.重启手机上的adb

搜到这里,博主激动了起来,看起来好像很简单啊,我在手机上也这么操作不就行了,马上去找找怎么在手机上执行命令行

在手机上运行它们!

Android上有很多命令行工具,博主随便找了一个,叫做Termux,运行了上面两条命令

报错了,not found 是什么鬼?经过一番搜索,原来是没有root权限

** 那我们只有去root手机了**

我们来看看root之后再运行怎么样

在获取root权限之后,报错消失了,太好了!

我们继续运行接下来两个命令

运行成功了,我们现在就可以在电脑上用下面的命令来连接手机了

adb connect 手机的ip:5555 

在自己的代码里运行命令

目前为止,一切都很顺利,我们不想用第三方的app,自己写一个程序,点一下,玩一年,不用数据线一整年

怎么在代码里运行shell命令呢?

经过又一番搜索,博主找到了几种方法,最终选定了下面这种,su可以替换成其他命令

 Runtime.getRuntime().exec("su")

让我们行动起来,运行三行命令吧

好像没有作用,尴尬

对比三方应用和自己的命令

通过对比,我们发现第三方的客户端的用户好像不太一样啊,经过搜索,我们发现是它调用了一下/system/bin/sh

我们也得给自己的代码加上才行

我们看看改完之后的命令

运行检测一下,成功啦!

优化一下使用体验

现在我们实现了基本的功能,但是不太友好,对于没有root的用户我们要提醒他,你不能用这个玩意,对于已经root的用户,操作成功了我们要提示他现在的ip是什么,用什么命令连接

这个很简单,弄完就像下面这样,其中的ip我们要去获取手机现在的ip地址

放出代码

前面比比了那么多,代码拿出来看看啊,别急,下面就是完整的代码

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
            val wm = applicationContext.getSystemService(WIFI_SERVICE) as WifiManager
            val ip: String = Formatter.formatIpAddress(wm.connectionInfo.ipAddress)
            AlertDialog.Builder(this).setMessage("该程序仅工作在拥有root权限设备上,如果没有root,请连接usb并使用下列命令进行远程调试\nadb tcpip 5555\nadb connect $ip:5555").setPositiveButton(
                "确认"
            ) { _, _ ->
                val commands = arrayListOf(
                    "/system/bin/sh",
                    "setprop service.adb.tcp.port 5555",
                    "stop adbd",
                    "start adbd"
                )
                try {
                    RunAsRoot(commands)
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }.setCancelable(false).show()

    }

    private fun RunAsRoot(cmds: ArrayList<String>) {
        val p = Runtime.getRuntime().exec("su")
        val os = DataOutputStream(p.outputStream)
        for (tmpCmd in cmds) {
            os.writeBytes(
                """
                $tmpCmd
                
                """.trimIndent()
            )
        }
        os.writeBytes("exit\n")
        os.flush()
        val wm = applicationContext.getSystemService(WIFI_SERVICE) as WifiManager
        val ip: String = Formatter.formatIpAddress(wm.connectionInfo.ipAddress)
        AlertDialog.Builder(this).setMessage("设置完成,请在同一局域网下使用以下命令连接设备\nadb connect $ip:5555").setPositiveButton(
            "确认"
        ) { _, _ -> finish() }.setCancelable(false).show()
    }

}

相信看完上面的介绍,代码应该不难看懂,如果不想自己写,可以去这里找到源码,直接复制粘贴一把梭

问题回顾

让我们来看看最开始的几个问题,总结一下

  • 1.为什么要做这个工具?

    我们的测试机可以重启后不连接usb启动远程调试模式啦!

  • 2.怎么实现不连接Usb启动adb的远程连接模式?

    在代码里运行命令就可以了,用Runtime.getRuntime().exec(你的命令)

  • 3.找到方法了之后,执行哪些命令才能达到我们的目的?

    下面这些

       su
       /system/bin/sh
       setprop service.adb.tcp.port 5555
       stop adbd
       start adbd

写在最后

终极问题,能不能不用root实现这套操作?不能,即使设置端口成功了,重启手机上adb的操作也需要su权限,所以不root是不行的,遗憾

那么大家下次再见