Swift

WebKitでPrivateAPI使ってProxyを実装する


やりたいこと

ある案件でアプリ内部組み込みブラウザのトラフィックを監視する必要が生まれた。

だから、当初はURLProtocolを使ってハンドリングしようとも考えたが、

URLProtocolUIWebViewでしか使えないので色々悩んだ結果

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についてもさもさ書くと思います。