WkWebView blocks requests when not visible - ios

I am working on hybrid app which mostly runs in the WkWebView, but uses camera and so on. We also have completely native screen which also needs communication with backend. The customer’s wish is to run those requests via WKWebView (they don’t want to perform them natively). So we have NavigationController -> WkWebViewController -> FunctionalityViewController.
FunctionalityViewController has reference to the WkWebViewController via delegate to send requests through JavaScript to backend. The iOS communication works fluently (FunctionalityViewController -> WkWebViewController) and also calls to via debugging with Safari all calls reach WkWebView.
The WKWebView then issues requests to backend and they are executed sometimes, and sometimes not… but when the FunctionalityViewController is dismissed all the unexectured requests are issued - like the WkWebView queues them…
Does anyone know how to fix that? (I have two undesired solutions like making FunctionalityViewController childViewController and so on - but I would like to avoid that if possible). Any suggestions are welcome.

I have finally found out what's wrong. The WKWebView must be in the view hierarchy to work properly. There are certain bug reports on GitHub describing the same problem.
Source(1): Keeping a WKWebView and it's UIViewController in the background running and accessible from multiple ViewControllers
Source(2): WKWebKit javascript execution when not attached to a view hierarchy
Source(3): http://ileyf.cn.openradar.appspot.com/43038986
For downvoters: is that all you can do right?

Related

Migrating iOS Hybrid App from UIWebView to WKWebview

I want to migrate my iOS hybrid app from UIWebView to WKWebView as the former has been deprecated. There are a number of similar questions to this on Stack Overflow that have already been answered but these questions focused on the rather simpler topic of just displaying a web view with out addressing the loading of local files nor the two way interaction required between the Objective C wrapper and the Javascript code for a hybrid app to deliver any functionality.
So far I have established that I need to do the following
Replace the import statement for UIKit with WebKit.
Before creating the wkwebview it is necessary to create a configuration object and set its key allowFileAccessFromFileURLs to TRUE.
After creating the wkwebview, setting its navigationDelegate and its UIDelegate to self.
When loading the url of the html/ccc/js file location, specifying allowingReadAccessToURL to delete the last path component (which I think is the file://)
Set the wkwebview as a sub view of the main view (I think this was not required in UIWebView)
Replacing the existing communications channel from the javascrtipt code to the Objective C code which made use of "shouldStartLoadWithRequest" by creating a script message handler in the wkwebview configuration object mentioned in 2 above and then using this message handler to invoke the processing that used to be done by "shouldStartLoadWithRequest".
Replacing all existing communications channels to the javascript code from the Objective C code which made use of "stringByEvaluatingJavaScriptFromString" with "evaluateJavaScript" which now requires a completion handler which can be set to nil as I am not using any callback values.
Adding a solution to allow the keyboard to be displayed without user selecting an input text field. The best I can see so far is Programmatically focus on a form in a webview (WKWebView). I am somewhat concerned that it appears to need changing every IOS release.
Addressing CORS issues. I understand that WKWebView is much stricter in its implementation of loading remote files from different URLs than UIWebView was, but I am not clear whether there is also a need to whitelist the local files to be loaded as well.
If anyone knows of a check list of things that need to be changed with tips/examples with exact details, or could provide such as an answer that would be superb.
In addition I would like to continue to support pre IOS 11 users by retaining UIWebView for these users as I believe WKWebView had issues in those earlier versions. Does anyone know if this going to cause any additional problems to resolve, and if so how?
Yes
allowFileAccessFromFileURLs is undocumented, so it may or may not work in iOS 13.
Yes
Yes
Yes, and it is required with UIWebViews as well. What might be different is that adding a WKWebView to a storyboard or nib was impossible or buggy, at least until very recent versions of Xcode, which may be why you have that impression.
No, the -webview:shouldStartLoadWithRequest:navigationType: method is a UIWebViewDelegate method. You want the corresponding WKNavigationDelegate method, which is -webView:decidePolicyForNavigationAction:decisionHandler:.
Yes
I can't answer to that, as I've never needed to do it.
See #8
WKWebView has been around since iOS 8, so unless you're targeting iOS 7, Apple still may reject your app once they start rejecting for use of UIWebView. I don't think there's any way to know if that is the case other than submitting the app to find out.
If your javascript makes use of custom schemes that rely on the webview delegate to handle them correctly (i.e., myscheme://some/callback), it can be flaky with Webkit. This is where the script message handler that you alluded to comes in. But you have to update your javascript to use window.webkit.messageHandlers.someCallback.postMessage(someParams) instead of using a custom URL scheme.

Can a WKWebView call a function in the main app and get a value back?

I am currently writing a web page that is designed to be run inside a WKWebView on iOS, or a WebView on Android. On Android, it is possible for the WebView to call a function that executes native app code and returns a value back to the WebView. Is it possible to do the same on iOS? Can I call a native iOS function and get a value returned back from it, in one way or another?
It certainly is possible, but needs a lot of preparation work.
I made this a few years ago https://github.com/ddaddy/DJJavaInsertion when I needed to be able to control how an app works by changing JavaScript on a webpage. It uses UIWebView but you should be able to modify it to use WKWebView
The way it works is it loads your web page and kicks off an initial js function. As your js needs to call an Obj-C method it makes an iframe call to a specially formulated url which the webview delegate catches and performs the function.
I used it to present native alerts, request data input and even perform quite complex web requests.
I doubt it’ll be a drop in for you, but may show you how to do it.

WKWebView analog of service worker

I'm trying to implement part of app with PWA approach, that works fine on Android, but not for iOS. We need to have
offline content availability
option to update content dynamically (like special offers or so). With service worker we show prompt to update web content.
As were mentioned here service workers are not supported within WKWebView (or UIWebView). So is there analog or alternative solution like smart cache control?
Seems like it is possible to store some web content from app and be able to update it if something changes. May there is already a framework/library/approach for that purpose?
EDIT
Service Workers unavailable in WKWebView in iOS 11.3 - this question explains the status of ServiceWorkers in WKWebView, but no alternative is given. I would like to discuss any alternative solutions.
One thing I discovered is https://github.com/xtools-at/iOS-PWA-Wrapper. It looks like working based on AppCache, but https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache#Browser_compatibility says it is deprecated and adviced to use SW instead (which is not an option for PWA).
So before WKWebView get service-workers to work, you can use AppCache (not yet fully deprecated).
You can use this and take a look at source page at https://leasingrechnen.at
What they do? In case if there is no service worker in browser, they load iframe that points to a page with manifest.appcache file implemented, so the page is cached.

Click events inside UIWebView with Swift

I've built a simple app/service that I'm displaying inside a UIWebView. Traditional links work just fine, but click events don't work at all. I'm aware this is a "thing" and I've looked at lots of code samples, and looked into touchstart etc., but nothing seems to make a dent in the problem.
Is there a definitive guide to making JS click events work inside web views, even if it involves passing messages to iOS?
Underlying app is Rails/Coffeescript. Current event code looks like this:
$('#frame ul li').on "click", ->
# Do stuff
Don't you use hosting jQuery on the Google server? The resource is likely to blocked by App Transport Security (ATS).
If so, the easy way is to set the domain to NSExceptionDomains.

Sharing HTML5 localstorage among multiple UIWebViews

I have a ViewController which has multiple UIWebViews. I am using localstorage.setItem to store some variables. But the problem is that these variables are accessible only within the UIWebViews in which has been set. If i am trying to get( localstorage.getitem) the variable of other UIWebViews it's giving null value .
WebView1=====>>>>localStorage.setItem("var1","val");
WebView2=====>>>>alert(localstorage.getItem("var1")); ===>>is null
Sorry, but that's just how the framework is designed: every UIWebView is it's own instance, isolated from other instances in the same app (just like there is no built-in pop-up or tab functionality).
If there is absolute no other way around it, you could make the web views Cordova WebView's and programatically arrange for some way to transfer data between them via the native layer (there's also alternatives, like WebViewJavascriptBridge that accomplishes the same thing).
Maybe you could even get by just by injecting the data needed using stringByEvaluatingJavaScriptFromString into a known data structure beforehand. But having the Javascript in a UIWebView call the native side is a well known difficult-to-do thing that can only be solved by using bridging solutions like i mentioned in the second paragraph.

Resources