最新消息:20210917 已从crifan.com换到crifan.org

【已解决】iOS自动化操作设置出错:启动设置后找不到无线局域网

设置 crifan 493浏览 0评论
折腾:
【未解决】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停止,要去找找代码如何写,是否有这方面的接口
openatx/facebook-wda: Facebook WebDriverAgent Python Client Library (not official)
# 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
是可以干掉的
启动后,结果:又是进入 无线局域网列表页。。。
奇怪了。
去参考:
openatx/facebook-wda: Facebook WebDriverAgent Python Client Library (not official)
# 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自动化操作设置出错:启动设置后找不到无线局域网

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
90 queries in 0.197 seconds, using 23.41MB memory