How to clear back forward list in UIWebview on iPh

2020-02-05 12:57发布

问题:

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).

回答1:

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.



回答2:

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:

  1. 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]];

  2. 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.



回答3:

Just recreate the webview. it would reset everything including history.



回答4:

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).



回答5:

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.



回答6:

I would imagine you can break the history by manually loading some HTML...

Something like:

[webview loadHTMLString:@"" baseURL:@""];


回答7:

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.



回答8:

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.