Files
cjgc_screenshot/permissions.py
2026-02-09 15:50:41 +08:00

307 lines
13 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 权限处理
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, require_all: bool = False) -> bool:
# """
# 为 Appium UiAutomator2 服务授予权限
# :param device_id: 设备 ID
# :param require_all: 是否要求所有权限都成功授予
# :return: 权限授予是否成功根据require_all参数判断
# """
# # 首先检查设备连接
# 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.SET_ANIMATION_SCALE",
# "android.permission.CHANGE_CONFIGURATION",
# "android.permission.WRITE_SETTINGS",
# "android.permission.DISABLE_KEYGUARD",
# ]
# success_count = 0
# total_attempted = 0
# package_results = {}
# # 检查并授予权限
# for package in packages_to_grant:
# package_results[package] = {"installed": False, "permissions": {}}
# if not is_package_installed(device_id, package):
# logging.warning(f"设备 {device_id}:包 {package} 未安装,跳过权限授予")
# package_results[package]["installed"] = False
# continue
# package_results[package]["installed"] = True
# package_success = 0
# package_attempted = 0
# for permission in permissions_to_grant:
# total_attempted += 1
# package_attempted += 1
# result = grant_single_permission(device_id, package, permission)
# package_results[package]["permissions"][permission] = result
# if result:
# success_count += 1
# package_success += 1
# # 记录每个包的授权结果
# logging.info(f"设备 {device_id}:包 {package} 权限授予结果: {package_success}/{package_attempted}")
# # 统计和报告
# logging.info(f"设备 {device_id}:权限授予完成")
# logging.info(f"总计: 尝试 {total_attempted} 次,成功 {success_count} 次")
# # 检查每个包的关键权限
# critical_permission = "android.permission.WRITE_SECURE_SETTINGS"
# critical_failures = []
# for package, info in package_results.items():
# if info["installed"] and critical_permission in info["permissions"]:
# if not info["permissions"][critical_permission]:
# critical_failures.append(package)
# if critical_failures:
# logging.warning(f"设备 {device_id}:以下包的关键权限 {critical_permission} 授予失败: {', '.join(critical_failures)}")
# logging.warning("这可能会影响某些自动化功能,但基础测试通常不受影响")
# # 根据require_all参数返回结果
# if require_all:
# # 要求所有权限都成功
# if critical_failures:
# logging.error("关键权限授予失败无法继续require_all=True")
# return False
# return success_count == total_attempted
# else:
# # 不要求所有权限只要设备连接正常就返回True
# 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}")
# 1. 检查兼容性
report = check_appium_compatibility(device_id)
logging.info(f"兼容性报告: Android {report.get('android_version', '未知')} - {report.get('compatibility', '未知')}")
# 2. 授予权限(不要求全部成功)
success = grant_appium_permissions(device_id, require_all=False)
if success:
logging.info(f"设备 {device_id} 设置完成,可以开始测试")
else:
logging.warning(f"设备 {device_id} 权限授予有失败,但可能仍可进行基础测试")
# 3. 提供建议
if "suggestions" in report:
logging.info("建议:")
for suggestion in report["suggestions"]:
logging.info(f" - {suggestion}")
else:
logging.error("无法获取设备列表请确保ADB已正确安装且设备已连接")