1. 背景说明
在App WebView加载网络请求场景下,Android/iOS系统可基于系统API进行网络请求拦截,并实现自定义逻辑注入,如使用HTTPDNS进行基于IP的直连请求。但iOS系统在Webview场景下拦截网络请求后,需要自行接管基于IP的网络请求的发送、数据接收、页面重定向、页面解码、Cookie、缓存等逻辑;Android除了上述iOS遇到的问题外,不同版本的ROM的网络请求拦截能力还存在差异,比如低版本Android ROM基于系统API拦截的网络请求会丢失请求方法、Body信息等。综合来看,Webview场景下HTTPDNS的使用(IP直连进行网络请求)门槛比较高,移动操作系统针对这个场景的支持粒度很粗,且存在一些缺陷,需要开发者具备较强的网络/OS Framework的代码级掌控能力来规避和优化上述问题。
2. 方案概述
2.1 Android
- 通过以下API对WebView进行配置;
-
[backcolor=transparent]
void[backcolor=transparent]
setWebViewClient [backcolor=transparent]
([backcolor=transparent]
WebViewClient[backcolor=transparent]
client[backcolor=transparent]
);
- 通过重写WebViewClient中以下方法拦截WebView的网络请求,获取请求URL.host进行HTTPDNS域名解析,解析完成后处理方式和普通网络请求一致,替换URL.host字段,设置HTTP Header Host域,最后返回新请求对应的WebResourceResponse。
- [backcolor=transparent]/**
- [backcolor=transparent] * 拦截WebView网络请求(Android API < 21)
- [backcolor=transparent] * 只能拦截网络请求的URL,请求方法、请求内容等无法拦截
- [backcolor=transparent] */
- [backcolor=transparent]public[backcolor=transparent] [backcolor=transparent]WebResourceResponse[backcolor=transparent] shouldInterceptRequest[backcolor=transparent]([backcolor=transparent]WebView[backcolor=transparent] view[backcolor=transparent],
- [backcolor=transparent] [backcolor=transparent]String[backcolor=transparent] url[backcolor=transparent]);
- [backcolor=transparent]/**
- [backcolor=transparent] * 拦截WebView网络请求(Android API >= 21)
- [backcolor=transparent] * 通过解析WebResourceRequest对象获取网络请求相关信息
- [backcolor=transparent] */
- [backcolor=transparent]public[backcolor=transparent] [backcolor=transparent]WebResourceResponse[backcolor=transparent] shouldInterceptRequest[backcolor=transparent]([backcolor=transparent]WebView[backcolor=transparent] view[backcolor=transparent],
- [backcolor=transparent] [backcolor=transparent]WebResourceRequest[backcolor=transparent] request[backcolor=transparent]);
- 使用方式参考Android WebClient API。
2.2 iOS
- 基于NSURLProtocol可拦截iOS系统上基于上层网络库NSURLConnection/NSURLSession发出的网络请求,WebView发出的请求同样包含在内;
- 通过以下接口注册自定义NSURLProtocol,用于拦截WebView上层网络请求,并创建新的网络请求接管数据发送、接收、重定向等处理逻辑,将结果反馈给原始请求。
-
[backcolor=transparent]
[[backcolor=transparent]
NSURLProtocol[backcolor=transparent]
registerClass[backcolor=transparent]
:[[backcolor=transparent]
CustomProtocol[backcolor=transparent]
[backcolor=transparent]
class[backcolor=transparent]
]];
- 自定义NSURLProtocol处理过程概述:在canInitWithRequest中过滤要需要做HTTPDNS域名解析的请求;
- 请求拦截后,做HTTPDNS域名解析;
- 解析完成后,同普通请求一样,替换URL.host字段,替换HTTP Header Host域,并接管该请求的数据发送、接收、重定向等处理;
- 通过NSURLProtocolClient的接口,将请求处理结果反馈到WebView原始请求。
NSURLProtocol使用参考Apple NSURLProtocol API,苹果官方示例代码参考Apple Sample Code - CustomHTTPProtocol。