前言
在苹果的官方文档 https://developer.apple.com/safari/tools/,我们可以看到Safari包含Web Inspector,这是一个功能强大的工具,可轻松修改,调试和优化网站,以在两个平台上实现最佳性能和兼容性。借助自适应设计模式,您甚至可以预览网页以获取各种屏幕尺寸,方向和分辨率。要访问这些工具,请在Safari的“高级”偏好设置中启用“开发”菜单。
Web Inspector是您的命令中心,可让您快速轻松地访问Web浏览器中包含的最丰富的开发工具集。它可以帮助您检查网页上的所有资源和活动,从而使跨macOS,iOS和tvOS的开发更加高效。简洁统一的设计将每个核心功能放在一个单独的选项卡中,您可以对其进行重新排列以适合您的工作流程。在macOS Sierra中,您可以发现新的方法来使用时间轴调试内存,并使用控件的微调样式来调整150多种最常见的CSS属性。
ios_webkit_debug_proxy 原理
所以关于iOS获取WebView和Safari上的Elements,需要用到Web Inspector库。
Appium借助ios_webkit_debug_proxy来获取WebView和Safari上的Elements。
ios_webkit_debug_proxy(又名iwdp)通过websocket连接代理来自usbmuxd守护进程的请求,允许开发人员在真实和模拟的iOS设备上向MobileSafari和UIWebViews发送命令。
Source
-
src / ios_webkit_debug_proxy_main.c-
“main”函数 -
src / ios_webkit_debug_proxy.c
-WebInspector至WebKit远程调试协议转换器 -
src / webinspector.c
-iOS WebInspector库 -
src / device_listener.c
-iOS设备添加/删除侦听器 -
SRC / websocket.c-
WebSocket库 -
公用事业:
- SRC / char_buffer.c字节的缓冲区
- SRC / hash_table.c字典
- SRC / port_config.c解析DEVICE_ID:端口配置文件
- SRC / socket_manager.c选择基于套接字的控制器
设计如下如
各种客户端如下所示
ios_webkit_debug_proxy的主要组件是:
监听iOS设备添加/删除事件的device_listener
每个设备的(端口,webinspector)对,例如:
[(端口9222 <-> iphoneX的检查器,
(端口9223 <-> iphoneY的检查器,...]
零个或多个活动的WebSocket客户端,例如:
[websocketA已连接到:9222 / devtools / page / 7,...]
一个处理所有套接字I / O的socket_manager
device_listener头文件
`// Google BSD license [https://developers.google.com/google-bsd-license](https://developers.google.com/google-bsd-license)`
`// Copyright 2012 Google Inc. wrightt@google.com`
`//`
`// iOS device add/remove listener.`
`//`
`#ifndef DEVICE_LISTENER_H`
`#define DEVICE_LISTENER_H`
`#ifdef __cplusplus`
`extern` `"C"` `{`
`#endif`
`#include <stdbool.h>`
`#include <stdint.h>`
`#include <stdlib.h>`
`typedef` `uint8_t dl_status;`
`#define DL_ERROR 1`
`#define DL_SUCCESS 0`
`// Create a device add/remove connection.`
`// @param recv_timeout milliseconds, negative for non_blocking`
`// @result fd, or -1 for error`
`int` `dl_connect(``int` `recv_timeout);`
`struct` `dl_struct;`
`typedef` `struct` `dl_struct *dl_t;`
`dl_t dl_new();`
`void` `dl_free(dl_t self);`
`struct` `dl_private;`
`typedef` `struct` `dl_private *dl_private_t;`
`// iOS device add/remove listener.`
`struct` `dl_struct {`
`//`
`// Use these API:`
`//`
`// Call once after startup.`
`dl_status (*start)(dl_t self);`
`// Call to append data, calls on_attach/on_detach when we have a full`
`// input packet.`
`dl_status (*on_recv)(dl_t self, ``const` `char` `*buf, ssize_t length);`
`void` `*state;`
`bool` `*is_debug;`
`//`
`// Set these callbacks:`
`//`
`// Called to send "listen" and other output packets.`
`dl_status (*send_packet)(dl_t self, ``const` `char` `*buf, ``size_t` `length);`
`// Called by on_recv.`
`// @param device_id 40-character hex iOS device identifier.`
`// @param device_num usbmuxd device identifier`
`dl_status (*on_attach)(dl_t self, ``const` `char` `*device_id, ``int` `device_num);`
`dl_status (*on_detach)(dl_t self, ``const` `char` `*device_id, ``int` `device_num);`
`// For internal use only:`
`dl_private_t private_state;`
`};`
`#ifdef __cplusplus`
`}`
`#endif`
`#endif /* DEVICE_LISTENER_H */`
两个“公共API”函数
dl_status (*start)(dl_t self);
dl_status (*on_recv)(dl_t self, const char *buf, );
和三个“抽象”回调函数:
dl_status (*send)(dl_t self, const char *buf, size_t length);
dl_status (*on_attach)(dl_t self, const char *device_id);
dl_status (*on_detach)(dl_t self, const char *device_id);
以及供客户使用的字段: void *state
;
在examples / dl_client.c创建一个侦听器并设置缺少的回调:
int fd = dl_connect();
dl_t dl = dl_new(); // sets the "start" and "on_recv" functions
dl->state = fd; // for use by "my_send"
dl->send = my_send; // --> send((int)dl->state, buf, length);
dl->on_attach = my_on_attach; // --> printf("%s", device_id);
dl->on_detach = my_on_detach; // --> ditto
然后
dl->start();
最后,客户端将所有套接字输入转发到侦听器的“ on_recv”处理程序:
char buf[1024];
while (1) {
int len = recv(fd, buf, 1024);
if (dl->on_recv(dl, buf, len)) break;
}
其中,“ on_recv”会缓冲输入内容,并在有完整消息时调用“ my_on_message”。
请注意,“ on_recv”和“发送”功能从接口提取I / O,从而简化了调试和单元测试。
详细设计如下所示:
image.png
红色行由主“ ios_webkit_debug_proxy”控制。例如,尽管该图显示了从socket_manager的“ on_recv”到ios_webkit_debug_proxy的处理程序的直接红线,但这是通过ios_webkit_debug_proxy_main的“ iwdpm_on_recv(...)”实现的回调。这种设计将组件彼此隔离,并简化了离线和按组件的单元测试。
安装与使用
与Web视图进行交互Appium使用自定义的远程调试器建立连接。在模拟器上执行时,由于模拟器和Appium服务器在同一台计算机上,因此直接建立了连接。Appium可以自动执行WkWebView 和UIWebView 元素。
不管是iOS平台的web view还是safari浏览器都需要安装及设置以下三点:
1、brew install --HEAD libimobiledevice
2、brew install ios-webkit-debug-proxy
3、settings(设置) > safari(浏览器) > advanced(高级) > web inspector(网页检查器) -> on(打开)
启用ios-webkit-debug-proxy 要添加startIWDP:true
iOS WebView
import time
from appium import webdriver
class TestDemo:
def setup(self):
desired_caps = {}
desired_caps['platformName'] = 'iOS'
desired_caps['platformVersion'] = '11.2'
desired_caps['automationName'] = "xcuitest"
desired_caps['deviceName'] = 'wj'
desired_caps['udid'] = '7e2ab74a0a110f43a46009bda771f409f20e6ca2'
desired_caps['bundleId'] = 'com.xes.WJTest'
desired_caps['startIWDP'] = True;
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
self.driver.implicitly_wait(5)
def testWebView(self):
self.driver.switch_to.context(self.driver.contexts[1])
#打印网页源文件
print(self.driver.page_source)
def teardown(self):
self.driver.quit()
iOS Safari
import time
from appium import webdriver
class TestDemo:
def setup(self):
desired_caps = {}
desired_caps['platformName'] = 'iOS'
desired_caps['platformVersion'] = '11.2'
desired_caps['automationName'] = "xcuitest"
desired_caps['deviceName'] = 'wj'
desired_caps["browserName"] = "Safari"
desired_caps['udid'] = '7e2ab74a0a110f43a46009bda771f409f20e6ca2'
#desired_caps['bundleId'] = 'com.xes.WJTest'
#desired_caps['startIWDP'] = True;
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
self.driver.implicitly_wait(5)
def test_safair(self):
self.driver.get("https://testerhome.com")
time.sleep(3)
print(self.driver.page_source)
self.driver.find_element_by_link_text("社团").click()
time.sleep(1)
self.driver.find_element_by_link_text("BlackTest").click()
def teardown(self):
self.driver.quit()
网友评论