sudo apt-get install android-tools-adb
adb devices # 确认设备在线(显示序列号)
adb tcpip 5555 # 切换 ADB 到 TCP 模式,监听 5555 端口
# 如果当前显示设备序列号,通过以下方式切换模式
adb -s F409659900017 tcpip 5555
adb devices # 获取设备号
adb -s 设备号 shell ip addr show eth0
// 例如 adb -s F409659900017 shell ip addr show eth0
adb connect ip:5555
注意:设备重启后,ADB 会恢复为 USB 模式,每次重启后需重新执行 adb tcpip 5555
Android11 及以上推荐使用配对的方式
adb pair ip:port
adb connect ip:port
很多 RK3566 设备 已内置 persist.adb.tcp.port 支持,只需一条命令即可永久开启 ADB over TCP。
adb shell # 进入设备命令环境
// 如果有多台设备
adb -s 设备号 shell // 例如 adb -s F409659900017 shell
// 查看设备号
// adb devices
setprop persist.adb.tcp.port 5555
setprop service.adb.tcp.port 5555
// 以下这两个命令可能不生效,但是不影响
stop adbd
start adbd
reboot
adb connect ip:5555
adb -s ip:port shell pm list packages
adb -s ip:port shell cmd package resolve-activity --brief 包名
import subprocess
import sys
import os
"""
ADB 远程安装触控屏软件
@Auth lgk
@Date 2025/01/09
"""
# 预定义会议室设备列表
ROOM_DEVICES = [
{"meeting_room": "会议室1", "ip": "192.168.6.81:5555", "sn": "F409659900019"},
{"meeting_room": "会议室2", "ip": "192.168.6.82:5555", "sn": "F409659900016"},
{"meeting_room": "会议室3", "ip": "192.168.6.83:5555", "sn": "F409659900017"},
{"meeting_room": "会议室4", "ip": "192.168.6.84:5555", "sn": "F409659900021"},
{"meeting_room": "会议室5", "ip": "192.168.6.85:5555", "sn": "F409659900006"},
{"meeting_room": "会议室6", "ip": "192.168.6.86:5555", "sn": "F409659900020"},
{"meeting_room": "会议室7", "ip": "192.168.6.87:5555", "sn": "F409659900011"},
# {"meeting_room": "会议室", "ip": "192.168.6.82:5555", "sn": "F409659900016"}, # 未设置默认转tcp
{"meeting_room": "中会议室", "ip": "192.168.6.89:5555", "sn": "F409659900015"},
{"meeting_room": "大会议室", "ip": "192.168.6.80:5555", "sn": "F409659900018"},
{"meeting_room": "多功能厅-会议室", "ip": "192.168.6.90:5555", "sn": "F409659900013"},
{"meeting_room": "多功能厅-展厅", "ip": "192.168.6.91:5555", "sn": "F409659900010"},
{"meeting_room": "展厅-多功能厅", "ip": "192.168.6.92:5555", "sn": "F409659900012"},
{"meeting_room": "展厅-储藏室", "ip": "192.168.6.93:5555", "sn": "E407000900005"},
{"meeting_room": "评价室-办公室", "ip": "192.168.6.97:5555", "sn": "F409659900009"},
{"meeting_room": "评价室-CFD", "ip": "192.168.6.98:5555", "sn": "F409659900007"},
{"meeting_room": "办公室-储藏室", "ip": "192.168.6.94:5555", "sn": "F409659900001"},
{"meeting_room": "办公室-电梯", "ip": "192.168.6.95:5555", "sn": "F409659900022"},
{"meeting_room": "办公室-评价室", "ip": "192.168.6.96:5555", "sn": "F409659900002"},
# {"meeting_room": "总控", "ip": "192.168.6.93:5555", "sn": "E407000900005"},# 未设置默认转tcp
]
APP_PACKAGE = "uni.app.UNI6B51D9B"
APP_ACTIVITY = "io.dcloud.PandoraEntry"
def run_adb_command(args, timeout=30):
"""
执行 adb 命令并返回 stdout, stderr, returncode
"""
try:
# 关键修复:显式指定 encoding='utf-8' 并忽略解码错误
result = subprocess.run(
['adb'] + args,
capture_output=True,
text=True,
timeout=timeout,
encoding='utf-8',
errors='replace' # 遇到非法字符用 替代,避免崩溃
)
return result.stdout.strip(), result.stderr.strip(), result.returncode
except FileNotFoundError:
print("❌ 错误:未找到 adb 命令。请确保 adb 已加入系统 PATH。")
sys.exit(1)
except subprocess.TimeoutExpired:
print(f"⚠️ 命令超时: {' '.join(args)}")
return "", "timeout", -1
def connect_device(device_id):
"""
尝试连接指定 IP 的设备
"""
print(f"🔌 尝试连接 {device_id} ...\n", end="")
stdout, stderr, code = run_adb_command(['connect', device_id], timeout=10)
if "connected" in stdout or "already connected" in stdout:
print(" ✅ 连接成功")
return device_id
else:
print(" ❌ 连接失败")
return None
def install_apk_to_device(apk_path, device_id):
"""
向已连接的设备安装 APK
"""
print(f"📦 正在向 {device_id} 安装 {os.path.basename(apk_path)} ...\n", end="")
stdout, stderr, code = run_adb_command(['-s', device_id, 'install', '-r', '-t', apk_path], timeout=60)
if code == 0:
print(" ✅ 安装成功")
return True
else:
print(" ❌ 安装失败")
# 可选:显示错误详情
# print(f" 错误: {stderr}")
return False
def disconnect_device(device_id):
"""
断开设备连接(可选)
"""
run_adb_command(['disconnect', device_id])
def launch_app(device_id, package, activity):
"""
启动 APK
"""
print(f"🚀 启动应用 {package} ...\n", end="", flush=True)
# 使用 am start -n 包名/Activity
stdout, stderr, code = run_adb_command(
['-s', device_id, 'shell', 'am', 'start', '-n', f"{package}/{activity}"],
timeout=10
)
if code == 0:
print(" ✅ 运行成功")
return True
else:
print(" ❌ 运行失败")
return False
def main():
if len(sys.argv) != 2:
print("用法: python main.py <apk文件路径>")
print("示例: python main.py D:\\Download\\dk-app.apk")
sys.exit(1)
apk_path = sys.argv[1]
if not os.path.isfile(apk_path):
print(f"❌ APK 文件不存在: {apk_path}")
sys.exit(1)
print(f"🎯 准备向 {len(ROOM_DEVICES)} 个会议室设备安装并启动 APK: {os.path.basename(apk_path)}")
print("=" * 70)
success_install_count = 0
success_run_count = 0
for device in ROOM_DEVICES:
room = device["meeting_room"]
ip = device["ip"]
sn = device['sn']
print(f"\n📌 {room} {sn} ({ip})")
# 1. 连接设备
device_id = connect_device(ip)
if not device_id:
continue
# 2. 安装 APK
if install_apk_to_device(apk_path, device_id):
success_install_count += 1
print(f"📊 安装完成:{success_install_count}/{len(ROOM_DEVICES)} 个设备安装成功")
# continue
# 3. 启动应用
if launch_app(device_id, APP_PACKAGE, APP_ACTIVITY):
success_run_count += 1
print(f"📊 运行完成:{success_run_count}/{len(ROOM_DEVICES)} 个设备启动成功")
else:
continue
# 4. (可选)断开连接,避免设备列表过长
# disconnect_device(device_id)
print("\n" + "=" * 70)
print(f"📊 安装完成:{success_run_count}/{len(ROOM_DEVICES)} 个设备成功")
if __name__ == "__main__":
main()