WKWebView网络请求拦截
业内已有的 WKWebView 请求拦截方案,主要分为如下两种
NSURLProtocol 默认会拦截所有经过 URL Loading System 的请求,因此只要 WKWebView 发出的请求经过 URL Loading System 就可以被拦截。经过我们的尝试,发现 WKWebView 独立于应用进程运行,发出去的请求默认是不会经过 URL Loading System,需要我们额外进行 hook 才能支持,具体的方式可以参考 NSURLProtocol对WKWebView的处理 。
虽然NSURLProtocol可以拦截监听每一个 URL Loading System 中发出 request 请求,记住是URL Loading System中那些类发出的请求,也支持AFNetwoking,UIWebView发出的request,NSURLProtocol都可以拦截和监听。
因为WKWebView 在独立进程里执行网络请求。一旦注册 http(s) scheme 后,网络请求将从 Network Process 发送到 App Process,这样 NSURLProtocol 才能拦截网络请求。
但是在 WebKit2 的设计里使用 MessageQueue 进行进程之间的通信,Network Process 会将请求 encode 成一个 Message,然后通过 IPC(进程间通信) 发送给 App Process。出于性能的原因,encode 的时候 将HTTPBody 和 HTTPBodyStream 这两个字段丢弃掉( 坑 )
因此,如果通过 registerSchemeForCustomProtocol 注册了 http(s) scheme, 那么由 WKWebView 发起的所有 http(s)请求都会通过 IPC 传给主进程 NSURLProtocol 处理,导致 post 请求 body 被清空;
说明1 :名目张胆使用私有API,是过不了AppStore审核的,具体使用什么办法,想来你也懂(hun xiao)。
说明2 :一旦打开ATS开关: Allow Arbitrary Loads 选项设置为NO ,通过 registerSchemeForCustomProtocol 注册了 http(s) scheme,WKWebView 发起的所有 http(s) 网络请求将被阻塞(即便将 Allow Arbitrary Loads in Web Content 选项设置为YES );
说明3 :iOS11之后可以通过 WKURLSchemeHandler 去完成对 WKWebView 的请求拦截,不需要再调用私有API解决上述问题了。
WKURLSchemeHandler是iOS11就推出的,用于处理自定义请求的方案,不过并不能处理Http、Https等常规scheme。
WKURLSchemeHandler 负责自定义请求的数据管理,如果需要支持 scheme 为 http 或 https请求的数据管理则需要 hook WKWebView 的 handlesURLScheme: 方法,然后返回NO即可。
调研的结论是: WKURLSchemeHandler 在隔离性、稳定性、一致性上表现优于 NSURLProtocol ,但是想在生产环境投入使用必须要解决 Body 丢失的问题。
总结:
NSURLProtocol
缺点:针对WKWebView流量需要额外使用私有方法,虽然可以通过混淆方式屏蔽关键词但是无法保证日后版本升级仍然适用
WKURLSchemeHandler
缺点:需要针对WKWebView实例设置,WKWebView实例零散的场景不适用
引用文章: