I want to access/clear the back forward list as if the UIWebView
is new again. Is there any public API or workaround to do this?
I've tried:
while ([webview canGoback]) {
[webview goBack];
}
but that will freeze the device (simulator too).
Disclaimer
As with anything like this, bear in mind that the results may not make it through app store approval and may not work at-all with future revisions of the SDK.
There is no official method for doing this in the SDK. However if you really want to clear the back/forward history of a UIWebView
it can be done with a little delve into the private frameworks.
A quick and dirty way to do it (complete with a bunch of ugly compiler warnings) is as follows:
Given that myUIWebViewInstance
is a perfectly normal instance of UIWebView
:
id internalWebView=[[myUIWebViewInstance _documentView] webView];
[internalWebView setMaintainsBackForwardList:NO];
[internalWebView setMaintainsBackForwardList:YES];
There is also the rather tempting _clearBackForwardCache
method in the framework, however it didn't seem to do much when tickled. Just flipping the boolian worked a treat for me.
If you're trying to "reuse" an existing UIWebView, and disable the ability to go back to whatever previous page it was in before, you can:
When loading the new request (the one that user shouldn't go back from), save the URL of the new request, say like:
self.curURL = [NSURL urlWithString:@"http://www.bla.com"];
[webview loadRequest:[NSURLRequest requestWithURL:curURL]];
I'm guessing you have your own back button, so on your webViewDidFinishLoad delegate method, add:
backbttn.enabled = webView.canGoBack && ![[webView.request URL] isEqual: curURL];
This way, the user won't even know that the UIWebView can go back to the page before.
Just recreate the webview. it would reset everything including history.
I was successful (as far as you can call such a workaround 'successful') using the following line of code:
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"if( window.history.length > 1 ) { window.history.go( -( window.history.length - 1 ) ) }; window.setTimeout( \"window.location.replace( '%@' )\", 300 );", targetLocation]];
where targetLocation
is the desired URL as a NSString
.
What it does is to tell the browser to go as far backwards as the history goes and then, after a short timeout, load the desired URL.
This of course does not solve the problem of clearing the forward going history (which I didn't need in my case).
I think if you release the uiwebview object and recreate then it would clear the history. I actually have a reverse problem. My uiwebview object automatically gets released during low memory event if it's inside a nonvisible view. I then have to recreate it in viewDidLoad but it does not retain the history from that point onwards.
I would imagine you can break the history by manually loading some HTML...
Something like:
[webview loadHTMLString:@"" baseURL:@""];
I've tried almost every solution posted without much success. My case is for Childbrowser phonegap plugin, but is based in the same problem, a single webview instance used to show external pages in my application. When I show an external page, the webview maintains the history of previous pages shown.
I wanted to remove the history when I show a new external webpage.
After some research, I've found a solution in this SO post that worked for me.
[webView stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML = \"\";"];
In the case of childbrowser, I placed it in the method -(IBAction) onDoneButtonPress:(id)sender
, which previously inserted a blank page to start blank (but with back button enabled).
HTH!
Milton.
Picking up Gilbert's clever approach: If modified, it does work with redirects (something it isn't capable of so far, as mharper pointed out).
Before loading the request, save the desired URL and set a boolean member variable called _saveURL
to indicate that the redirect URL shall be saved (you will see the exact use of these two variables later):
- (void)my_loadURL:(NSURL *)url
{
NSURLRequest *request = [NSURLRequest requestWithURL:url]; // create the request
[_desiredURL release]; // clear up the previous value (assuming -my_loadURL: may be called multiple times)
_desiredURL = [url retain]; // store the desired URL (will be used later)
_saveURL = YES; // will also be used later
[_webView loadRequest:request]; // start loading the request
}
(The retain and release calls of course won't be necessary if compiling in an Automatic Reference Counting (ARC) environment.)
Now in the -webViewDidFinishLoad:
delegate callback, check to see whether the redirect has already occured by testing whether the URL of the web view's current request differs from the desired URL. If so, save the redirect URL in a member variable _firstURL
. This is also where _saveURL
gets into place. It is to avoid overwriting _firstURL
each time this delegate method is called.
Also, enable or disable the back and forward buttons just the way we did before.
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// grab the URL currently being loaded
NSURL *currentURL = [webview.request URL];
// check whether we are supposed to save the redirect URL and
// whether redirection has taken place yet
if (_saveURL && ![currentURL isEqual:_desiredURL]) {
[_firstURL release];
_firstURL = [currentURL retain];
}
// adjust the enabled-state of the back and forward buttons just like before
_backButton.enabled = _webView.canGoBack && ![currentURL isEqual:_firstURL];
_forwardButton.enabled = _webView.canGoForward;
}
(Again, retain and release are not needed with ARC enabled.)
However, there's one key disadvantage of this method. It only works if you know for sure that the URL passed into my_loadURL:
will redirect. Otherwise, the _firstURL
variable will be set somewhen else. So if you can't tell whether the according URL will redirect, then this approach does not fit your needs. Anyway, it did fit my needs, and I hope I could help out someone else as well.
Update: You can improve this method by dropping all of that dealing with _desiredURL, meaning don't save the desired URL in -my_loadURL:
and in -webViewDidFinishLoad:
just say if(_saveURL)
. This way, it'll work for websites that either don't redirect at all or that redirect instantly.