WKWebView 에서 Ajax 통신을 감지하는 방법. feat. Javascript

UIWebView 시절에도 그랬지만, WKWebView 에서도 Ajax 통신을 감지할 수 없습니다.

WKWebView 에서 추가된

@available(iOS 8.0, *)
optional public func webView(webView: WKWebView, decidePolicyForNavigationResponse navigationResponse: WKNavigationResponse, decisionHandler: (WKNavigationResponsePolicy) -> Void)

에서는 <iframe /> 통신(완료)은 감지 가능하지만 역시 Ajax 통신을 감지할 수 없습니다.

웹은 Swift의 전문 분야가 아닙니다. 웹의 전문 분야인 Javascript에게 도움을 요청합시다.

@available(iOS 8.0, *)
optional public func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!)

didFinishNavigation에서 일반 통신이 종료되는 시점을 감지하여 Ajax 통신을 감지하는 자바스크립트 명령을 삽입합니다.

self.webKit.evaluateJavaScript("_send = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function() { alert('ajax:'); var callback = this.onreadystatechange; this.onreadystatechange = function() { if (this.readyState === 4 &amp;amp;&amp;amp; this.status === 200) { alert('ajaxDone'); } callback.apply(this, arguments); }; _send.apply(this, arguments); }; 'script inserted';", completionHandler: { (object, error) in
    print(object)
})

위 명령은 Ajax 를 관장하는 XMLHttpRequest의 send() 메소드를 오버라이딩하여 Ajax 통신 상태를 앱에 전달하여 주기 위한 자바스크립트입니다.

_send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function() {
    alert('ajax');
    var callback = this.onreadystatechange;
    this.onreadystatechange = function() {
        if (this.readyState === 4 && this.status === 200) {
            alert('ajaxDone');
        }

        callback.apply(this, arguments);
    };

    _send.apply(this, arguments);
};

Javascript와 WKWebView간의 효과적인 통신 방법은 WKUserContentController를 이용하는 방법이 있습니다. 하지만 이것은 다음에 기회가 되면 다시 설명 드리기로 하고 여기에서는 간단하게 Javascript의 alert()과 WKUIDelegate의

@available(iOS 8.0, *)
optional public func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void)

를 이용하는 방법을 사용하겠습니다. 위 protocol은 WKWebView에서 alert() 자바스크립트가 작동되면 호출됩니다.

위 자바스크립트를 이용하여 Ajax(XMLHttpRequest)가 작동하면 alert(‘ajax’); 를 호출 하도록 했고, 통신이 정상적으로 완료 되면 alert(‘ajaxDone’); 를 호출 하도록 하였습니다.

Swift에서는 아래와 같이 각 메세지를 받아서 분기 처리를 할 수 있습니다.

func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
    if message == "ajax" {
        // Ajax 통신 시 웹뷰의 URL을 변경 시키는 경우가 있으므로 이를 확인.
        // Ajax 통신이 이루어지는 URL과는 다름.
        print(webView.URL?.absoluteString)
        completionHandler()

        return
    }
    else if message == "ajaxDone" {
        // Ajax 통신으로 달라 진 HTML (DOM) 을 확인.
        self.webKit.evaluateJavaScript("document.documentElement.outerHTML", completionHandler: { (object, error) in
            print(object)
        })
        completionHandler()

        return
    }

    // UIAlertController 사용 message 내용 띄우기.

    completionHandler()
}

이제 WKWebView는 Ajax를 포함한 모든 통신을 감지할 수 있게 되었습니다.

단순히 웹뷰에 웹을 보여 주는 한계에서 벗어 나 앱의 제어권을 더 넒힌 하이브리드앱의 제작이 가능해졌습니다.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s