Files
cjgc_upload/permissions.py
2026-02-02 11:47:53 +08:00

251 lines
10 KiB
Python
Raw 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
# 配置日志
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.WRITE_SECURE_SETTINGS",
"android.permission.CHANGE_CONFIGURATION",
"android.permission.DUMP",
]
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 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已正确安装且设备已连接")