first commit

This commit is contained in:
2026-03-12 17:03:56 +08:00
commit aa4d4c7d7c
48 changed files with 10958 additions and 0 deletions

279
permissions.py Normal file
View File

@@ -0,0 +1,279 @@
# 权限处理
import subprocess
import logging
import time
import os
# 配置日志
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s: %(message)s")
def check_device_connection(device_id: str) -> bool:
"""检查设备连接状态"""
try:
check_cmd = ["adb", "-s", device_id, "shell", "getprop", "ro.product.model"]
result = subprocess.run(check_cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
logging.info(f"设备 {device_id} 连接正常,型号: {result.stdout.strip()}")
return True
else:
logging.error(f"设备 {device_id} 连接失败: {result.stderr.strip()}")
return False
except subprocess.TimeoutExpired:
logging.error(f"设备 {device_id} 连接超时")
return False
except Exception as e:
logging.error(f"检查设备 {device_id} 时发生错误: {str(e)}")
return False
def is_package_installed(device_id: str, package_name: str) -> bool:
"""检查包是否已安装"""
try:
check_cmd = ["adb", "-s", device_id, "shell", "pm", "list", "packages", package_name]
result = subprocess.run(check_cmd, capture_output=True, text=True, timeout=10)
return result.returncode == 0 and package_name in result.stdout
except Exception as e:
logging.error(f"检查包 {package_name} 时发生错误: {str(e)}")
return False
def grant_single_permission(device_id: str, package: str, permission: str) -> bool:
"""
为单个包授予单个权限
:return: 是否成功授予
"""
try:
grant_cmd = [
"adb", "-s", device_id,
"shell", "pm", "grant", package,
permission
]
result = subprocess.run(grant_cmd, capture_output=True, text=True, timeout=15)
if result.returncode == 0:
logging.info(f"设备 {device_id}:已成功授予 {package} 权限: {permission}")
return True
else:
error_msg = result.stderr.strip()
logging.warning(f"设备 {device_id}:授予 {package} 权限 {permission} 失败: {error_msg}")
# 尝试使用root权限
if "security" in error_msg.lower() or "permission" in error_msg.lower():
logging.info(f"设备 {device_id}尝试使用root权限授予 {package} 权限")
# 重启adb为root模式
root_cmd = ["adb", "-s", device_id, "root"]
subprocess.run(root_cmd, capture_output=True, text=True, timeout=10)
time.sleep(2) # 等待root权限生效
# 再次尝试授予权限
result = subprocess.run(grant_cmd, capture_output=True, text=True, timeout=15)
if result.returncode == 0:
logging.info(f"设备 {device_id}使用root权限成功授予 {package} 权限: {permission}")
return True
else:
logging.error(f"设备 {device_id}即使使用root权限也无法授予 {package} 权限 {permission}: {result.stderr.strip()}")
return False
else:
return False
except subprocess.CalledProcessError as e:
logging.error(f"设备 {device_id}ADB 命令执行失败,返回码 {e.returncode}")
logging.error(f"标准输出:{e.stdout.strip()}")
logging.error(f"错误输出:{e.stderr.strip()}")
return False
except Exception as e:
logging.error(f"设备 {device_id}:处理 {package} 时发生未知错误:{str(e)}")
return False
# def grant_appium_permissions(device_id: str) -> bool:
# """
# 为 Appium UiAutomator2 服务授予 WRITE_SECURE_SETTINGS 权限
# :param device_id: 设备 ID可通过 `adb devices` 查看)
# :return: 权限授予是否成功
# """
# # 首先检查设备连接
# if not check_device_connection(device_id):
# return False
# packages_to_grant = [
# "io.appium.settings",
# "io.appium.uiautomator2.server",
# "io.appium.uiautomator2.server.test"
# ]
# # 添加其他可能需要的权限
# permissions_to_grant = [
# "android.permission.WRITE_SECURE_SETTINGS",
# "android.permission.CHANGE_CONFIGURATION", # 备选权限
# "android.permission.DUMP", # 调试权限
# ]
# success_count = 0
# total_attempted = 0
# # 检查并授予权限
# for package in packages_to_grant:
# if not is_package_installed(device_id, package):
# logging.warning(f"设备 {device_id}:包 {package} 未安装,跳过权限授予")
# continue
# for permission in permissions_to_grant:
# total_attempted += 1
# result = grant_single_permission(device_id, package, permission)
# if result:
# success_count += 1
# try:
# grant_cmd = [
# "adb", "-s", device_id,
# "shell", "pm", "grant", package,
# "android.permission.WRITE_SECURE_SETTINGS"
# ]
# result = subprocess.run(grant_cmd, capture_output=True, text=True, timeout=15)
# if result.returncode == 0:
# logging.info(f"设备 {device_id}:已成功授予 {package} 权限")
# else:
# logging.warning(f"设备 {device_id}:授予 {package} 权限失败: {result.stderr.strip()}")
# # 尝试使用root权限
# if "security" in result.stderr.lower() or "permission" in result.stderr.lower():
# logging.info(f"设备 {device_id}尝试使用root权限授予 {package} 权限")
# root_cmd = ["adb", "-s", device_id, "root"]
# subprocess.run(root_cmd, capture_output=True, text=True, timeout=10)
# time.sleep(2) # 等待root权限生效
# # 再次尝试授予权限
# result = subprocess.run(grant_cmd, capture_output=True, text=True, timeout=15)
# if result.returncode == 0:
# logging.info(f"设备 {device_id}使用root权限成功授予 {package} 权限")
# else:
# logging.error(f"设备 {device_id}即使使用root权限也无法授予 {package} 权限: {result.stderr.strip()}")
# except subprocess.CalledProcessError as e:
# logging.error(f"设备 {device_id}ADB 命令执行失败,返回码 {e.returncode}")
# logging.error(f"标准输出:{e.stdout.strip()}")
# logging.error(f"错误输出:{e.stderr.strip()}")
# except Exception as e:
# logging.error(f"设备 {device_id}:处理 {package} 时发生未知错误:{str(e)}")
# # 最终验证
# logging.info(f"设备 {device_id}权限授予过程完成建议重启设备或Appium服务使更改生效")
# return True
def grant_appium_permissions(device_id: str, require_all: bool = False) -> bool:
"""
修复版:为 Appium 授予权限(使用正确的方法)
"""
logging.info(f"设备 {device_id}开始设置Appium权限")
# 1. 使用系统设置命令替代原来的pm grant尝试
logging.info("使用系统设置命令...")
system_commands = [
["adb", "-s", device_id, "shell", "settings", "put", "global", "window_animation_scale", "0"],
["adb", "-s", device_id, "shell", "settings", "put", "global", "transition_animation_scale", "0"],
["adb", "-s", device_id, "shell", "settings", "put", "global", "animator_duration_scale", "0"],
["adb", "-s", device_id, "shell", "settings", "put", "system", "screen_off_timeout", "86400000"],
]
success_count = 0
for cmd in system_commands:
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
success_count += 1
logging.info(f" 成功: {' '.join(cmd[3:])}")
else:
logging.warning(f" 失败: {' '.join(cmd[3:])}")
except:
logging.warning(f" 异常: {' '.join(cmd[3:])}")
# 2. 授予可自动授予的权限
logging.info("授予基础权限...")
grantable = [
"android.permission.INTERNET",
"android.permission.ACCESS_NETWORK_STATE",
"android.permission.ACCESS_WIFI_STATE",
]
for perm in grantable:
cmd = ["adb", "-s", device_id, "shell", "pm", "grant", "io.appium.settings", perm]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
success_count += 1
logging.info(f" 成功授予: {perm.split('.')[-1]}")
else:
logging.debug(f" 跳过: {perm.split('.')[-1]}")
# 3. 返回结果
logging.info(f"设置完成,成功项数: {success_count}")
if require_all:
return success_count == (len(system_commands) + len(grantable))
else:
return success_count > 0 # 只要有成功项就返回True
def check_appium_compatibility(device_id: str) -> dict:
"""
检查Appium兼容性
:return: 兼容性报告字典
"""
try:
# 获取Android版本
version_cmd = ["adb", "-s", device_id, "shell", "getprop", "ro.build.version.release"]
result = subprocess.run(version_cmd, capture_output=True, text=True, timeout=10)
android_version = result.stdout.strip() if result.returncode == 0 else "未知"
report = {
"device_id": device_id,
"android_version": android_version,
"compatibility": "unknown",
"notes": [],
"suggestions": []
}
try:
version_num = float(android_version.split('.')[0])
if version_num >= 11:
report["compatibility"] = "limited"
report["notes"].append("Android 11+ 对WRITE_SECURE_SETTINGS权限限制非常严格")
report["suggestions"].append("使用--no-reset参数启动Appium")
report["suggestions"].append("设置autoGrantPermissions=false")
elif version_num >= 10:
report["compatibility"] = "moderate"
report["notes"].append("Android 10 限制了WRITE_SECURE_SETTINGS权限")
report["suggestions"].append("可尝试使用root权限的设备")
elif version_num >= 9:
report["compatibility"] = "good"
report["notes"].append("Android 9 兼容性较好")
else:
report["compatibility"] = "excellent"
report["notes"].append("Android 8或以下版本完全兼容")
except (ValueError, IndexError):
report["notes"].append("无法解析Android版本")
return report
except Exception as e:
logging.error(f"检查兼容性时出错: {str(e)}")
return {"device_id": device_id, "error": str(e)}
# 使用示例
if __name__ == "__main__":
# 获取设备ID示例
devices_cmd = ["adb", "devices"]
result = subprocess.run(devices_cmd, capture_output=True, text=True)
if result.returncode == 0:
lines = result.stdout.strip().split('\n')[1:] # 跳过第一行标题
for line in lines:
if line.strip() and "device" in line:
device_id = line.split('\t')[0]
logging.info(f"找到设备: {device_id}")
grant_appium_permissions(device_id)
else:
logging.error("无法获取设备列表请确保ADB已正确安装且设备已连接")