折腾:
【未解决】iOS自动化安装app:给当前WiFi去掉代理以及自动安装app后再恢复之前代理
期间,调试期间遇到一个情况:
【未解决】iOS自动化操作设置出错:启动设置后找不到无线局域网
调试遇到问题:

[200611 13:38:53][DevicesMethods.py 856] Not found element {'type': 'XCUIElementTypeStaticText', 'name': '无线局域网', 'enabled': 'true', 'parent_class_chains': ["/XCUIElementTypeCell[`name = '无线局域网' AND rect.x = 0 AND rect.width = 414`]"]}
背景是:之前已打开了设置,此时不是 设置的首页 而是 无线局域网 的列表页:

所以,要去想办法避免此问题。
为了完全避免,感觉最好是:
启动 设置之前,完全关闭掉设置
否则设置 还可能处于其他页面,也会遇到不支持的情况
此处启动
com.apple.Preferences
之前,先去完全stop停止,要去找找代码如何写,是否有这方面的接口
# terminate app c.session().app_terminate("com.apple.Health")
去试试
先去看了看代码
/Users/xxx/.pyenv/versions/3.8.0/Python.framework/Versions/3.8/lib/python3.8/site-packages/wda/__init__.py
def app_launch(self, 。。。 def app_activate(self, bundle_id): return self._session_http.post("/wda/apps/launch", { "bundleId": bundle_id, }) def app_terminate(self, bundle_id): return self._session_http.post("/wda/apps/terminate", { "bundleId": bundle_id, }) def app_state(self, bundle_id): 。。。
写代码
iOS_AppId_Settings = "com.apple.Preferences" # stop before start to avoid current page is not homepage of 设置 self.wdaClient.session().app_terminate(iOS_AppId_Settings)
调试看看
结果并没有用:
启动后,还是处于:无线局域网 列表页
所以,此处app_terminate并没有关闭掉app
再去试试
self.wdaClient().app_terminate(iOS_AppId_Settings)
结果:
File "/Users/xxx/dev/xxx/crawler/appAutoCrawler/AppCrawler/venv/lib/python3.8/site-packages/wda/__init__.py", line 1703, in __getattr__ return getattr(element, oper) AttributeError: 'Element' object has no attribute 'app_terminate'
报错,不支持。
参考
# get app state c.session().app_state("com.apple.Health")
先去看看,此处的 设置 是否的确是 正在运行,且处于 后台
突然发现之前写法是:
src/common/MainUtils.py
# self.wdaClient.session().app_terminate(self.appPackage) self.wdaClient.app_terminate(self.appPackage)
所以此处去改为:
self.wdaClient.app_terminate(iOS_AppId_Settings)
结果:
问题依旧。
还是去获取 设置 的当前状态,比较确定
curState = self.iOSGetAppState(iOS_AppId_Settings) logging.info("curState=%s", curState) def iOSGetAppState(self, appBundleId): """get iOS app state""" curAppState = self.wdaClient.app_state(appBundleId) logging.debug("curAppState=%s", curAppState) # -> 发生异常: TypeError, not all arguments converted during string formatting # curAppStateValue = curAppState["value"] # -> 发生异常: TypeError, tuple indices must be integers or slices, not str # curAppStateValue = curAppState["value"] """ { "value" : 4, "sessionId" : "5BBD460B-F420-461D-A5E3-244A74CDF5CE" } """ curAppStateValue = curAppState[0] logging.debug("curAppStateValue=%s", curAppStateValue) curStateEnum = ApplicationState(curAppStateValue) logging.debug("curStateEnum=%s", curStateEnum) return curStateEnum
调试
# <GenericDict, len() = 3> # curAppStateValue = curAppState[0] curAppStatus = curAppState.status curAppSessionId = curAppState.sessionId logging.debug("curAppStatus=%s, curAppSessionId=%s", curAppStatus, curAppSessionId) curAppStateValue = curAppState.value logging.debug("curAppStateValue=%s", curAppStateValue) curStateEnum = ApplicationState(curAppStateValue) logging.debug("curStateEnum=%s", curStateEnum)

<ApplicationState.RunningBackgroundSuspended: 2>
表示是在运行,但是是在后台 被暂停了
curState=ApplicationState.RunningBackgroundSuspended
那去手动杀掉,看看返回结果如何
此处,遇到之前问题:
当杀掉 设置 的app,重新调试时,结果wda的client就报错,连不上了。
-》推断是,确定是:杀掉最近运行的app,比如 AppStore,设置等,重新调试时,wda的挂了。
其中log中会显示:
t = 1822.22s Requesting snapshot of accessibility hierarchy for app with pid 52 2020-06-11 14:08:31.570725+0800 WebDriverAgentRunner-Runner[9228:3611864] Getting the most recent active application (out of 1 total items) 2020-06-11 14:10:48.151681+0800 WebDriverAgentRunner-Runner[9228:3611864] Getting the most recent active application (out of 1 total items)
即:
Getting the most recent active application (out of 1 total items)
只能重启wda的test manager才可以

<ApplicationState.NotRunning: 1>
就是:没有运行,是对的。
再去启动试试
结果:启动后,还是无线局域网列表页
-》说明是:
不是之前 设置 没有被关闭掉,而是之前退出最后的页面是 无线局域网的列表页
-》反推:要确保之前 设置 被关闭时,退出时,要处于 主页,而不能是其他页面
否则后续,即使已完全关闭了 设置,重新打开时,都会保留在 之前页面
此处之前页面是 无线局域网列表页,所以就是处在 无线局域网列表页,而不是我们希望的:设置的主页。
此处故意再去试试:
杀掉 设置时,处于:通用 页面,重新去启动,看看是否处于:通用 页面
手动点击时,是不会的,是会进入主页的。
换代码启动试试,也是没问题,会进入主页的。
那看来是:
对于 无线局域网页面,很特殊,杀掉之前,如果处于 无线局域网列表页,重启后就会进入 这个 无线局域网列表页
也看来 手动和 代码启动,效果是一样的
那手动多去测试测试其他情况
无线局域网列表页 和 WiFi详情页 杀掉后,重启设置,都不会进入之前页面,都还是 设置主页
所以,之前很是奇怪,为何会进入后,直接进入 无线局域网列表页
先去测另外的:
代码中 设置 后台运行,关闭掉,看看状态十分变化
[200611 14:21:57][DevicesMethods.py 2589] before terminal: curState=ApplicationState.RunningBackgroundSuspended [200611 14:21:59][DevicesMethods.py 2596] after terminal: curState=ApplicationState.NotRunning
是可以干掉的
启动后,结果:又是进入 无线局域网列表页。。。
奇怪了。
去参考:
# launch without terminate app (WDAEmptyResponseError might raise) c.session().app_activate("com.apple.Health") # same as app_launch
试试app_activate或,找找是否有app_launch
从注释看:app_launch会先terminate app,再launch
之前代码也看到是有的:app_launch的
所以去试试
另外注意到
/Users/xxx/.pyenv/versions/3.8.0/Python.framework/Versions/3.8/lib/python3.8/site-packages/wda/__init__.py
def deactivate(self, duration): """Put app into background and than put it back Args: - duration (float): deactivate time, seconds """ return self._session_http.post('/wda/deactivateApp', dict(duration=duration))
有 非激活 app,像是按home,让app进入后台运行
后续有空需要用到,再去试试
不过这次的:
[200611 14:26:47][DevicesMethods.py 2589] before terminal: curState=ApplicationState.RunningForeground [200611 14:26:48][DevicesMethods.py 2596] after terminal: curState=ApplicationState.NotRunning
干掉后,再去代码的launch启动,至少是进入设置主页了。
多测试其他情况试试
期间,去解决:
【已解决】Python代码logging打印报错:TypeError not all arguments converted during string formatting
此处,先去terminate,再去launch,貌似很稳定:确保启动后可以进入设置主页,而不是 之前的 无线局域网的列表页
再多测试看看
另外,再去:
【已解决】整理和优化facebook-wda的app管理相关通用功能和函数
【总结】
至此,启动 设置 之前,先去 terminate终止 设置(如果有,不管是 前台运行,还是 后台运行 的 设置 的话),再去launch启动,即可确保启动后的 设置,是设置主页,而不会是之前,偶尔会出现的 无线局域网列表页 了。
相关代码:
def iOSGetAppState(self, appBundleId): """get iOS app state Args: appBundleId (str): iOS app bundle id Returns: bool, enum/dict: true, app status enum false, error info dict Raises: """ curAppState = self.wdaClient.app_state(appBundleId) logging.debug("curAppState=%s", curAppState) """ { "value" : 4, "sessionId" : "5BBD460B-F420-461D-A5E3-244A74CDF5CE" } """ # # <GenericDict, len() = 3> # # curAppStateValue = curAppState[0] # # curAppStatus = curAppState.status # # curAppSessionId = curAppState.sessionId # # logging.debug("curAppStatus=%s, curAppSessionId=%s", curAppStatus, curAppSessionId) # curAppStateValue = curAppState.value # logging.debug("curAppStateValue=%s", curAppStateValue) # curStateEnum = ApplicationState(curAppStateValue) # logging.debug("curStateEnum=%s", curStateEnum) # return curStateEnum isGetOk, respInfo = self.processWdaResponse(curAppState) if isGetOk: respValue = respInfo curStateEnum = ApplicationState(respValue) logging.debug("curStateEnum=%s", curStateEnum) respInfo = curStateEnum return isGetOk, respInfo def iOSTerminateApp(self, appBundleId): """Terminate iOS app Args: appBundleId (str): iOS app bundle id Returns: bool, bool/str: true, bool True: terminal Ok False: terminal fail eg: current not running 设置, if terminal, return False false, str: error message Raises: """ # isTerminalOk = False # respInfo = None # self.wdaClient.session().app_terminate(appBundleId) # self.wdaClient().app_terminate(appBundleId) terminateResp = self.wdaClient.app_terminate(appBundleId) logging.debug("terminateResp=%s", terminateResp) # respStatus = resp.status # respValue = resp.value # respSessionId = resp.sessionId # logging.info("respStatus=%s, respValue=%s, respSessionId", respStatus, respValue, respSessionId) # if respStatus == 0: # isTerminalOk = True # respInfo = None # else: # errInfo = { # "status": respStatus, # "value": respValue, # } # respInfo = errInfo isTerminalOk, respInfo = self.processWdaResponse(terminateResp) return isTerminalOk, respInfo def iOSLaunchApp(self, appBundleId): """Launch iOS app Args: appBundleId (str): iOS app bundle id Returns: bool, None/str: true, None false, str: error message Raises: """ launchResp = self.wdaClient.app_launch(appBundleId) logging.debug("launchResp=%s", launchResp) isLaunchOk, respInfo = self.processWdaResponse(launchResp) return isLaunchOk, respInfo def processWdaResponse(self, wdaResponse): """Process common wda (http post) response Args: Returns: bool, ?/dict: true, response value false, error info dict Raises: """ isRespOk = False respInfo = None logging.debug("wdaResponse=%s", wdaResponse) respStatus = wdaResponse.status respValue = wdaResponse.value respSessionId = wdaResponse.sessionId logging.debug("respStatus=%s, respValue=%s, respSessionId", respStatus, respValue, respSessionId) if respStatus == 0: isRespOk = True respInfo = respValue else: isRespOk = False errInfo = { "status": respStatus, "value": respValue, "sessionId": respSessionId, } respInfo = errInfo return isRespOk, respInfo def settingsDisableWiFiProxy(self): """in settings, find current WiFi, find and disable its proxy if existed Args: Returns: bool, dict/str: true, proxy info dict: found and disable proxy OK, return proxy info if no proxy, proxy info dict is empty false, str: occure some error, return error message Raises: """ isProcessdOk = False respInfo = None iOS_AppId_Settings = "com.apple.Preferences" isGetOk, curState = self.iOSGetAppState(iOS_AppId_Settings) logging.info("before terminal: curState=%s", curState) # stop before start to avoid current page is not homepage of 设置 isTerminalOk, respInfo = self.iOSTerminateApp(iOS_AppId_Settings) logging.info("isTerminalOk=%s, respInfo=%s", isTerminalOk, respInfo) isGetOk, curState = self.iOSGetAppState(iOS_AppId_Settings) logging.info("after terminal: curState=%s", curState) # settingsSession = self.wdaClient.session(iOS_AppId_Settings) # logging.debug("settingsSession=%s" % settingsSession) # launchResult = self.wdaClient.app_launch(iOS_AppId_Settings) # logging.debug("launchResult=%s", launchResult) isLaunchOk, respInfo = self.iOSLaunchApp(iOS_AppId_Settings) logging.info("isLaunchOk=%s, respInfo=%s", isLaunchOk, respInfo) # logging.info("launchResult: value=%s, status=%s, sessionId=%s", launchResult.value, launchResult.status, launchResult.sessionId) # launchResult: value=None, status=0, sessionId=79A39B72-F5F9-4A01-8E58-DD380452350A # logging.info("launchResult=%s", str(launchResult)) # launchResult=GenericDict(value=None, sessionId='79A39B72-F5F9-4A01-8E58-DD380452350A', status=0)
即可。
【后记 20200611】
折腾:
【未接】iOS自动化处理WiFi代理:配置代理页中从关闭切换到手动恢复之前代理配置信息
期间,已经实现了 强制关闭 设置,再重新启动,结果:

[200611 18:21:54][DevicesMethods.py 2177] isTerminalOk=True, respInfo=True [200611 18:21:56][DevicesMethods.py 856] Not found element {'type': 'XCUIElementTypeStaticText', 'name': '无线局域网', 'enabled': 'true', 'parent_class_chains': ["/XCUIElementTypeCell[`name = '无线局域网' AND rect.x = 0 AND rect.width = 414`]"]} [200611 18:21:56][DevicesMethods.py 856] Not found element {'type': 'XCUIElementTypeStaticText', 'name': '无线局域网', 'enabled': 'true', 'parent_class_chains': ["/XCUIElementTypeCell[`name = '无线局域网' AND rect.x = 0 AND rect.width = 414`]"]} [200611 18:21:56][DevicesMethods.py 856] Not found element {'type': 'XCUIElementTypeStaticText', 'name': '无线局域网', 'enabled': 'true', 'parent_class_chains': ["/XCUIElementTypeCell[`name = '无线局域网' AND rect.x = 0 AND rect.width = 414`]"]} [200611 18:21:56][DevicesMethods.py 856] Not found element {'type': 'XCUIElementTypeStaticText', 'name': '无线局域网', 'enabled': 'true', 'parent_class_chains': ["/XCUIElementTypeCell[`name = '无线局域网' AND rect.x = 0 AND rect.width = 414`]"]} [200611 18:21:57][DevicesMethods.py 856] Not found element {'type': 'XCUIElementTypeStaticText', 'name': '无线局域网', 'enabled': 'true', 'parent_class_chains': ["/XCUIElementTypeCell[`name = '无线局域网' AND rect.x = 0 AND rect.width = 414`]"]} [200611 18:21:57][common_utils.py 654] Still fail after 5 retry for <bound method DevicesMethods.iOSFromSettingsIntoWifiList of <src.AppCrawler.AppCrawler object at 0x1027fbeb0>>
情况是:
很明显,前面是terminate 成功了,但是,现在重新launch设置,但是设置却还是一进来就是: 无线局域网列表页
所以:此处有问题
设置 很可能就会 直接进入 无线局域网列表页
实在不行,可以去:
加上额外判断,如果进来的是 无线局域网页,也能支持
但是就是有点觉得诡异:
为何有时候就会出现这种:
启动设置后 直接进入 无线局域网 列表页
但是也懒得研究原因了。因为也找不到原因。
对了,要不去:
更改了WiFI的配置后,直接terminate干掉设置
看看是否会出现这个问题
# Note: after save, terminal Settings, try to avoid re-launch directly into WiFi list page iOS_AppId_Settings = "com.apple.Preferences" isTerminalOk, respInfo = self.iOSTerminateApp(iOS_AppId_Settings) logging.info("isTerminalOk=%s, respInfo=%s", isTerminalOk, respInfo)
去试试。
算了,不用试了。
先去支持:
【已解决】iOS自动化设置WiFi:如何启动设置并判断进入WiFi列表页
如此,即可实现:
启动 设置
如果(异常的)已经处于 WiFI列表页,则返回
如果 正常的 处于设置首页,再去找到并点击 无线局域网 进入 WiFi列表页,即可。
转载请注明:在路上 » 【已解决】iOS自动化操作设置出错:启动设置后找不到无线局域网