WKWebKit未附加到视图层次结构时执行javascript

时间:2015-07-01 19:20:22

标签: javascript ios angularjs webkit wkwebview

我想从WKWebView切换到UIWebView。在我的代码中,Web视图实例是在屏幕外创建的(不附加到视图层次结构)并且加载了URL。加载完成后,Web视图将在单独的UIWindow(如插页式广告)中呈现给用户。 UIWebView,一切正常;但在切换到WKWebView后,角度javascript代码会以意想不到的方式运行。

在做了一些研究之后,我发现当WKWebView实例未附加到视图层次结构时,javascript计时器(和HTTP加载器)被挂起:如果你在javascript中启动一个以分离运行的计时器WKWebView - 在附加Web视图之前不会触发它。

任何人都可以建议一个可能的解决方法(除了将隐藏的Web视图附加到关键窗口然后将其移动到另一个窗口)?

我已经创建了一个示例项目来演示问题(或者,更有可能是WebKit功能)

https://dl.dropboxusercontent.com/u/148568148/WebKitViewTest.zip

测试应用程序加载一个带有javascript的网页,该网页调度计时器并加载HTTP请求。您可以使用开关来显示/隐藏Web视图(设置“隐藏”属性)并将其从视图层次结构中附加/分离。

Sample app running on iOS 8.0

如果网页视图已附加(隐藏或可见)并且您点击Load,则javascript工作正常:您可以看到successfailure提醒对话框。如果它已分离 - 计时器只会在它附加到视图层次结构时触发(将“Detached”切换为“on”,点击“Load”,等待几秒钟并切换回“off”)。您还可以从Safari Web Inspector中查看console.log

以下是测试网页来源:

<!doctype html>
<html ng-app="project">
  <head>
    <script
      src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular.js"></script>
    <script src="project.js"></script>
  </head>
  <body>
    <div id="simple" ng-controller="MyController" data-ng-init="callNotify(message);">
    </div>
  </body>
</html>

和javascript:

angular.
  module('project', []).
  controller('MyController', ['$scope','notify', function ($scope, notify) {
  $scope.callNotify = function(msg) {
    notify(msg);
  };
}]).
  factory('notify', ['$window', '$http', '$q', '$timeout', function(win, $http, $q, $timeout) {
  return function(msg) {
    deferred = $q.defer();

    $timeout(function() {
      $http.get('http://jsonplaceholder.typicode.com/posts').
      success(function(data, status, headers, config) {
        alert("success");
        console.log("success")
      }).
        error(function(data, status, headers, config) {
        alert("error");
        console.log("error")
      });
    });
    return deferred.promise;
  };
}]);

2 个答案:

答案 0 :(得分:2)

遇到同样的问题,除了将WKWebView添加到视图层次结构并使用AutoLayout将其移出屏幕外,我从未找到任何解决方案。幸运的是,这种解决方法确实可靠。

答案 1 :(得分:0)

我遇到了完全相同的问题,并用UIStackView解决了。我创建了StackNavigationController,它是UINavigationController的简约替代品,它基本上在堆栈中添加了新视图,同时隐藏了除最后一个视图以外的所有视图。因此,所有视图仍处于层次结构中,正在执行和加载,但是只有最后一个可见。没有动画,缺少很多API,可以随时在其上进行构建。

public class StackNavigationController: UIViewController {

    private(set) var viewControllers: [UIViewController] = []
    private var stackView: UIStackView { return view as! UIStackView }

    override public func loadView() {
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.distribution = .fillEqually
        view = stackView
    }

    func pushViewController(_ viewController: UIViewController, animated: Bool) {
        let previousView = stackView.arrangedSubviews.last
        viewControllers.append(viewController)
        stackView.addArrangedSubview(viewController.view)
        previousView?.isHidden = true
    }

    func popToRootViewController(animated: Bool) {
        while stackView.arrangedSubviews.count > 1 {
            stackView.arrangedSubviews.last?.removeFromSuperview()
            viewControllers.removeLast()
        }
        stackView.arrangedSubviews.first?.isHidden = false
    }

}

我的故事:

  1. 我有一个以UINavigationController作为根视图的WKWebView(1)
  2. WKWebView(1)的超链接带有参数集target: _blank
  3. 点击链接后,我抓到WKUIDelegate的{​​{1}}并将另一个webView(_:didRequestNewWebView:)推到WKWebView(2)
  4. UINavigationController对服务器执行请求
  5. 服务器以JavaScript消息响应WKWebView(2)
  6. 我从未收到消息,因为WKWebView(1)已暂停
相关问题