UIWebView throwing Frame load interrupted error - ios

I am working on application in which I am downloading file and saving it in documents directory
so when user uses the application next time he can directly open the file which are already downloaded
I am showing that file on next screen in UIWebView using follwing code :
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:self.url]; // where url is url of file in documents directory
[webView loadRequest:urlRequest];
This is working perfectly for file having extension pdf but there are some files with extension asp and
when I am trying to open those file I get this error
Error
Domain=WebKitErrorDomain Code=102 "Frame load interrupted"
UserInfo=0x9b58fa0
{NSErrorFailingURLKey=file:///Users/poonam/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/7EE726E5-5315-4BEE-9629-F85FBCD46BC3/Documents/V2_076eb8847184be9e441f1bed7cc1a705.asp,
NSErrorFailingURLStringKey=file:///Users/poonam/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/7EE726E5-5315-4BEE-9629-F85FBCD46BC3/Documents/V2_076eb8847184be9e441f1bed7cc1a705.asp,
NSLocalizedDescription=Frame load interrupted}
To solve this I tried
- (BOOL)webView:(UIWebView *)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if ([url.scheme isEqualToString:#"file"]) {
NSLog(#"Open start page");
[[UIApplication sharedApplication] openURL:url];
return NO;
}
return YES;
}
But However I am not able to solve my problem. Any suggestions please

Finally after spending hours on this , Here i found the solution for this common Webview "frame load interrupted" issue:
Download the file in bytes form
Store it in the Local Storage
Load the file in Web view with the local path and it works
Code for the above steps:
https://stackoverflow.com/a/59194408/12483992

Late answer but this could be useful for someone.
I got this same error and it was because I didn't realize I was returnint false in
func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool
in my UIWebView Delegate. Changed to
return true
fixed the issue and
func webViewDidFinishLoad(_ webView: UIWebView)
was called after that.

Related

Did finish navigation load multiple times

I am using WKWebView to load a URL but my didFinishNavigation class multiple times.
I have to evaluate javascript and I had to wait for page to load complete and then have to inject JS in it but it fires multiple times.
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
[_webView evaluateJavaScript:js completionHandler:nil];
}
js is the string in which I have written my JS code.
If you are using UIWebView, after the web view has finished loading, it is calling the delegate method:
func webViewDidFinishLoad(_ webView: UIWebView)
Try it.

WKWebView Hangs on local webpage load with certain web configuration.

I have a WKWebView that loads a local set of webpages using WKWebViewConfiguration to set the configuration for #"allowFileAccessFromFileURLs" to be true.
The request is set up with something like this:
NSURL *url = [[NSBundle mainBundle] URLForResource:#"testPage" withExtension:#"html" subdirectory:#"html/pages"];
NSURLRequest *req = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0f];
Then the request is sent using the following WKWebview method:
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
my problem is where the device has a current connection but there is no network traffic. The webview as an element on the screen will be added to the screen and the request will be made but the webview will show a white screen for about 50 seconds before displaying the local content.
Everything in the webview loads regardless of the network status as its loaded locally when there is no link conditioner set.
For example if the device is connected to wireless but the network link conditioner is set to 100% loss. The webview is created and the request is sent to load the local content triggering the hang of the load.
I had a thought that it might be the WKWebView trying to do some kind of validation in the background that requires a network transaction but I did some network profiling with instruments and also some timeline recording in the safari webview and I couldnt see anything that would cause it to hang.
The only reason I can think of it loading local content after 50 seconds or so is that its hit some sort of WKWebView timeout to load a network connection.
Any help would be greatly appreciated, thanks.
Okay so for anyone else who stumbles across this I have found what I was doing wrong.
The issue was not actually the WKWebview or the web content itself it was how I was handling the completion of the webview loading.
in the method:
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
I was listening for a completion of events by evaluating some JS like so:
-(void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
[webView evaluateJavaScript:#"document.body.innerHTML" completionHandler:^(id result, NSError *error)
{
if (result != nil) {
[self doCertainNetworkEvent]; //here another method is called with a networking function inside of it.
}
if(error)
{
NSLog(#"evaluateJavaScript error : %#", error.localizedDescription);
}
}];
}
The completion block of course couldnt finish until the network function within the didFinishNavigation method call was finished (which it couldnt because there was no traffic.)

how can I clear the contents of a UIWebView/WKWebView?

I have a webview that can be cycled through different URLs. When I switch from one to the other I want the old web page to disappear before loading the next one. How can I do this without re allocating the webview?
If I try to [self.webView loadHTMLString:#"" baseURL:nil]; and load my URL in the same function the previous web page still remains:
[self.webView loadHTMLString:#"" baseURL:nil];
[self.webView loadRequest:[NSURLRequest requestWithURL:self.pageURL]];
EDIT: this apparently isn't clear enough for you. the below code doesn't clear the webview, it displays the previous page until the new one is loaded:
- (void) startLoadOfNextURL:(NSURL*)url
{
// clear:
[self.webView loadHTMLString:#"" baseURL:nil]; //DOESNT WORK
// Load real next URL
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
You can write the code below while your controller dismisses.
webView.load(URLRequest(url: URL(string:"about:blank")!))
You can make it load a blank page
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"about:blank"]]];
Use JavaScript instead.
webView.evaluateJavaScript("document.body.remove()")
The following code clears the screen and then navigates
Swift
webView.evaluateJavaScript("document.documentElement.remove()") { (_, _) in
self.webView.load(urlRequest)
}
To clear old contents of webview
When you call - loadHTMLString:baseURL: it doesn't block until the load is complete. Once it records your request, it returns and loads in the background.
As a result, you would need to wait for the first load to finish before kicking off a new load request.
With UIWebView you would use UIWebViewDelegate's
- webViewDidFinishLoad:.
With WKWebView you would use WKNavigationDelegate's
- webView:didFinishNavigation:
Another approach if you really wanted to clear the contents without a delegate method would be to use JavaScript (eg https://stackoverflow.com/a/4241420/3352624). Then for UIWebView you could invoke - stringByEvaluatingJavaScriptFromString:. That method will block execution until the JavaScript executes and returns.
For WKWebView, you would need to do something like https://stackoverflow.com/a/30894786/3352624 since its - evaluateJavaScript:completionHandler: doesn't block.
To make old contents "disappear"
If you really just want to make "the old web page to disappear", you could cover the content area of the webview with a blank UIView temporarily. You could hide the contents when you initiate the load and then show the contents using the delegate methods above after the load completes.
Swift
webView.load(URLRequest(url: URL(string: "about:blank")!))
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
//Load request or write code here
})

Disable WKActionSheet on WKWebView

I'm migrating an iOS app form UIWebView to WKWebView. So far so good... In the previous app I disabled long press and implemented a custom long press (to do custom handling of links), however I can't get this working in the WKWebView
I've tried the following:
- (void)webView:(WKWebView *)wkWebView didFinishNavigation:(WKNavigation *)navigation {
[wkWebView evaluateJavaScript:#"document.body.style.webkitTouchCallout='none';" completionHandler:nil];
}
I've checked and that line gets executed, the response of the call is #"None"
But it responds with:
Warning: Attempt to present on whose view is not in the window hierarchy!
Any ideas?
SOLUTION:
Inject javascript into wkwebview now works!
[self.wkWebView evaluateJavaScript:#"document.body.style.webkitTouchCallout='none';" completionHandler:nil];
This is the solution in Swift 3.0:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("document.body.style.webkitTouchCallout='none';")
}
myWkWebView.allowsLinkPreview = false
I haven't verified it, but it looks like you can also use CSS to disable this functionality:
-webkit-touch-callout: none;
Source: https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-touch-callout

How To Clear A UIWebView

I am very new to the whole programming business, and was wondering if there is any way to clear the contents of a UIWebView in iphone programming, so that the loading symbol for the next view is not showing up in front of the last view.
Many Thanks,
Thomas
Try setting the URL to about:blank and reload the page.
Just load an empty html string into it
[self.webView loadHTMLString:#"" baseURL:nil];
Answer extension for documentation purposes to maybe help someone else:
I had the same desire (clear content before loading next url) but had a UIWebView delegate set to receive webviewDidFinishLoad:(UIWebView)webview message and update another part of UI in response.
Problem: the call to clear the content to also called delegate method, so getting false-hits (that is, getting call when clear is done, too, but delegate is coded to expect call only when real content is loaded).
Solution: use a known URL for clear, and have webviewDidFinishLoad: ignore calls made when that URL is finished:
- (void) startLoadOfNextURL:(NSURL*)url
{
// clear:
[self.webView loadHTMLString:#"" baseURL:nil];
// Load real next URL
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSLog(#"WebView finished loading: %#", webView);
if ([self.webView.request.URL.absoluteString isEqualToString:#"about:blank"]) {
NSLog(#" This is Blank. Ignoring as false event.");
}
else {
NSLog(#" This is a real url");
[self updateUIInSomeWay];
}
}
Note: using this:
[self.webView loadHTMLString:#"about:blank" baseURL:nil];
actually causes the words "about:blank" to appear as text in the webview's content pane!
Final complication: In practice, with my two [webview load...] calls so close together, I was finding that instead of a "loaded" event for the clear, the webview was actually canceling it in favor of the second request and calling webView: didFailLoadWithError: for the first load request. Thus, I had to put similar code in that event:
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
NSLog(#"WebView error on: %#", webView);
NSLog(#"Error is: %#", error);
NSURL* failingURL = [error.userInfo objectForKey:#"NSErrorFailingURLKey"];
if ([failingURL.absoluteString isEqualToString:#"about:blank"]) {
NSLog(#" This is Blank. Ignoring.");
}
else {
NSLog(#" This is a real URL.");
[self doSomethingAboutError];
}
}
Swift, Xcode 7 beta 5
webView.loadRequest(NSURLRequest(URL: NSURL(string: "about:blank")!))
Swift 4.0 , XCODE 9
webView.loadRequest(URLRequest.init(url: URL.init(string: "about:blank")!))
Same answer in Swift 4.2, xCode 10
if let clearURL = URL(string: "about:blank") {
myWebView.loadRequest(URLRequest(url: clearURL))
}

Resources