Using a UIWebView with loadHTMLString/loadData breaks the back and forward buttons, workaround?
There's a known problem with embedded UIWebViews that if you load data into them using loadHTMLString or loadData, the canGoBack/canGoForward properties and goBack/goForward methods don't work. These only work when using loadRequest.
Since Safari's normal app cache doesn't work in embedded UIWebViews, creating a native app that effectively caches otherwise live content becomes impossible/unusable. That is, I can cache the contents of the HTML, Javascript, images, etc. and load them via loadHTMLString or loadData, but then the back and forward buttons don't work.
I could also use loadRequest and specify a file URL, but that breaks when it comes t开发者_运维百科o communicating with the live site -- even if I specify a tag (because of cookie domain issues).
I have a work around that involves basically re-implementing the app cache using local store (and not having the native app do any caching itself), which is OK, but not really ideal. Are there any other work arounds/something I missed?
I am using the UIWebView's canGoBack to check to see if I'm at the first page of the history. If I am then I just call the little method I used to load the first page (displayLocalResource sets up the HTMLString and loads it into the webView). Here is a snippet:
//Implementing a back button
- (void)backOne:(id)sender{
if ([webView canGoBack]) {
// There's a valid webpage to go back to, so go there
[webView goBack];
} else {
// You've reached the end of the line, so reload your own data
[self displayLocalResource];
}
}
So do you download the HTML yourself, then pass it to UIWebView as a string? Why so? Do you modify it on the fly or something?
Maybe a custom URL schema would help? You use loadRequest with a schema of your own, which in turn works with HTTP and then feeds the webview whatever data you want?
I had a same problem. I tried manage the history, but it is error prone. Now I have discovered a better solution of this.
What you want to do is simply add a loadRequest to about:blank and make that as a placeholder for you before you call loadHTMLString/loadData. Then you are totally free from monitoring the history. The webview.canGoBack and canGoForward will just work. Of course, you will need a hack to handle go back to the placeholder about:blank. You can do that in webViewDidFinishLoad. Here is the code highlight:
In the function when you call loadHTMLString:
[weakSelf.fbWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
[weakSelf.fbWebView loadHTMLString:stringResponse baseURL:url];
Code to handle goBack:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if ([webView.request.URL.absoluteString isEqualToString:@"about:blank"]
&& ![webView canGoBack] && [webView canGoForward]) {
[weakSelf.fbWebView loadHTMLString:stringResponse baseURL:url];
}
}
I think it is also possible expand this solution to handle those loadHTMLString that is not the first load. Just by having a Stack to record all the string response and insert an about:blank on each loadHTMLString. And pop the stack when each time go back to about:blank.
Could you fetch the content, save it to the local filesystem, point the webview to the local filesystem using file:// URLs, then intercept the link follows with shouldStartLoadWithRequest to fetch more to local fs, point webview at new local content, etc?
I've had good luck with UIWebView and file:/// URLs. Basically you'd be intercepting load requests, fetching stuff yourself, writing it to the local filesystem with rewritten URLs, then loading that into the browser.
There seems to be no way to load/save the browser history.
Loading the string into a temp file and using that as a URL request seems to cure this. It's something about loading the string directly that causes UIWebView not to see it as the home page you can navigate back to. This code worked for me:
//If you load the string like this, then "webView.canGoBack" never returns YES. It's documented frequently on the web.
//Loading the string as a URL instead seems to work better.
//[self.myWebView loadHTMLString:str baseURL:nil];
//write the string to a temp file
NSString *fileName = @"homepage.html";
NSURL *fileURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:fileName]];
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
[data writeToURL:fileURL atomically:NO];
//open that temp file in the UIWebView
[self.myWebView loadRequest:[NSURLRequest requestWithURL:fileURL]];
Use this to enable/disable the back button:
- (void)webViewDidFinishLoad:(UIWebView *)webView{
//this is to check if we're back at the root page.
if (webView.canGoBack == YES) {
self.backButton.enabled=YES;
}
else {
self.backButton.enabled=NO;
}
}
精彩评论