性能数据了解
分析移动端H5性能数据,首先我们说说是哪些性能数据。白屏时间,白屏时间无论安卓还是iOS在加载网页的时候都会存在的问题,也是目前无法解决的;页面耗时,页面耗时指的是开始加载这个网页到整个页面load完成即渲染完成的时间;还有加载链接的一些性能数据,重定向时间,DNS解析时间,TCP链接时间,request请求时间,response响应时间,dom节点解析时间,page渲染时间,同时我们还需要抓取资源时序数据,什么是资源时序数据呢?每个网页是有很多个资源组成的,有.js、.png、.css、.script等等,我们就需要将这些每个资源链接的耗时拿到,是什么类型的资源,完整链接;对于客户来说有了这些还不够,还需要JS错误,页面的ajax请求。JS错误获取的当然是堆栈信息和错误类型。ajax请求一般是获取三个时间,响应时间,ajax下载时间,ajax回调时间。
上面分析的是能够获取到移动端H5的性能数据,这些数据怎么得到就是接下来要讲的了。数据获取是需要js来做的,都知道移动端是通过webView来加载网页的,js里面能通过performance这个接口来从webView内部api获取上面的那些数据,js获取的数据然后发给OC;那JS怎么样才能拿到这些数据呢,这就是最关键的,OC代码如何写才能让JS获取数据。
代码编写
有两种方法可以得到数据,先介绍用NSURLProtocol这个类获取数据。
iOS的UIWebView加载网页的时候会走进NSURLProtocol这个类,所以我们就需要在这个类里面作文章了,我们先用UIWebView加载一个链接,例如百度等等,然后创建一个继承NSURLProtocol的类。
NSURLProtocol里面有很多方法,就不一一介绍了,有一个startLoading的方法,我们在这个方法里面用NSURLConnection发送一个请求,设置代理,请求的request就是加载网页的request,因为NSURLProtocol有一个NSURLRequest的属性。
- (instancetype)initWithRequest:(NSURLRequest*)request delegate:(id)delegate startImmediately:(BOOL)startImmediately
这个就是请求的方法。
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
通过NSURLConnection设置代理,就需要写出代理方法,在其中一个代理方法里面能获得网页的代码,这就是我们最关键的地方,就是上面这个方法,将data用utf-8转码就会得到代码。
得到网页的代码有什么用呢?熟悉网页端代码的都知道,网页端的代码都是由很多标签组成,我们先找到<head>这个标签,在下面插入一个<script>标签,里面放入js代码,这个js代码就是用来获取上面介绍的性能数据。
- (void)URLProtocol:(NSURLProtocol *)protocol didLoadData:(NSData *)data;
上面会用到很多这个方法,为什么要用这个呢,因为你注入了新的代码,你需要将这个新的网页代码用这个方法加载一下,不然网页会加载不出来的。
最后只需要将MonitorURLProtocol在appDelegate里面注册一下就可以了。
以上是通过NSURLProtocol这个类注入获取数据的代码,将JS代码注入后就需要JS将数据发送给我们,可以通过交互这些方式,接下来我就介绍一种直白的交互,大多数的交互也是这么做的,只不过封装了,考虑的情况更多,我就只是根据实际情况来做了。
OC与JS交互获取数据
交互都会有一个标识,OC传一个标识给JS,JS通过标识判断,发送给你想要的数据。我首先是通过运行时动态加载的方法将加载链接的三个方法给hook,进入同一个我定义的方法,然后在这个方法里面传标识给JS。
将标识和block作为键值对存起来,然后将JS将数据用url的形式发过来,我们取出来,匹配一下对应相应的标识,然后用block回调相应的数据,相应的代码这里就不贴了,最后我会给github上代码的链接。接受url就是用UIWebView的代理方法。
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
{
[WebViewTracker webView:webView withUrl:request.URL];
return YES;
}
我们还可以在didFinishLoad里面手动调用JS代码来获取获取数据,和NSURLProtocol结合起来用,各有各的优缺点,一个是在顶部注入代码,一个是在尾部调用代码,都是会丢失一部分数据,所以最好的办法就是结合起来用。
以上是自己获取这些数据,如果是做成SDK监控APP获取这些数据,就不一样了,需要去hookUIWebView的代理方法,hook静态库的方法和普通的运行时加载是不一样的,这个我可以在以后的文章里面介绍。
WKWebView
WKWebView是iOS8.0以后出来的,目前使用的人还不是很多,但是这个比UIWebView性能方面好很多,从内核到内存优化等等,但是由于还有iOS7以下的用户,所以面使用的人不多,但是这个是趋势。WKWebView获取上面的性能数据是一模一样的,不同的是WKWebView不会走进NSURLProtocol,所以实在didFinishLoad里面手动调用,这里就不详细说了,直接给代码链接
说了那么多,可能还不是很清楚,我把github代码链接发在这里,觉得对你有用的话请给个星星。
https://github.com/LonelyWise/WebViewMonitor
至于那些性能数据有什么用,接下来我会介绍每个字段的意思及如何算才能得到DNS、TCP时间等等。