为什么在iOS7中UIWebView的canGoBack属性为NO?

13

我会像这样将这个网站嵌入我的应用程序中:

NSString *url = [NSString stringWithFormat:@"https://mobile.twitter.com/search?q=%@", @"@test OR #test"];
url = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[self.twitterWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];

self.twitterWebView.scalesPageToFit = YES;

这个网站有两个按钮可以在页面中返回和前进。我相应地调用[self.twitterWebView goBack];[self.twitterWebView goForward];

iOS 6上正常工作,但在iOS 7上,我的Web视图的canGoBack和canGoForward属性为NO,因此我的后退和前进按钮无法使用。

另外一点是,当应用程序首次安装并加载页面时,我的按钮可以正常工作。但是当我再次运行应用程序并点击网站上的链接时,我的Web视图的canGoBack属性始终返回NO。

我该如何解决这个问题?

编辑:我上传了一个小测试应用程序,展示了我的问题。您可以从这里下载它。请在iOS 7模拟器上运行应用程序,查看第一次安装应用程序时后退按钮是否有效。然后退出,再次运行应用程序,您会发现它将停止工作。

顺便说一下,问题似乎与Twitter移动网站有关。您可以尝试其他网站地址。

4个回答

18
这似乎与HTML5的“应用程序缓存”功能有关。在首次启动时,网站没有被缓存,UIWebView正确地检测到是否可以前进或后退。一旦缓存被填充,新的UIWebView实例决定,即使URL更改(可以在UIWebViewDelegatewebView:shouldStartLoadWithRequest:navigationType:中观察到),前进或后退也不再可能。 canGoForwardcanGoBack将返回NO,而goForwardgoBack将不起作用。只要该特定站点的HTML5缓存存在,这种情况会持续到应用程序重新启动。
也许这个问题只限于通过JavaScript修改URL的哈希标识符后面的片段的Web应用程序。是的,UIWebView在这种情况下的行为在iOS 6和iOS 7之间确实发生了变化。
我还没有找到解决方案,我们可能需要等待苹果在iOS 7.1或者更高版本中修复这个问题。
其他人也有这个问题:
如果您正在使用应用程序缓存,并且还通过哈希或其他技术来管理状态,则历史对象将无法保留您的导航历史记录,因此history.back()永远不会起作用,而history.length将永远保持为1。
(来自http://www.mobilexweb.com/blog/safari-ios7-html5-problems-apis-review
这个问题也存在于Safari 7.0(OS X 10.9 Mavericks默认版本)中。但是,最新的WebKit夜间构建(r158339)似乎可以正常工作。很可能只是时间问题,修复程序将会在iOS和OS X发布版本中推出。 编辑3 这个问题仍然存在于iOS 7.1和OS X 10.9.2中。 编辑4 此漏洞已在iOS 8和Safari 7.1(9537.85.10.17.1)的OS X版中得到修复! 相关:

您提供的相关链接称他们通过禁用应用程序缓存来解决问题。那该如何操作呢?谢谢! - Olie
1
@Olie 他们的意思是通过在HTML文档的“head”部分中不引用清单来完全禁用HTML5缓存功能。这并不是真正的解决方法... - Andreas Ley
嗯,那很“次优”... :\ 有什么好的解决方法吗? - Olie

3

我遇到过同样的问题。通过以下改变,我成功解决了这个问题。

实现了一个新的方法 updateButtons。

- (void)updateButtons:(UIWebView*)theWebView {
    if ([theWebView canGoBack])
    {
        self.backButton.enabled = YES;
    }
    else
    {
        self.backButton.enabled = NO;
    }
    if ([theWebView canGoForward])
    {
        self.forwardButton.enabled = YES;
    }
    else
    {
        self.forwardButton.enabled = NO;
    }
     }

shouldStartLoadWithRequest, webViewDidFinishLoad, didFailLoadWithError事件中调用上述方法。

现在来到棘手的部分。在进行以上更改后,返回和前进按钮按预期工作,除了一个情况。当我们通过点击后退按钮返回到第一页时,它没有被禁用。因为当页面通过点击后/前进按钮加载时,不会触发任何以上事件,而是从缓存中加载。

我尝试了许多方法,但只有一种解决了我的问题。

添加了一个WebHistoryItemChangedNotification观察者。

   [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(webViewHistoryDidChange:)
                                             name:@"WebHistoryItemChangedNotification"
                                           object:nil];

在 webViewHistoryDidChange 中调用了相同的 updatebuttons 方法。

- (void)webViewHistoryDidChange
{
     [self updateButtons:self.webView];
}

这个解决方案解决了我在YouTube移动页面上的问题。实际上,我在4个函数中调用了updateButtons:shouldStartLoadWithRequest、webViewDidFinishLoad、didFailLoadWithError和webViewHistoryDidChange。前三个函数在站点为桌面版本时运行良好。但是在处理移动站点时,我需要第四个函数。 - John Pang

3

我在iOS 7中也遇到了这个问题。对我有用的方法是将"canGoBack"代码和"canGoForward"代码移动到shouldStartLoadWithRequest中,如下所示。之前,我将其放在了webViewDidFinishLoad中,这适用于iOS 6,但不适用于iOS 7。

 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
 navigationType:(UIWebViewNavigationType)navigationType
 {
    if ([webView canGoBack])
    {
        [browserBackItem setEnabled:YES];
    }
    else
    {
        [browserBackItem setEnabled:NO];
    }
    if ([webView canGoForward])
    {
        [browserForwardItem setEnabled:YES];
    }
    else
    {
        [browserForwardItem setEnabled:NO];
    }
    return YES;
}

2
不,那对我也没有解决问题。我相信问题就像Andreas上面所解释的那样。 - aslı

-1

将属性更改为 "strong" 引用后,我的问题消失了。

之前:

 @property (nonatomic, weak) IBOutlet UIWebView *webView;

在将属性更改为“strong”之后:
 @property (nonatomic, strong) IBOutlet UIWebView *webView;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接