Wednesday, March 14, 2018

WKWebKit javascript execution when not attached to a view hierarchy

Leave a Comment

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 interstitial ad). Everything works fine with UIWebView; but after switching to WKWebView, the angular javascript code behaves in 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 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 fires 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;   }; }]); 

0 Answers

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment