彻底摆脱数据线——远程ADB调试小工具开发过程记录
前排提示
本文中所描述工具只在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是不行的,遗憾
那么大家下次再见