微软代码页标识符 (Code Page Identifiers)

代码页标识符 (Code Page Identifiers)

Identifiere
标识符
.NET Name
.NET 名称
Additional information其他信息
037IBM037IBM EBCDIC US-CanadaIBM EBCDIC US-Canada
437IBM437OEM United StatesOEM 美国
500IBM500IBM EBCDIC InternationalIBM EBCDIC 国际字符集
708ASMO-708Arabic (ASMO 708)阿拉伯语 (ASMO 708)
709Arabic (ASMO-449+, BCON V4)阿拉伯语 (ASMO-449+、BCON V4)
710Arabic - Transparent Arabic阿拉伯语 - 透明阿拉伯语
720DOS-720Arabic (Transparent ASMO); Arabic (DOS)阿拉伯文 (透明 ASMO) ; 阿拉伯语 (DOS)
737ibm737OEM Greek (formerly 437G); Greek (DOS)OEM 希腊 (原为 437G) ; 希腊文 (DOS)
775ibm775OEM Baltic; Baltic (DOS)OEM 波罗的海;波罗的海 (DOS)
850ibm850OEM Multilingual Latin 1; Western European (DOS)OEM 多语言拉丁语 1; 西欧 (DOS)
852ibm852OEM Latin 2; Central European (DOS)OEM 拉丁语 2; 中欧 (DOS)
855IBM855OEM Cyrillic (primarily Russian)OEM 西里尔文 (主要是俄罗斯)
857ibm857OEM Turkish; Turkish (DOS)OEM 土耳其语;土耳其语 (DOS)
858IBM00858OEM Multilingual Latin 1 + Euro symbolOEM 多语言拉丁语 1 + 欧元符号
860IBM860OEM Portuguese; Portuguese (DOS)OEM 葡萄牙语;葡萄牙语 (DOS)
861ibm861OEM Icelandic; Icelandic (DOS)OEM 冰岛语;冰岛 (DOS)
862DOS-862OEM Hebrew; Hebrew (DOS)OEM 希伯来语;希伯来语 (DOS)
863IBM863OEM French Canadian; French Canadian (DOS)OEM 加拿大法语;加拿大法语 (DOS)
864IBM864OEM Arabic; Arabic (864)OEM 阿拉伯语;阿拉伯语 (864)
865IBM865OEM Nordic; Nordic (DOS)OEM 北欧;北欧 (DOS)
866cp866OEM Russian; Cyrillic (DOS)OEM 俄语;西里尔文 (DOS)
869ibm869OEM Modern Greek; Greek, Modern (DOS)OEM 现代希腊文;希腊文、现代 (DOS)
870IBM870IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2IBM EBCDIC 多语言 / ROECE (拉丁文 2) ;IBM EBCDIC 多语言拉丁语 2
874windows-874ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows)泰语 (Windows)
875cp875IBM EBCDIC Greek ModernIBM EBCDIC Greek Modern
932shift_jisANSI/OEM Japanese; Japanese (Shift-JIS)ANSI/OEM 日语;日语 (Shift-JIS)
936gb2312ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)ANSI/OEM 简体中文 (中国、新加坡) ; 简体中文 (GB2312)
949ks_c_5601-1987ANSI/OEM Korean (Unified Hangul Code)ANSI/OEM 朝鲜语 (统一朝鲜文代码)
950big5ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)ANSI/OEM 繁体中文 (台湾;中国香港特别行政区) : 中国传统 (Big5)
1026IBM1026IBM EBCDIC Turkish (Latin 5)IBM EBCDIC 土耳其语 (拉丁语 5)
1047IBM01047IBM EBCDIC Latin 1/Open SystemIBM EBCDIC Latin 1/Open System
1140IBM01140IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)IBM EBCDIC US-Canada (037 + 欧元符号) ;IBM EBCDIC (美加欧)
1141IBM01141IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)IBM EBCDIC Germany (20273 + 欧元符号) ;IBM EBCDIC (德国 - 欧元)
1142IBM01142IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)IBM EBCDIC Denmark-Norway (20277 + 欧元符号) ;IBM EBCDIC (丹麦 - 挪威 - 欧元)
1143IBM01143IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)IBM EBCDIC Finland-Sweden (20278 + 欧元符号) ;IBM EBCDIC (芬兰 - 瑞典 - 欧元)
1144IBM01144IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)IBM EBCDIC 意大利 (20280 + 欧元符号) ;IBM EBCDIC (意大利 - 欧元)
1145IBM01145IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)IBM EBCDIC 拉丁语 America-Spain (20284 + 欧元符号) ;IBM EBCDIC (西班牙 - 欧元)
1146IBM01146IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)IBM EBCDIC 英国 (20285 + 欧元符号) ;IBM EBCDIC (英国 - 欧元)
1147IBM01147IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)IBM EBCDIC 法国 (20297 + 欧元符号) ;IBM EBCDIC (法欧)
1148IBM01148IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)IBM EBCDIC 国际 (500 + 欧元符号) ;IBM EBCDIC (国际 - 欧元)
1149IBM01149IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)IBM EBCDIC 冰岛 (20871 + 欧元符号) ;IBM EBCDIC (冰岛 - 欧元)
1200utf-16Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applicationsUnicode UTF-16,iso 10646) 的小端字节顺序 (BMP; 仅适用于托管应用程序
1201unicodeFFFEUnicode UTF-16, big endian byte order; available only to managed applicationsUnicode UTF-16,big endian 字节顺序;仅适用于托管应用程序
1250windows-1250ANSI Central European; Central European (Windows)ANSI 中欧;中欧 (Windows)
1251windows-1251ANSI Cyrillic; Cyrillic (Windows)ANSI 西里尔文;西里尔文 (Windows)
1252windows-1252ANSI Latin 1; Western European (Windows)ANSI 拉丁语 1; 西欧 (Windows)
1253windows-1253ANSI Greek; Greek (Windows)ANSI 希腊文;希腊文 (Windows)
1254windows-1254ANSI Turkish; Turkish (Windows)ANSI 土耳其语;土耳其语 (Windows)
1255windows-1255ANSI Hebrew; Hebrew (Windows)ANSI 希伯来语;希伯来语 (Windows)
1256windows-1256ANSI Arabic; Arabic (Windows)ANSI 阿拉伯语;阿拉伯语 (Windows)
1257windows-1257ANSI Baltic; Baltic (Windows)ANSI 波罗的海;波罗的海 (Windows)
1258windows-1258ANSI/OEM Vietnamese; Vietnamese (Windows)ANSI/OEM 越南语;越南语 (Windows)
1361JohabKorean (Johab)韩语 (Johab)
10000macintoshMAC Roman; Western European (Mac)MAC 罗马;西欧 (Mac)
10001x-mac-japaneseJapanese (Mac)日语 (Mac)
10002x-mac-chinesetradMAC Traditional Chinese (Big5); Chinese Traditional (Mac)MAC 繁体中文 (Big5) ; 繁体中文 (Mac)
10003x-mac-koreanKorean (Mac)朝鲜语 (Mac)
10004x-mac-arabicArabic (Mac)阿拉伯语 (Mac)
10005x-mac-hebrewHebrew (Mac)希伯来语 (Mac)
10006x-mac-greekGreek (Mac)希腊语 (Mac)
10007x-mac-cyrillicCyrillic (Mac)西里尔语 (Mac)
10008x-mac-chinesesimpMAC Simplified Chinese (GB 2312); Chinese Simplified (Mac)MAC 简体中文 (GB 2312) ; 简体中文 (Mac)
10010x-mac-romanianRomanian (Mac)罗马尼亚语 (Mac)
10017x-mac-ukrainianUkrainian (Mac)乌克兰语 (Mac)
10021x-mac-thaiThai (Mac)泰语 (Mac)
10029x-mac-ceMAC Latin 2; Central European (Mac)MAC 拉丁语 2; 中欧 (Mac)
10079x-mac-icelandicIcelandic (Mac)冰岛语 (Mac)
10081x-mac-turkishTurkish (Mac)土耳其语 (Mac)
10082x-mac-croatianCroatian (Mac)克罗地亚语 (Mac)
12000utf-32Unicode UTF-32, little endian byte order; available only to managed applicationsUnicode UTF-32, little endian 字节顺序;仅适用于托管应用程序
12001utf-32BEUnicode UTF-32, big endian byte order; available only to managed applicationsUnicode UTF-32, big endian 字节顺序;仅适用于托管应用程序
20000x-Chinese_CNSCNS Taiwan; Chinese Traditional (CNS)CNS 台湾;繁体中文 (CNS)
20001x-cp20001TCA TaiwanTCA 台湾
20002x_Chinese-EtenEten Taiwan; Chinese Traditional (Eten)Eten Taiwan: 中国传统 (Eten)
20003x-cp20003IBM5550 TaiwanIBM5550 台湾
20004x-cp20004TeleText TaiwanTeleText 台湾
20005x-cp20005Wang TaiwanWang 台湾
20105x-IA5IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5)IA5 (IRV 国际字母号 5,7 位) ; 西欧 (IA5)
20106x-IA5-GermanIA5 German (7-bit)IA5 德语 (7 位)
20107x-IA5-SwedishIA5 Swedish (7-bit)IA5 Swedish (7 位)
20108x-IA5-NorwegianIA5 Norwegian (7-bit)IA5 挪威语 (7 位)
20127us-asciiUS-ASCII (7-bit)US-ASCII (7 位)
20261x-cp20261T.61T. 61
20269x-cp20269ISO 6937 Non-Spacing AccentISO 6937 非间距着色
20273IBM273IBM EBCDIC GermanyIBM EBCDIC Germany
20277IBM277IBM EBCDIC Denmark-NorwayIBM EBCDIC Denmark-Norway
20278IBM278IBM EBCDIC Finland-SwedenIBM EBCDIC Finland-Sweden
20280IBM280IBM EBCDIC ItalyIBM EBCDIC 意大利
20284IBM284IBM EBCDIC Latin America-SpainIBM EBCDIC 拉丁语 America-Spain
20285IBM285IBM EBCDIC United KingdomIBM EBCDIC 英国
20290IBM290IBM EBCDIC Japanese Katakana ExtendedIBM EBCDIC 日语片假名扩展
20297IBM297IBM EBCDIC FranceIBM EBCDIC 法国
20420IBM420IBM EBCDIC ArabicIBM EBCDIC 阿拉伯语
20423IBM423IBM EBCDIC GreekIBM EBCDIC (希腊文)
20424IBM424IBM EBCDIC HebrewIBM EBCDIC 希伯来语
20833x-EBCDIC-KoreanExtendedIBM EBCDIC Korean ExtendedIBM EBCDIC 朝鲜语扩展
20838IBM-ThaiIBM EBCDIC ThaiIBM EBCDIC 泰语
20866koi8-rRussian (KOI8-R); Cyrillic (KOI8-R)俄语 (KOI8-R) ; 西里尔文 (KOI8-R)
20871IBM871IBM EBCDIC IcelandicIBM EBCDIC 冰岛语
20880IBM880IBM EBCDIC Cyrillic RussianIBM EBCDIC 西里尔文俄语
20905IBM905IBM EBCDIC TurkishIBM EBCDIC 土耳其语
20924IBM00924IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)IBM EBCDIC Latin 1/Open System (1047 + Euro 符号)
20932EUC-JPJapanese (JIS 0208-1990 and 0121-1990)日语 (JIS 0208-1990 和 0212-1990)
20936x-cp20936Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)简体中文 (GB2312) ; 简体中文 (GB2312-80)
20949x-cp20949Korean Wansung韩语 Wansung
21025cp1025IBM EBCDIC Cyrillic Serbian-BulgarianIBM EBCDIC 西里尔文 Serbian-Bulgarian
21027(deprecated)(已弃用)
21866koi8-uUkrainian (KOI8-U); Cyrillic (KOI8-U)乌克兰 (KOI8-U) ; 西里尔文 (KOI8-U)
28591iso-8859-1ISO 8859-1 Latin 1; Western European (ISO)ISO 8859-1 拉丁语 1; 西欧 (ISO)
28592iso-8859-2ISO 8859-2 Central European; Central European (ISO)ISO 8859-2 中欧;中欧 (ISO)
28593iso-8859-3ISO 8859-3 Latin 3ISO 8859-3 拉丁语 3
28594iso-8859-4ISO 8859-4 BalticISO 8859-4 波罗的海
28595iso-8859-5ISO 8859-5 CyrillicISO 8859-5 西里尔文
28596iso-8859-6ISO 8859-6 ArabicISO 8859-6 阿拉伯语
28597iso-8859-7ISO 8859-7 GreekISO 8859-7 希腊语
28598iso-8859-8ISO 8859-8 Hebrew; Hebrew (ISO-Visual)ISO 8859-8 希伯来语;希伯来语 (ISO-Visual)
28599iso-8859-9ISO 8859-9 TurkishISO 8859-9 土耳其语
28603iso-8859-13ISO 8859-13 EstonianISO 8859-13 爱沙尼亚语
28605iso-8859-15ISO 8859-15 Latin 9ISO 8859-15 拉丁语 9
29001x-EuropaEuropa 3欧罗巴 3
38598iso-8859-8-iISO 8859-8 Hebrew; Hebrew (ISO-Logical)ISO 8859-8 希伯来语;希伯来语 (ISO 逻辑)
50220iso-2022-jpISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)ISO 2022 日语,无半形片假名;日语 (JIS)
50221csISO2022JPISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)ISO 2022 日语与半形片假名;日语 (JIS-Allow 1 字节假名)
50222iso-2022-jpISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)ISO 2022 日语 JIS X 0201-1989; 日语 (JIS-Allow 1 字节假名 - SO/SI)
50225iso-2022-krISO 2022 KoreanISO 2022 朝鲜语
50227x-cp50227ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022)ISO 2022 简体中文;简体中文 (ISO 2022)
50229ISO 2022 Traditional ChineseISO 2022 繁体中文
50930EBCDIC Japanese (Katakana) ExtendedEBCDIC 日语 (片假名) 扩展
50931EBCDIC US-Canada and JapaneseEBCDIC US-Canada 和日语
50933EBCDIC Korean Extended and KoreanEBCDIC 朝鲜语扩展和朝鲜语
50935EBCDIC Simplified Chinese Extended and Simplified ChineseEBCDIC 简体中文 扩展和简体中文
50936EBCDIC Simplified ChineseEBCDIC 简体中文
50937EBCDIC US-Canada and Traditional ChineseEBCDIC US-Canada 和繁体中文
50939EBCDIC Japanese (Latin) Extended and JapaneseEBCDIC 日语 (拉丁语) 扩展和日语
51932euc-jpEUC JapaneseEUC 日语
51936EUC-CNEUC Simplified Chinese; Chinese Simplified (EUC)EUC 简体中文;简体中文 (EUC)
51949euc-krEUC KoreanEUC 朝鲜语
51950EUC Traditional ChineseEUC 繁体中文
52936hz-gb-2312HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)HZ-GB2312 简体中文;简体中文 (HZ)
54936GB18030Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)Windows XP及更高版本: GB18030 简体中文 (4 字节) ; 简体中文 (GB18030)
57002x-iscii-deISCII DevanagariISCII 梵文
57003x-iscii-beISCII BengaliISCII 孟加拉语
57004x-iscii-taISCII TamilISCII 泰米尔语
57005x-iscii-teISCII TeluguISCII 泰卢固语
57006x-iscii-asISCII AssameseISCII 阿萨姆语
57007x-iscii-orISCII OriyaISCII Odia
57008x-iscii-kaISCII KannadaISCII 埃纳德文
57009x-iscii-maISCII MalayalamISCII 马拉雅拉姆语
57010x-iscii-guISCII GujaratiISCII 古吉拉特语
57011x-iscii-paISCII PunjabiISCII 旁遮普语
65000utf-7Unicode (UTF-7)Unicode (UTF-7)
65001utf-8Unicode (UTF-8)Unicode (UTF-8)

* 翻译来自官网原文

备注:

当在不同计算机或在单台计算机上更改 ANSI 代码页时,可能会导致数据损坏。

为了获得最一致的结果,应用程序应尽可能使用 UTF-8 或 UTF-16。

扩展阅读

C:\own\app\python_code\.venv\Scripts\python.exe C:\own\app\python_code\work\IBL_click_all\full_automation.py 🚀 启动 Android 自动化测试框架... ℹ️ 应用已安装 📱 正在启动应用... 🔍 检测用户协议... 📄 用户协议页面已加载 👇 正在滚动协议内容... ✅ 第 7 次滑动后发现可点击的【I agree】按钮 ✅ 已点击【I agree】 💥 运行异常: AttributeError: 'AndroidAppExplorer' object has no attribute 'handle_printer_selection' 🧹 正在重置应用状态... ✅ 应用已卸载,状态重置完成 🔚 自动化流程全部完成 Process finished with exit code 0 from appium import webdriver from appium.options.android import UiAutomator2Options from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.common.exceptions import TimeoutException, NoSuchElementException, ElementNotInteractableException import time import os # ==================== 配置参数 ==================== APK_PATH = r"C:\own\download\iPL5.3.10_signed.apk" APP_PACKAGE = "com.brother.ptouch.iprintandlabel" APP_ACTIVITY = ".module.home.home.HomeActivity" MAX_RESTORE_ATTEMPTS = 2 MAX_BACK_OFFICE_COUNT = 3 MAX_RUNTIME = 600 # 最大运行时间:10分钟 # ==================== 创建 WebDriver ==================== def create_driver(): options = UiAutomator2Options() options.set_capability("platformName", "Android") options.set_capability("deviceName", "emulator-5554") # 修改为你的设备名(adb devices 查看) options.set_capability("automationName", "UiAutomator2") options.set_capability("noReset", False) # 每次都清空状态 options.set_capability("fullReset", False) # 不使用完全重置 options.set_capability("autoGrantPermissions", True) options.set_capability("newCommandTimeout", 600) options.set_capability("appPackage", APP_PACKAGE) options.set_capability("appActivity", APP_ACTIVITY) return webdriver.Remote('http://localhost:4723', options=options) # ==================== 安装 APK(如果未安装)==================== def install_app_if_needed(driver, apk_path): if not driver.is_app_installed(APP_PACKAGE): print(f"📦 正在安装应用: {apk_path}") if not os.path.exists(apk_path): raise FileNotFoundError(f"APK 文件不存在: {apk_path}") driver.install_app(apk_path) print("✅ 安装完成") else: print("ℹ️ 应用已安装") # ==================== 卸载应用(用于重置状态)==================== def reset_app_state(driver): print("🧹 正在重置应用状态...") if driver.is_app_installed(APP_PACKAGE): try: driver.remove_app(APP_PACKAGE) print("✅ 应用已卸载,状态重置完成") except Exception as e: print(f"⚠️ 卸载失败: {e}") else: print("ℹ️ 应用未安装,无需卸载") # ==================== 主探索类 ==================== class AndroidAppExplorer: def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(driver, 10) self.clicked_identifiers = set() self.recovery_history = [] self.restore_attempt_count = 0 self.start_time = time.time() def wait_for_page_load(self, timeout=10): """等待页面基本结构加载""" try: WebDriverWait(self.driver, timeout).until( EC.presence_of_element_located(( 'xpath', '//*[contains(@resource-id, "layout") or @class="android.widget.LinearLayout"]' )) ) time.sleep(1) except: pass def get_element_identifier(self, element): """生成唯一可读标识符""" parts = [] res_id = element.get_attribute("resourceId") text = element.get_attribute("text") content_desc = element.get_attribute("contentDescription") clazz = element.get_attribute("className") if res_id: parts.append(f"resId={res_id.split('/')[-1]}") if text and len(text) < 20: parts.append(f"text='{text}'") if content_desc: parts.append(f"desc='{content_desc}'") if clazz: simple_class = clazz.split('.')[-1] if simple_class not in ['View', 'ViewGroup']: parts.append(f"class={simple_class}") return " | ".join(parts) if parts else "unknown" def find_clickable_elements(self): """查找所有可点击且可见的元素""" xpath = '//*[(@clickable="true" or @focusable="true") and @displayed="true" and @enabled="true"]' try: elements = self.driver.find_elements('xpath', xpath) return [e for e in elements if e.is_displayed()] except: return [] def click_element_safely(self, element): """安全点击元素,防止重复点击""" identifier = self.get_element_identifier(element) if identifier in self.clicked_identifiers: return False try: # 滚动到可见 self.driver.execute_script("arguments[0].scrollIntoView(true);", element) time.sleep(0.5) element.click() print(f"🟢 点击成功: {identifier}") self.clicked_identifiers.add(identifier) time.sleep(1.5) return True except Exception as e: print(f"🔴 点击失败: {identifier}, 错误: {str(e)}") return False def is_popup_visible(self): """判断是否弹出浮层菜单(如 Spinner 下拉)""" try: # 常见浮层控件 popup_classes = [ 'android.widget.PopupWindow', 'android.widget.ListPopupWindow' ] for cls in popup_classes: if self.driver.find_elements('class name', cls): return True # CheckedTextView 出现在屏幕中间区域 items = self.driver.find_elements('class name', 'android.widget.CheckedTextView') for item in items: if item.is_displayed(): bounds = item.get_attribute("bounds") try: y1 = int(bounds.split(',')[1].split(']')[0]) if 200 < y1 < 1000: # 屏幕中上部 return True except: pass return False except: return False def handle_floating_popup(self): """处理浮层选择项(如 High / Low)""" if not self.is_popup_visible(): return False print("🎈 检测到浮层,尝试选择...") common_options = ["High", "Normal", "Low", "On", "Off", "Auto", "Cut Every Label"] for opt in common_options: try: elem = self.driver.find_element(By.XPATH, f'//android.widget.CheckedTextView[@text="{opt}"]') if elem.is_displayed(): elem.click() print(f"🪄 选择了浮层选项: {opt}") time.sleep(1.5) return True except: continue # 尝试点击第一个 try: first_item = self.driver.find_element( By.XPATH, '//android.widget.CheckedTextView[@displayed="true"][1]' ) first_item.click() print("🪄 选择了默认浮层项") time.sleep(1.5) return True except: print("❌ 无法选择浮层项,使用 back 关闭") try: self.driver.back() time.sleep(1) except: pass return False def handle_alert_popup(self): """处理系统或应用弹窗(如权限请求)""" alert_xpaths = [ '//android.widget.Button[contains(@text, "OK")]', '//android.widget.Button[contains(@text, "允许")]', '//android.widget.Button[contains(@text, "Allow")]', '//android.widget.Button[@text="YES"]' ] for xpath in alert_xpaths: try: btn = self.driver.find_element('xpath', xpath) if btn.is_displayed(): btn.click() print("✅ 自动处理了弹窗") time.sleep(1) return True except: continue return False def ensure_in_target_app(self): """确保当前在目标 App,支持短暂跳转(如浏览器)""" current_pkg = self.driver.current_package current_act = self.driver.current_activity if current_pkg == APP_PACKAGE: self.wait_for_page_load(1) return True allowed_packages = ["nexuslauncher", "chrome", "android", "packageinstaller"] if any(pkg in current_pkg.lower() for pkg in allowed_packages): print(f"⏸️ 暂时处于外部页面: {current_pkg}/{current_act}") # 记录恢复历史,防循环 key = (current_pkg, current_act) if self.recovery_history[-10:].count(key) >= 3: print("🛑 恢复循环检测,终止") return False self.recovery_history.append(key) try: self.driver.back() time.sleep(2) if self.driver.current_package == APP_PACKAGE: print("✅ 通过 back 返回目标 App") return True except: pass try: self.driver.activate_app(APP_PACKAGE) time.sleep(3) return self.driver.current_package == APP_PACKAGE except: return False return False def accept_user_agreement(self): """处理首次启动的用户协议(自动滚动 + 点击 I agree)""" print("🔍 检测用户协议...") try: # 等待协议标题出现 WebDriverWait(self.driver, 15).until( EC.presence_of_element_located(( 'xpath', '//*[contains(@text, "License Agreement") or contains(@text, "User")]' )) ) print("📄 用户协议页面已加载") # 定义查找“Agree”或“I agree”按钮的函数 def find_agree_button(): candidates = [ '//android.widget.Button[@text="Agree"]', '//android.widget.Button[@text="I agree"]', '//android.widget.Button[contains(@resource-id, "yes")]', ] for xpath in candidates: try: btn = self.driver.find_element(By.XPATH, xpath) if btn.is_displayed() and btn.is_enabled(): return btn except: continue return None # 先尝试直接点击(可能已经激活) agree_btn = find_agree_button() if agree_btn: print("✅ 发现【I agree】按钮,直接点击") agree_btn.click() time.sleep(3) return True # 否则开始滑动并轮询 print("👇 正在滚动协议内容...") for i in range(10): # 最多滑动10次 size = self.driver.get_window_size() x = size['width'] // 2 y_start = int(size['height'] * 0.8) y_end = int(size['height'] * 0.3) self.driver.swipe(x, y_start, x, y_end, 600) time.sleep(0.8) # 查找并尝试点击 agree_btn = find_agree_button() if agree_btn: print(f"✅ 第 {i + 1} 次滑动后发现可点击的【I agree】按钮") try: agree_btn.click() print("✅ 已点击【I agree】") time.sleep(3) return True except Exception as e: print(f"❌ 尝试点击失败: {e}") # 如果还找不到,用 uiautomator 强制点 try: self.driver.find_element( 'android uiautomator', 'new UiSelector().textContains("agree").clickable(true)' ).click() print("🪄 使用 uiautomator 强制点击【I agree】") time.sleep(3) return True except: print("❌ 无法找到或点击【I agree】按钮") return False except TimeoutException: print("🟢 未检测到用户协议,跳过") return True except Exception as e: print(f"⚠️ 协议处理异常: {type(e).__name__}: {e}") return False def explore_page(self): """主探索逻辑""" print("\n🔄 开始探索当前页面...") last_handled_popup = False explored_states = set() consecutive_back_count = 0 while True: if time.time() - self.start_time > MAX_RUNTIME: print("⏰ 探索超时,自动结束。") break if not self.ensure_in_target_app(): print("❌ 无法恢复至目标应用") break self.handle_alert_popup() if self.is_popup_visible() and not last_handled_popup: self.handle_floating_popup() last_handled_popup = True time.sleep(1) continue else: last_handled_popup = False elements = self.find_clickable_elements() if not elements: print("📭 当前页面无可点击元素") try: self.driver.back() print("🔙 返回上一页") time.sleep(2) consecutive_back_count += 1 if consecutive_back_count > MAX_BACK_OFFICE_COUNT: print("🏁 所有路径已探索完毕") break continue except: break # 页面指纹(activity + 前几个元素 ID/text) current_act = self.driver.current_activity element_fingerprint = "|".join(sorted([self.get_element_identifier(e) for e in elements[:5]])) page_key = f"{current_act}|{element_fingerprint[:60]}" if page_key in explored_states: print(f"🟡 已探索过此页面: {current_act}") try: self.driver.back() time.sleep(2) consecutive_back_count += 1 if consecutive_back_count > MAX_BACK_OFFICE_COUNT: print("🔚 探索完成") break continue except: break else: explored_states.add(page_key) consecutive_back_count = 0 clicked = False for elem in elements: if self.click_element_safely(elem): clicked = True break if not clicked: print("✅ 当前页无新元素可操作") try: self.driver.back() time.sleep(2) except: break def handle_printer_selection(self): """处理打印机选择页面:选择第一个可用设备 + 点击 Done""" print("🖨️ 检测是否需要选择打印机...") # 判断是否在打印机选择界面(根据常见特征) try: # 等待列表或标题出现 WebDriverWait(self.driver, 10).until( EC.presence_of_element_located(( 'xpath', '//android.widget.TextView[@text="Select Printer"] | ' '//android.widget.TextView[contains(@text, "Available Printers")]' )) ) print("✅ 进入打印机选择页面") # 尝试选择第一个非空的设备项 device_items = self.driver.find_elements( 'xpath', '//android.widget.CheckedTextView[@text and not(@text="")] | ' '//android.widget.TextView[@resource-id and @text and string-length(@text) > 2]' ) if device_items: first_device = device_items[0] try: first_device.click() print(f"✅ 选择了打印机: {first_device.get_attribute('text')}") except: print("🟡 无法点击设备项,可能已默认选中") else: print("ℹ️ 未发现可用打印机列表") # 查找并点击 Done 按钮(通常在右下角) done_buttons = [ '//android.widget.Button[@text="Done"]', '//android.widget.Button[@text="OK"]', '//android.widget.Button[contains(@resource-id, "ok_button")]', '//android.widget.Button[contains(@resource-id, "done")]' ] for xpath in done_buttons: try: done_btn = self.driver.find_element(By.XPATH, xpath) if done_btn.is_displayed() and done_btn.is_enabled(): done_btn.click() print("✅ 已点击【Done】进入主界面") time.sleep(3) return True except: continue # 如果没找到 Done,尝试返回键(兜底) print("⚠️ 未找到【Done】按钮,尝试返回") self.driver.back() time.sleep(2) return True except TimeoutException: print("🟢 无需选择打印机") return True except Exception as e: print(f"⚠️ 处理打印机选择失败: {e}") return True # 失败也不阻塞后续探索 # ==================== 主程序入口 ==================== if __name__ == "__main__": driver = None try: print("🚀 启动 Android 自动化测试框架...") # Step 1: 创建驱动 driver = create_driver() # Step 2: 安装 APK install_app_if_needed(driver, APK_PATH) # Step 3: 启动应用 print("📱 正在启动应用...") driver.activate_app(APP_PACKAGE) time.sleep(5) # Step 4: 创建探索器并处理初始化流程 explorer = AndroidAppExplorer(driver) # 依次处理初始化步骤 if not explorer.accept_user_agreement(): print("❌ 用户协议处理失败,终止运行") else: # 新增:处理打印机选择 explorer.handle_printer_selection() # Step 5: 开始探索 explorer.explore_page() except KeyboardInterrupt: print("\n👋 用户中断执行") except Exception as e: print(f"💥 运行异常: {type(e).__name__}: {e}") finally: # Step 6: 重置状态(卸载应用) if driver: reset_app_state(driver) driver.quit() print("🔚 自动化流程全部完成")
10-17
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值