从WKWebView获取JavaScript错误

时间:2016-06-01 09:31:29

标签: javascript ios wkwebview

我实施了WKScriptMessageHandler协议,我已经定义了userContentController(:didReceiveScriptMessage:)方法。

当Javascript中出现错误时,我得到(在WKScriptMessage对象中)一些不太有用的东西,如:

{
    col = 0;
    file = "";
    line = 0;
    message = "Script error.";
    type = error;
}

另一方面,如果我打开Safari Web Inspector,我可以看到真正的错误(例如):

TypeError: FW.Ui.Modal.sho is not a function. (In 'FW.Ui.Modal.sho', 'FW.Ui.Modal.sho' is undefined)

有没有办法在我的本机代码中恢复该错误?

修改 只是为了澄清,javascript代码是由javascript开发人员编写的(他无法访问本机源代码,因此他无法通过Xcode调试应用程序)。他编写的代码然后被推送到iOS应用程序(从企业应用程序商店下载)。

1 个答案:

答案 0 :(得分:-1)

在评估表达式之前,您可以将表达式包装在try catch块中。然后让JavaScript返回错误消息,如果失败。以下是从Turbolinks-iOS adapter获取的示例,可在GitHub上找到。

extension WKWebView {
   func callJavaScriptFunction(functionExpression: String, withArguments arguments: [AnyObject?] = [], completionHandler: ((AnyObject?) -> ())? = nil) {
        guard let script = scriptForCallingJavaScriptFunction(functionExpression, withArguments: arguments) else {
            NSLog("Error encoding arguments for JavaScript function `%@'", functionExpression)
            return
        }

        evaluateJavaScript(script) { (result, error) in
            if let result = result as? [String: AnyObject] {
                if let error = result["error"] as? String, stack = result["stack"] as? String {
                    NSLog("Error evaluating JavaScript function `%@': %@\n%@", functionExpression, error, stack)
                } else {
                    completionHandler?(result["value"])
                }
            } else if let error = error {
                self.delegate?.webView(self, didFailJavaScriptEvaluationWithError: error)
            }
        }
    }

    private func scriptForCallingJavaScriptFunction(functionExpression: String, withArguments arguments: [AnyObject?]) -> String? {
        guard let encodedArguments = encodeJavaScriptArguments(arguments) else { return nil }

        return
            "(function(result) {\n" +
            "  try {\n" +
            "    result.value = " + functionExpression + "(" + encodedArguments + ")\n" +
            "  } catch (error) {\n" +
            "    result.error = error.toString()\n" +
            "    result.stack = error.stack\n" +
            "  }\n" +
            "  return result\n" +
            "})({})"
    }

    private func encodeJavaScriptArguments(arguments: [AnyObject?]) -> String? {
        let arguments = arguments.map { $0 == nil ? NSNull() : $0! }

        if let data = try? NSJSONSerialization.dataWithJSONObject(arguments, options: []),
            string = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
                return string[string.startIndex.successor() ..< string.endIndex.predecessor()]
        }

        return nil
    }
}