Windows Mobile Device Emulator In-Depth

本文详细介绍了WindowsMobileDeviceEmulator的启动方法、与PC的同步、上网设置、状态与配置选项等内容,旨在帮助初学者掌握其使用技巧。
  模拟器在Windows Mobile应用开发中的作用是越来越大了,UI的设计、程序的调试都可以用到它。本文讲述了Windows Mobile Device Emulator的使用方法和技巧,希望对初学者有用。 1. Launching the Device Emulator-启动模拟器
  方法1:从Visual Studio的Connect To Device启动。如在VS2008中,点击"Tools | Connect To Device",选择好需要连接的模拟器以后,点击"Connect"。如下图1所示:
  
  图1: Connect To Device来启动模拟器
  方法2:从 Device Emulator Manager启动。如在VS2008中,点击"Tools |Device Emulator Manager",选择好需要连接的模拟器以后,点击"Connect"。如下图2所示:
  
  图2: Device Emulator Manager来启动模拟器
  方法3:进入"\Program Files\Microsoft Device Emulator\1.0"目录,双击" dvcemumanager.exe", 从Device Emulator Manager启动,方法同2。
  2. Cradling the Device Emulator-模拟器和PC同步
  将模拟器和PC同步,也就是Cradling的意思。启动模拟器以后,可以在Device Emulator Manager中看到,图标变成了绿色,选中该模拟器,点击右键,选择" Cradle",这样就可以使模拟器和PC同步,如下图3所示。
  
  图3:Cradling the Device Emulator
  注意:VS2005只支持ActiveSync 4.0以后的版本。
  同步以后,用户可以建立Guest账户或者Standard partnership账户,其中,Standard partnership账户可以和PC上的日历、联系人、邮件等自动进行同步。
  3. Enabling Internet Connectivity from the Emulator模拟器上网
  首先,必须将模拟器和PC同步。然后,在模拟器中,点击" Start | Settings",在" Connections"中选择"Advanced",在" Networks"中选择" Internet connections",在其中选择" My ISP"。在" Programs that connect to a private network"中,也选择" My ISP"。如下图4所示:
  
  图4:模拟器上网设置
  注意:其实,只要将模拟器和PC同步以后,模拟器就可以上网了。以上的设置主要是为了说明清楚模拟器上网的设置。
  4. Emulator's States-模拟器状态
  当从Device Emulator中启动模拟器时,模拟器会恢复上一次保存的状态,包括RAM、ROM中的文件和模拟器的设置。如果要保存模拟器的状态并退出,可以选择File | Save State and Exit。如果出现由于模拟器保存的状态出错而无法启动的情况(比如串口映射等设置),可以在Device Emulator Manager中选择该模拟器,然后点击右键,在弹出的选项中,选择Clear Save State,如下图5所示,这样,模拟器就可以正常启动了。
  
  图6:清除模拟器状态 5. Emulator's Configuration Options - 模拟器配置选项 模拟器配置选项里面可以设置很多功能。点击File | Configure 打开模拟器配置选项对话框。如下图1所示:
  
  图1:模拟器配置选项
  a. Host Key-主机键 指定主机键,可以是 None、Left-Alt 或 Right-Alt。这是一个特殊的开关,其值通常为 193。值 193 会将键盘功能键(F1、F2 等)映射到设备仿真程序的软键。如F1为"Phone",F2为"Contacts",如下图2所示:
  
  图2:Host Key所对应的键
  b. Share desktop computer's folders-设置模拟器存储卡路径 可以在模拟器中访问PC机目录,即通过"Storage Card"目录访问。具体方法为:在"Shared folder"中,选择需要访问的路径,然后就可以在"Storage Card"目录下访问,如下图3所示:
  
  图3:设置模拟器存储卡路径
  c. Customize the emulator's skin-定制模拟器外观
  在选项中点击"Display",出现如图4所示设置界面:
  
  图4:设置模拟器外观
  其中,Skin下的路径表示模拟器外观的配置文件。一般来说,定制模拟器外观,需要三个图形文件和一个XML配置文件。这三个图形文件包括:模拟器的默认外观、模拟器所有按键被按下和单个按键被按下时的按键区域图形,这些文件可以是bmp或者png类型。例如,我们打开所使用的WM6.1.4 Professional Emulator的skin目录,可以看到如下图5所示的4个文件:
  
  图5:skin目录中的文件
  其中的Video选项是指定 LCD 窗口的屏幕大小和位深度,其中Screen width、Screen height 和Color depth 为十进制值。例如:640x480x16。
  d. Network binding-网卡绑定
  在选项中点击"Network",出现如图6所示设置界面:
  
  图6:Network界面
  启用NE2000 PCMCIA 网络适配器,其中可选的 macaddress 是一个十二位数字的十六进制数,指定卡将绑定到哪个主机适配器。
  e. Peripherals-模拟器端口映射
  模拟器端口映射在模拟器调试中起到很大的作用。比如说串口映射(可以参考以前的文章ZigBee On Windows Mobile--3.模拟器和实物调试)和模拟蜂窝调试(Appointment over SMS on Windows Mobile)。在选项中点击" Peripherals",出现如图7所示设置界面:
  
  图7:Peripherals界面 通过串口映射,可以将串行端口0-2映射到PC机的串口上去,进行串口通信调试。
from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy from appium.options.android import UiAutomator2Options import time import traceback import logging from datetime import datetime # 日志配置 logging.basicConfig(level=logging.INFO) logger = logging.getLogger('AndroidAutoTest') # 测试结果记录 test_results = [] # 修复后的驱动程序初始化函数 def start_driver(): try: # 使用 UiAutomator2Options 代替旧版 desired_capabilities options = UiAutomator2Options() # 设置 Appium 选项 options.platform_name = 'Android' options.automation_name = 'UiAutomator2' options.device_name = 'emulator-5554' # 通用名称,实际通过 udid 识别设备 options.udid = 'emulator-5554' # 替换为你的设备ID (adb devices) options.app_package = 'com.brother.ptouch.iprintandlabel' # 替换为你的应用包名 options.app_activity = '.splash.SplashActivity' # 替换为主Activity options.no_reset = True options.full_reset = False options.new_command_timeout = 600 # 添加明确的 URL 格式和端口号 driver = webdriver.Remote( command_executor='http://localhost:4723', options=options ) return driver except Exception as e: logger.error(f"驱动初始化失败: {e}") import traceback traceback.print_exc() return None # 判断是否为“返回”界面(比如首页/启动页) def is_home_screen(driver, home_texts=["首页", "主页", "Home"]): source = driver.page_source for text in home_texts: if text in source: return True return False # 模拟返回操作 def go_back(driver): try: driver.press_keycode(4) # 模拟返回键 (KEYCODE_BACK) time.sleep(1.5) return True except Exception as e: logger.warning(f"返回失败: {e}") return False # 输入随机文本到 EditText def fill_edit_text(element): try: placeholder = element.get_attribute("text") or element.get_attribute("content-desc") or "" hint = element.get_attribute("hint") or "" input_text = f"TestInput_{hash(placeholder + hint) % 10000}" element.click() element.clear() element.send_keys(input_text) logger.info(f"已输入文本: {input_text}") return True except Exception as e: logger.error(f"输入失败: {e}") return False # 分析并操作当前页面所有元素 def explore_current_page(driver, visited_pages, max_depth=5, current_depth=0): if current_depth > max_depth: logger.info("达到最大递归深度,停止探索") return try: page_source = driver.page_source if page_source in visited_pages: logger.info("页面已访问过,返回...") return visited_pages.add(page_source) # 查找所有可点击和可输入元素 clickable_elements = driver.find_elements(AppiumBy.XPATH, "//*[@clickable='true' or @long-clickable='true']") edittext_elements = driver.find_elements(AppiumBy.CLASS_NAME, "android.widget.EditText") found_new_page = False # 处理输入框 for elem in edittext_elements: try: if elem.is_displayed() and elem.is_enabled(): result = fill_edit_text(elem) test_results.append({ "action": "input", "element": elem.get_attribute("resource-id") or elem.get_attribute("content-desc") or "EditText", "success": result, "timestamp": datetime.now().isoformat() }) time.sleep(1) found_new_page = True except Exception as e: test_results.append({ "action": "input", "element": "unknown", "success": False, "error": str(e), "timestamp": datetime.now().isoformat() }) # 处理可点击元素 for idx, elem in enumerate(clickable_elements): try: if not elem.is_displayed() or not elem.is_enabled(): continue # 获取元素描述信息 desc = elem.get_attribute("content-desc") or "" text = elem.get_attribute("text") or "" res_id = elem.get_attribute("resource-id") or "" class_name = elem.get_attribute("class") # 忽略某些系统返回按钮或导航栏图标(可选优化) if "navigation" in res_id.lower() or "back" in desc.lower(): continue logger.info(f"尝试点击: {text} | {desc} | {res_id}") # 记录点击前页面状态 before_page = driver.page_source elem.click() time.sleep(2) # 等待页面跳转 after_page = driver.page_source success = before_page != after_page if success: found_new_page = True # 进入新页面继续探索 explore_current_page(driver, visited_pages, max_depth, current_depth + 1) # 返回上一页 go_back(driver) time.sleep(1.5) test_results.append({ "action": "click", "element": f"{text}/{desc}/{res_id}", "class": class_name, "success": True, "navigated": success, "timestamp": datetime.now().isoformat() }) except Exception as e: error_msg = traceback.format_exc() test_results.append({ "action": "click", "element": f"{elem.get_attribute('text')}/Unknown", "success": False, "error": error_msg, "timestamp": datetime.now().isoformat() }) logger.error(f"点击元素失败: {e}") # 如果没有发现新页面,尝试返回一级再继续 if not found_new_page and current_depth == 0: logger.info("未发现新页面,结束探索") return except Exception as e: logger.error(f"页面探索出错: {e}") test_results.append({ "action": "explore", "success": False, "error": str(e), "timestamp": datetime.now().isoformat() }) # 生成简单文本测试报告 def generate_report(): report_path = f"test_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt" with open(report_path, "w", encoding="utf-8") as f: f.write("=== Android 自动化遍历测试报告 ===\n") f.write(f"开始时间: {test_results[0]['timestamp'] if test_results else 'N/A'}\n") f.write(f"总操作数: {len(test_results)}\n") successes = [r for r in test_results if r.get("success")] failures = [r for r in test_results if not r.get("success")] f.write(f"成功操作: {len(successes)}\n") f.write(f"失败操作: {len(failures)}\n\n") f.write("详细日志:\n") for res in test_results: action = res['action'] elem = res['element'] ts = res['timestamp'] if res['success']: f.write(f"[{ts}] {action.upper()}: {elem} ✅\n") else: err = res.get('error', 'Unknown') f.write(f"[{ts}] {action.upper()}: {elem} ❌ 错误: {err[:100]}...\n") logger.info(f"测试报告已生成: {report_path}") return report_path # 主函数 def main(): driver = None try: logger.info("正在启动 Appium 驱动...") driver = start_driver() time.sleep(3) if driver is None: logger.error("无法启动Appium驱动,请检查:") logger.error("1. Appium服务器是否已启动(运行 appium 命令)") logger.error("2. 设备是否连接(运行 adb devices 确认)") logger.error("3. 设备ID和包名配置是否正确") return visited_pages = set() logger.info("开始遍历测试...") explore_current_page(driver, visited_pages, max_depth=4) logger.info("测试完成,正在生成报告...") report = generate_report() print(f"✅ 报告已保存至: {report}") except Exception as e: logger.critical(f"测试过程发生严重错误: {e}") traceback.print_exc() finally: if driver: driver.quit() if __name__ == '__main__': main()
10-18
### ADB 命令提示设备未找到问题的解决方案 当使用 ADB 命令时提示 `error: device 'emulator-5554' not found`,通常表示 ADB 服务未能正确识别连接的设备或模拟器。该问题可能由 ADB 服务未启动、设备未正确连接、端口冲突或模拟器未正常运行等原因引起。 #### 1. 启动 ADB 服务 如果 ADB 服务未运行,设备将无法被识别。可以通过以下命令手动启动 ADB 服务: ```bash adb start-server ``` 该命令会启动 ADB 后台服务,确保设备连接后能够被正确识别 [^1]。 #### 2. 检查 ADB 版本与路径 若 ADB 版本过旧或路径配置错误,可能导致设备识别失败。可以通过以下命令查看当前 ADB 版本信息: ```bash adb --version ``` 输出示例: ``` Android Debug Bridge version 1.0.40 Version 29.0.1-5303910 Installed as C:\SDK\platform-tools\adb.exe ``` 确保使用的是最新版本的 ADB 工具,并且环境变量中已正确配置 `adb.exe` 所在路径 [^2]。 #### 3. 重启 ADB 服务并重新连接设备 若设备仍无法识别,可以尝试重启 ADB 服务并重新连接设备: ```bash adb kill-server adb start-server ``` 在设备重新连接后,使用以下命令查看是否识别到设备: ```bash adb devices ``` 若设备列表为空,则可能是设备驱动未正确安装或 USB 调试模式未启用 [^1]。 #### 4. 检查模拟器运行状态 当使用模拟器时,若模拟器未正常启动或内存配置过低,也可能导致设备无法识别。可以尝试在 AVD Manager 中编辑模拟器配置,增加内存至 512 MB 或更高,以避免因内存不足导致的启动失败 [^3]。 #### 5. 检查设备存储空间 在运行模拟器期间,若设备存储空间不足,可能导致 ADB 无法正常安装应用或识别设备。可以通过以下命令查看设备存储情况: ```bash adb shell df ``` 如果发现 `/data` 或其他关键分区已满,可尝试清除部分应用数据或卸载不必要的应用 [^4]。 --- ### 相关问题 1. 如何使用 ZIP 工具验证 JAR 文件的完整性? 2. 在 Maven 项目中如何清理本地缓存并重新下载依赖? 3. 如何使用校验工具确保 WAR 文件上传未损坏? 4. Java 中 ZIP 文件的结束标记(END header)作用是什么? 5. Gradle 缓存目录位置在哪些操作系统中通常位于何处?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值