Question

I'm facing a problem with UIWebView's goBack function.

My requirement is when the user presses a button (called "Back Button"), I have to redirect the user to the particular page in certain conditions. Think of it as a "cart system": When the user is at "Menu" page, he selects an item and and "add an item to cart". When he clicks "remove an item", then go to "The Item was removed" page. When the user clicks the "Back Button", the user should go back to the "Menu" instead of empty cart page.

To solve this, I thought about using "Queue" to save the URL history, then the user presses the "Back Button" in certain conditions, reload the URL from the "Queue".

I made custom NSMutableArray with enqueue/dequeue functions thanks to this answer. Then using it to store the URL history:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    _currentPage = [[request URL] absoluteString];
    NSString *targetURL = [self getTargetURLName:[request URL]];

    if ([webViewHistory count] > 5) {
        [webViewHistory dequeue];
        [webViewHistory enqueue:_currentPage];
    } else {
        [webViewHistory enqueue:_currentPage];
    }
    if ([targetURL isEqualToString:@"delete_cart"]) {
        delBackPage = [webViewHistory objectAtIndex:2];
        NSLog(@"URL BEFORE DELETE: %@", delBackPage);
    }
}  

Then call the "reload" when the "Back Button" was pressed in certain conditions:

- (void) backWebView:(id)sender
{

    currentURL = [[_webView request] URL];
    NSString *currentTGTName = [self getTargetURLName:currentURL];

    if ([_webView canGoBack])
    {
        if ([currentURL isEqual:[[_webView request] URL]])
        {
            if ([currentTGTName isEqualToString:@"my_cart"] && delBackPage != nil) {
                NSLog(@"GO BACK FROM MY_CART: %@", delBackPage);
                _requestURL = delBackPage;
                [_webView reload];
             } else {
                [_webView goBack];
                NSLog(@"WEBVIEW CANGOBACK----");
            }
        }
    ...

Now I can successfully get "delBackPage" as "Menu" page's URL. But when I reload the webView with that URL, it won't work.

Am I missing something? Is there any way to achieve this? If there is better way to control WebView's URL, it would be very appreciated.

EDIT

Thanks to the tips from Chris, we finally managed controlling "Back Button" like the following:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    url = [[request URL] absoluteString];

    // Store the conditions 
    if ([url rangeOfString:[NSString stringWithFormat:@"%@orders/my_cart", SITE_URL]].location != NSNotFound ||
        [url rangeOfString:[NSString stringWithFormat:@"%@orders/add_cart", SITE_URL]].location != NSNotFound) {
        if ([currentURLStr rangeOfString:[NSString stringWithFormat:@"%@orders/top", SITE_URL]].location != NSNotFound ||
            ...) {
        ref = currentURLStr;
        }
    }

    currentURLStr = url;
    return YES;
}  

And "Back Button"...

- (void) backWebView:(id)sender
{
    if ([currentURLStr rangeOfString:[NSString stringWithFormat:@"%@orders/top", SITE_URL]].location != NSNotFound ||
        [currentURLStr rangeOfString:[NSString stringWithFormat:@"%@orders/error", SITE_URL]].location != NSNotFound)
    {
        [[self navigationController] popViewControllerAnimated:YES];

    } else if ([currentURLStr rangeOfString:[NSString stringWithFormat:@"%@orders/genre", SITE_URL]].location != NSNotFound ||
               ....) {
        [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@orders/top/%@/%@", SITE_URL, guid, authKey]]]];

    // Refer the stored conditions...
    } else if ([currentURLStr rangeOfString:[NSString stringWithFormat:@"%@orders/my_cart", SITE_URL]].location != NSNotFound) {

        if ([ref rangeOfString:[NSString stringWithFormat:@"%@orders", SITE_URL]].location != NSNotFound) {
            [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:ref]]];
            ref = @"";
        } else {
            [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@orders/top/%@/%@", SITE_URL, guid, authKey]]]];
        }

    } else {

        if (![_webView canGoBack]) {
            [[self navigationController] popViewControllerAnimated:YES];
        } else {
            [_webView goBack];
        }
    }
}

I hope this approach helps all facing the similar problems...

Was it helpful?

Solution

It sounds like you want to have more fine-tuned control over the navigation between webpages in your app, and the standard back/forward functionality won't do.

I recommend simplifying matters by completely ignoring the built-in goBack and goForward functionality in the UIWebView, and have your buttons delegate to a "StateManager" type object - where based on the current state of the application and which direction the user is trying to go, you know which state should result (ie: which page to load).

To load the new state, just use [_webView loadRequest:request] (or one of the other load functions - see below), where request represents the new state.

I don't see how _requestURL is being used in your code above, but calling [_webView reload] will just load the last page that was loaded via one of the UIWebView load functions (ie: loadData, loadHTMLString, or loadRequest), or whatever the last page navigated to afterwards was (either through clicking links or navigating back/forward).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top