现在很多 App 上许多内容都采用 WebView 来展示 H5 内容,以减少开发时间和开发成本,但是这也就遇到了一个问题。

在 Android 应用中,是以栈来展示不同的 UI 界面的,栈的概念相信学过开发的人都不会陌生,先进后出嘛。

栈

但是,WebView 相当于一个浏览器容器,是嵌在一个 Activity 中的,所以遇到的问题就是,当应用检测到用户触摸 Back 键时,会把这个 Activity 从栈中移除,也就是说,如果我在第一个 Activity 中使用 WebView 的话,无论用户在这个 WebView 中进行了什么操作,只要触摸 Back 键,就相当于退出程序。

这显然不是我们想要的。

我们可以通过重写 Back 键的响应方法,让程序监测到当用户触摸 Back 键时,如果 WebView 能够返回,则使网页返回上一页,如果没有上一页,则按照正常的 Back 键逻辑操作。

方法一,重写 onKeyDown() 方法,代码如下:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if(keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
        webView.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

监测当 keyCode 为 Back 键并且网页可回退时则使网页返回。返回值在这里表示是否能完全处理该事件,在此处返回 TRUE,以防止此事件被进一步传播,如果返回 FALSE,则表示还没有处理完这个事件,它应该继续传播到其他监听。

方法二:重写 onBackPressed() 方法,代码如下:

@Override
public void onBackPressed() {
    if (webView.canGoBack()) {
        webView.goBack();
    } else {
        super.onBackPressed();
    }
}

需要注意的是,super.onBackPressed() 会自动调用 finish() 方法,关闭当前 Activity,所以这里放在 ELSE 分支执行,即当网页不可回退的情况下销毁当前 Activity

这两个方法其实大同小异,都是先使用 WebView.canGoBack() 方法来判断网页是否可以回退,如果可以的话就执行 WebView.goBack() 使其返回上一页,如果不可以回退,则调用父类的方法,销毁当前 Activity,唯一的区别就是,onKeyDown() 方法监听的是手机上所有按键,然后再在该方法内部进行判断是否为 Back 键,而 onBackPressed() 方法则仅监听 Back 键。

当然,这样还会遇到一个交互十分不友好的情况,就是如果用户在 WebView 中进行了多步操作,当用户想要退出应用时,需要连续点击多次 Back 键,使 WebView 中的网页回到最开始的页面才能退出。

对于这种情况,我的做法是在 Toolbar 上添加一个一键退出的按钮,直接把这个 Activityfinish() 掉,这也是目前大多数 App 使用的方案。