366 lines
12 KiB
Python
366 lines
12 KiB
Python
import subprocess
|
||
import re
|
||
import time
|
||
import requests
|
||
import json
|
||
from appium import webdriver
|
||
from appium.webdriver.common.appiumby import AppiumBy
|
||
from appium.options.android import UiAutomator2Options
|
||
from selenium.webdriver.support.ui import WebDriverWait
|
||
from selenium.webdriver.support import expected_conditions as EC
|
||
from urllib3.connection import port_by_scheme
|
||
|
||
|
||
# =======================
|
||
# 基础工具函数
|
||
# =======================
|
||
|
||
def run_command(command):
|
||
"""执行系统命令并返回输出"""
|
||
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||
return result.stdout.strip()
|
||
|
||
|
||
# =======================
|
||
# API请求函数
|
||
# =======================
|
||
|
||
def get_new_port(yh_id):
|
||
"""从服务器获取新的端口号"""
|
||
url = "https://engineering.yuxindazhineng.com/index/index/get_yh_port"
|
||
headers = {
|
||
"Content-Type": "application/x-www-form-urlencoded"
|
||
}
|
||
data = {
|
||
"yh_id": yh_id
|
||
}
|
||
|
||
try:
|
||
print(f"🔍 查询服务器新端口号,用户ID: {yh_id}")
|
||
response = requests.post(url, headers=headers, data=data, timeout=10)
|
||
|
||
if response.status_code == 200:
|
||
result = response.json()
|
||
if result.get("code") == 0:
|
||
print(f"✅ 查询成功,新端口号: {result.get('data', '未知')}")
|
||
return result.get("data", None)
|
||
else:
|
||
print(f"❌ 查询失败: {result.get('msg', '未知错误')}")
|
||
return None
|
||
else:
|
||
print(f"❌ 服务器响应错误: {response.status_code}")
|
||
return None
|
||
except requests.exceptions.RequestException as e:
|
||
print(f"❌ 网络请求失败: {e}")
|
||
return None
|
||
|
||
def get_accounts_from_server(yh_id):
|
||
"""从服务器获取账户信息"""
|
||
url = "http://www.yuxindazhineng.com:3002/api/accounts/get_uplaod_data"
|
||
headers = {
|
||
"Content-Type": "application/json"
|
||
}
|
||
data = {
|
||
"yh_id": yh_id
|
||
}
|
||
|
||
try:
|
||
print(f"🔍 查询服务器账户信息,用户ID: {yh_id}")
|
||
response = requests.post(url, headers=headers, json=data, timeout=10)
|
||
|
||
if response.status_code == 200:
|
||
result = response.json()
|
||
if result.get("code") == 0:
|
||
print(f"✅ 查询成功,找到 {result.get('total', 0)} 个账户")
|
||
return result.get("data", [])
|
||
else:
|
||
print(f"❌ 查询失败: {result.get('message', '未知错误')}")
|
||
return []
|
||
else:
|
||
print(f"❌ 服务器响应错误: {response.status_code}")
|
||
return []
|
||
except requests.exceptions.RequestException as e:
|
||
print(f"❌ 网络请求失败: {e}")
|
||
return []
|
||
except json.JSONDecodeError as e:
|
||
print(f"❌ JSON解析失败: {e}")
|
||
return []
|
||
|
||
|
||
def update_device_info(account_id, device_name, device_port, device_ip):
|
||
"""更新设备信息到服务器"""
|
||
url = "http://www.yuxindazhineng.com:3002/api/accounts/update"
|
||
headers = {
|
||
"Content-Type": "application/json"
|
||
}
|
||
data = {
|
||
"account_id": str(account_id),
|
||
"account_data": {
|
||
"device_name": str(device_name),
|
||
"device_port": str(device_port),
|
||
"device_ip": str(device_ip)
|
||
}
|
||
}
|
||
|
||
try:
|
||
print(f"🔄 更新设备信息,账户ID: {account_id}")
|
||
print(f" 设备信息: 名称={device_name}, 端口={device_port}, IP={device_ip}")
|
||
|
||
response = requests.post(url, headers=headers, json=data, timeout=10)
|
||
|
||
if response.status_code == 200:
|
||
result = response.json()
|
||
if result.get("code") == 0:
|
||
print(f"✅ 更新成功: {result.get('message', '未知信息')}")
|
||
return True
|
||
else:
|
||
print(f"❌ 更新失败: {result.get('message', '未知错误')}")
|
||
return False
|
||
else:
|
||
print(f"❌ 服务器响应错误: {response.status_code}")
|
||
return False
|
||
except requests.exceptions.RequestException as e:
|
||
print(f"❌ 网络请求失败: {e}")
|
||
return False
|
||
|
||
|
||
# =======================
|
||
# Appium 启动
|
||
# =======================
|
||
|
||
def start_appium():
|
||
appium_port = 4723
|
||
print(f"🚀 启动 Appium Server(端口 {appium_port})...")
|
||
subprocess.Popen(
|
||
["appium.cmd", "-a", "127.0.0.1", "-p", str(appium_port)],
|
||
stdout=subprocess.DEVNULL,
|
||
stderr=subprocess.DEVNULL
|
||
)
|
||
# 检查端口是否就绪(替代固定sleep)
|
||
max_wait = 30 # 最大等待30秒
|
||
start_time = time.time()
|
||
while time.time() - start_time < max_wait:
|
||
try:
|
||
# 尝试连接Appium端口,验证是否就绪
|
||
import socket
|
||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||
sock.settimeout(1)
|
||
result = sock.connect_ex(("127.0.0.1", appium_port))
|
||
sock.close()
|
||
if result == 0: # 端口就绪
|
||
print(f"✅ Appium Server 启动成功(端口 {appium_port})")
|
||
return True
|
||
except Exception:
|
||
pass
|
||
time.sleep(1)
|
||
|
||
print(f"❌ Appium Server 启动超时({max_wait}秒)")
|
||
return False
|
||
|
||
|
||
# =======================
|
||
# 启动沉降观测 App
|
||
# =======================
|
||
|
||
def start_settlement_app(device_id, device_ip, device_port):
|
||
print(f"📱 使用 Appium 连接设备: {device_id}")
|
||
|
||
options = UiAutomator2Options()
|
||
options.platform_name = "Android"
|
||
options.device_name = device_id
|
||
options.udid = device_id
|
||
|
||
# ⚠️ TODO:替换为你的真实信息
|
||
options.app_package = "com.bjjw.cjgc"
|
||
options.app_activity = ".activity.LoginActivity"
|
||
|
||
options.automation_name = "UiAutomator2"
|
||
options.no_reset = True
|
||
options.auto_grant_permissions = True
|
||
options.new_command_timeout = 28800
|
||
|
||
# 超时增强(无线 ADB 必须)
|
||
options.set_capability("uiautomator2ServerLaunchTimeout", 60000)
|
||
options.set_capability("adbExecTimeout", 120000)
|
||
|
||
driver = webdriver.Remote(
|
||
"http://127.0.0.1:4723",
|
||
options=options
|
||
)
|
||
|
||
# 使用ADB命令启动Activity
|
||
try:
|
||
adb_command = f"adb -s {device_id} shell am start -n com.bjjw.cjgc/.activity.LoginActivity"
|
||
result = subprocess.run(adb_command, shell=True, capture_output=True, text=True)
|
||
if result.returncode == 0:
|
||
time.sleep(1) # 等待Activity启动
|
||
except Exception:
|
||
return False
|
||
|
||
print("✅ 沉降观测 App 已成功启动")
|
||
|
||
# =======================
|
||
# 获取用户名文本框内容
|
||
# =======================
|
||
app_username = None
|
||
try:
|
||
print("🔍 尝试获取用户名文本框内容...")
|
||
|
||
# 创建显式等待对象
|
||
wait = WebDriverWait(driver, 15) # 最多等待15秒
|
||
|
||
# 等待用户名文本框可点击
|
||
username_field = wait.until(
|
||
EC.element_to_be_clickable((AppiumBy.ID, "com.bjjw.cjgc:id/et_user_name"))
|
||
)
|
||
|
||
# 获取文本框中的文本内容
|
||
app_username = username_field.text
|
||
|
||
# 如果文本框是空的,尝试使用get_attribute获取文本
|
||
if not app_username:
|
||
app_username = username_field.get_attribute("text")
|
||
|
||
# 如果还是空的,尝试获取其他属性
|
||
if not app_username:
|
||
app_username = username_field.get_attribute("content-desc") or username_field.get_attribute("label")
|
||
|
||
if app_username:
|
||
print(f"✅ 成功获取到用户名: {app_username}")
|
||
else:
|
||
print("⚠️ 用户名文本框为空")
|
||
|
||
except Exception as e:
|
||
print(f"❌ 获取用户名失败: {e}")
|
||
|
||
return driver, app_username
|
||
|
||
|
||
# =======================
|
||
# 无线 ADB 建链主流程
|
||
# =======================
|
||
|
||
def setup_adb_wireless(yh_id="68c0dbfdb7cbcd616e7c5ab5"):
|
||
port = get_new_port(yh_id)
|
||
# port = 3435
|
||
print(f"🚀 开始无线 ADB 建链(端口 {port})")
|
||
print(f"📋 用户ID: {yh_id}")
|
||
|
||
# 从服务器获取账户信息
|
||
accounts = get_accounts_from_server(yh_id)
|
||
if not accounts:
|
||
print("❌ 未从服务器获取到账户信息,终止流程")
|
||
return
|
||
|
||
devices_output = run_command("adb devices")
|
||
lines = devices_output.splitlines()[1:]
|
||
|
||
usb_devices = []
|
||
|
||
for line in lines:
|
||
if not line.strip():
|
||
continue
|
||
|
||
device_id = line.split()[0]
|
||
|
||
# 跳过已经是无线的
|
||
if ":" in device_id:
|
||
continue
|
||
|
||
usb_devices.append(device_id)
|
||
|
||
if not usb_devices:
|
||
print("❌ 未检测到 USB 设备")
|
||
return
|
||
|
||
for serial in usb_devices:
|
||
print(f"\n🔎 处理设备: {serial}")
|
||
|
||
# 获取 WLAN IP
|
||
ip_info = run_command(f"adb -s {serial} shell ip addr show wlan0")
|
||
ip_match = re.search(r'inet\s+(\d+\.\d+\.\d+\.\d+)', ip_info)
|
||
|
||
if not ip_match:
|
||
print("⚠️ 获取 IP 失败,请确认已连接 WiFi")
|
||
continue
|
||
|
||
device_ip = ip_match.group(1)
|
||
print(f"📍 设备 IP: {device_ip}")
|
||
|
||
# 切 TCP 模式
|
||
run_command(f"adb -s {serial} tcpip {port}")
|
||
time.sleep(2)
|
||
|
||
# 无线连接
|
||
connect_result = run_command(f"adb connect {device_ip}:{port}")
|
||
|
||
if "connected" not in connect_result.lower():
|
||
print(f"❌ 无线连接失败: {connect_result}")
|
||
continue
|
||
|
||
wireless_id = f"{device_ip}:{port}"
|
||
print(f"✅ 无线 ADB 成功: {wireless_id}")
|
||
|
||
# ===== 后续自动化 =====
|
||
start_appium()
|
||
driver, app_username = start_settlement_app(wireless_id, device_ip, port)
|
||
|
||
if not app_username:
|
||
print("⚠️ 未获取到App中的用户名,跳过服务器更新")
|
||
continue
|
||
|
||
# 在账户列表中查找匹配的用户名
|
||
matched_account = None
|
||
for account in accounts:
|
||
if account.get("username") == app_username:
|
||
matched_account = account
|
||
break
|
||
|
||
if not matched_account:
|
||
print(f"❌ 未找到与用户名 '{app_username}' 匹配的账户")
|
||
continue
|
||
|
||
print(f"✅ 找到匹配账户: {matched_account.get('cl_name')} ({matched_account.get('username')})")
|
||
print(f" account_id: {matched_account.get('account_id')}")
|
||
|
||
# 更新设备信息到服务器
|
||
device_name = serial # 使用设备序列号作为设备名称
|
||
|
||
# 构建更新数据
|
||
update_data = {
|
||
"account_id": matched_account.get("account_id"),
|
||
"device_name": device_name,
|
||
"device_port": port,
|
||
"device_ip": device_ip
|
||
}
|
||
|
||
success = update_device_info(
|
||
account_id=matched_account.get("account_id"),
|
||
device_name=device_name,
|
||
device_port=port,
|
||
device_ip=device_ip
|
||
)
|
||
|
||
if success:
|
||
print(f"🎉 所有操作完成! 账户 {matched_account.get('username')} 的设备信息已更新")
|
||
else:
|
||
print(f"⚠️ 设备信息更新失败,但无线连接和App启动已完成")
|
||
|
||
# 关闭Appium连接
|
||
if driver:
|
||
print("🔄 关闭Appium连接...")
|
||
driver.quit()
|
||
|
||
break # 处理完第一个设备后退出,如需处理多个设备可移除此行
|
||
|
||
|
||
# =======================
|
||
# 程序入口
|
||
# =======================
|
||
|
||
if __name__ == "__main__":
|
||
# 配置参数
|
||
|
||
USER_ID = "68c0dbfdb7cbcd616e7c5ab5" # 替换为实际的用户ID
|
||
|
||
setup_adb_wireless(USER_ID) |