やりたいこと
ある案件でアプリ内部組み込みブラウザのトラフィックを監視する必要が生まれた。
だから、当初はURLProtocol
を使ってハンドリングしようとも考えたが、
URLProtocol
はUIWebView
でしか使えないので色々悩んだ結果
PrivateAPIに手を出してみたと言うお話。
実装
iOS11以上であれば全く難しくはない
iOS11未満であってもできなくはないがPrivateClassをNSClassFromString(:)
で持ってきて...
って話になるので割愛
WKURLSchemeHandlerなるものがあるのでそれで実装する。
let config = WKWebViewConfiguration()
config.setURLSchemeHandler(WebViewProtocol(), forURLScheme: "dummy")//_urlSchemeHandlersはlazyなのでdummyで初期化してあげる必要がある。
let _handlers = config.value(forKey: "_urlSchemeHandlers") as! NSMutableDictionary
_handlers.setObject(WebViewProtocol(), forKey: "https" as NSString)
_handlers.setObject(WebViewProtocol(), forKey: "http" as NSString)
webview = WKWebView(frame: self.view.frame, configuration: config)
ポイントは
WKWebViewConfiguration::setURLSchemeHandler
で"http","https"を登録すると落ちる(落とされる)ので
value(forKey:)
で"_urlSchemeHandlers"
をそのままいじってしまうこと
(NSMutableDictionary
はクラスなので参照渡し)
んであとはProtocolの中身を書いてしまえばよい
例
import WebKit
import Alamofire
class WebViewProtocol:NSObject, WKURLSchemeHandler {
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
print(urlSchemeTask.request)
Alamofire.request(urlSchemeTask.request).response(queue: .main){res in
if let error = res.error{
urlSchemeTask.didFailWithError(error)
}
urlSchemeTask.didReceive(res.response!)
urlSchemeTask.didReceive(res.data!)
urlSchemeTask.didFinish()
}
}
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
}
}
まとめ
多分今後PrivateAPIについてもさもさ書くと思います。