Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
186 views
in Technique[技术] by (71.8m points)

ios - WKWebKit javascript execution when not attached to a view hierarchy

I want to switch to WKWebView from UIWebView. In my code, the web view instance is created offscreen (without attaching to the view hierarchy) and URL is loaded. When loading is done, the web view is presented to the user in a separate UIWindow (like an interstitial ad). Everything works fine with UIWebView; but after switching to WKWebView, the angular javascript code behaves in an unexpected way.

After doing some research, I've figured out that javascript timers (and HTTP loaders) are suspended when the WKWebView instance is not attached to the view hierarchy: if you start a timer in javascript which runs in detached WKWebView - it won't be fired until the web view is attached.

Can anyone suggest a possible workaround (besides attaching a hidden web view to the key window and then moving it to another window)?

I've created a sample project to demonstrate the issue (or, more likely, a WebKit feature)

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

The test application loads a web page with javascript which schedules a timer and loads HTTP request. You can use switches to show/hide web view (sets 'hidden' property) and attach/detach it from the view hierarchy.

Sample app running on iOS 8.0

If the web view is attached (hidden or visible) and you hit Load, the javascript works fine: you can see success or failure alert dialog. If it's detached - the timer will only fire when it's attached to the view hierarchy (switch "Detached" to "on", hit "Load", wait a couple of seconds and switch back to "off"). You can also check console.log from Safari Web Inspector.

Here's the test web page source:

<!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>

And the 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;
  };
}]);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Having run into the same problem, I never found any solution except to add the WKWebView to the view hierarchy and move it offscreen with AutoLayout. Fortunately, this workaround does work reliably.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...