【问题标题】:Get callback when UIWebView finishes loading Ajax当 UIWebView 完成加载 Ajax 时获取回调
【发布时间】:2018-08-30 07:57:58
【问题描述】:

Ajax 在 UIWebView 中完成加载时是否可以收到通知?在 Android 中,我可以这样做:

@SuppressLint("SetJavaScriptEnabled")
private void setUpWebView() {
    webview = view.findViewById(R.id.webView);
    webview.getSettings().setJavaScriptEnabled(true);
    webview.addJavascriptInterface(new JavaScriptInterface(), "HtmlViewer");
    webview.setWebViewClient(new LoginWebView());
    webview.loadUrl("EXAMPLE URL");
}

private class LoginWebView extends WebViewClient {
    @SuppressLint({"JavascriptInterface"})
    @Override
    public void onPageFinished(WebView view, String url) {
        view.loadUrl("javascript:(function(){" +
            "\n" + "    jQuery(document).ajaxComplete(function(event, request, settings){" +
            "\n" + "        var responseCode = JSON.parse(request.responseText).result.responseCode;" +
            "\n" + "        window.HtmlViewer.ajaxResponse(settings.url, responseCode);" +
            "\n" + "    });" +
            "\n" + "})();";);
    }
}

private class JavaScriptInterface {
    @JavascriptInterface
    public void ajaxResponse(String url, String responseCode) {
        // Gets notified when Ajax finished loading
    }
}

现在每次 Ajax 完成加载时,都会调用我的 ajaxResponse 方法。是否也可以在 UIWebView 中实现?

【问题讨论】:

    标签: ios swift uiwebview


    【解决方案1】:

    我终于找到了解决这个问题的方法。那里有很多解决方案,但它们都使用 jQuery,这似乎在 WKWebView 中不起作用。这是我在原始JavaScript 中的解决方案。

    这里是 ViewController 实现,它让您在 WKWebView 中完成的每个 AJAX 请求都收到通知:

    import UIKit
    import WebKit
    
    class WebViewController: UIViewController {
    
        private var wkWebView: WKWebView!
        private let handler = "handler"
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let config = WKWebViewConfiguration()
            let userScript = WKUserScript(source: getScript(), injectionTime: .atDocumentStart, forMainFrameOnly: false)
            config.userContentController.addUserScript(userScript)
            config.userContentController.add(self, name: handler)
    
            wkWebView = WKWebView(frame:  view.bounds, configuration: config)
            view.addSubview(wkWebView)
    
            if let url = URL(string: "YOUR AJAX WEBSITE") {
                wkWebView.load(URLRequest(url: url))
            } else {
                print("Wrong URL!")
            }
        }
    
        private func getScript() -> String {
            if let filepath = Bundle.main.path(forResource: "script", ofType: "js") {
                do {
                    return try String(contentsOfFile: filepath)
                } catch {
                    print(error)
                }
            } else {
                print("script.js not found!")
            }
            return ""
        }
    }
    
    extension WebViewController: WKScriptMessageHandler {
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            if let dict = message.body as? Dictionary<String, AnyObject>, let status = dict["status"] as? Int, let responseUrl = dict["responseURL"] as? String {
                print(status)
                print(responseUrl)
            }
        }
    }
    

    相当标准的实现。有一个以编程方式创建的WKWebView。存在从script.js 文件加载的注入脚本。

    最重要的部分是script.js文件:

    var open = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function() {
        this.addEventListener("load", function() {
            var message = {"status" : this.status, "responseURL" : this.responseURL}
            webkit.messageHandlers.handler.postMessage(message);
        });
        open.apply(this, arguments);
    };
    

    userContentController 委托方法会在每次加载 AJAX 请求时被调用。我要经过statusresponseURL,因为这是我需要的,但您也可以获得有关请求的更多信息。以下是所有可用属性和方法的列表: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

    我的解决方案受到@John Culviner 撰写的这个答案的启发: https://stackoverflow.com/a/27363569/3448282

    【讨论】:

      【解决方案2】:

      您可以使用evaluateJavaScript:completionHandler:

      webView.evaluateJavaScript("yourJSfuncsToRunAJAX") { response, error in
          //if error didn't occure do sth after js function finished
      }
      

      【讨论】:

      • 感谢您的回答。问题是我需要使用UIWebView,它不允许使用带有回调的evaluateJavaScript 函数。我想我可以尝试使用WKWebView(它的cookie管理系统很差,这就是我需要使用UIWebView的原因)。问题是我不知道 JS 脚本在 iOS 版本中应该是什么样子。在 Android 上,我打电话给window.HtmlViewer.ajaxResponse(settings.url, responseCode);,让我将回调信息传递给我的函数。如何在 iOS 上实现这一点?
      • @user3448282 Apple 推荐使用 WKWebView,所以试一试 ;) JS 在每个浏览器上都非常相似,所以如果它适用于基于 chromium 的浏览器,它也应该适用于 safari 基础。
      【解决方案3】:

      不幸的是,iOS 8 已弃用 UIWebView,因此您应该切换到 WKWebView。 来自apple:“在 iOS 8 及更高版本中运行的应用程序中,使用 WKWebView 类而不是使用 UIWebView。”

      若要在 ajax 完成时收到通知,您可以使用来自here 的已接受响应。我使用相同的原理在 javascript 和 swift 之间进行桥接。

      希望对你有帮助。

      【讨论】:

        猜你喜欢
        • 2013-06-21
        • 1970-01-01
        • 2016-12-26
        • 2010-12-12
        • 2010-10-30
        • 1970-01-01
        • 2010-09-14
        • 1970-01-01
        • 2012-06-15
        相关资源
        最近更新 更多