WebView使用解析(二)之WebViewClient/WebChromeClient

WebViewClient—–在影响View的事件到来时,会通过WebViewClient中的方法回调通知用户。
WebChromeClient—–当影响浏览器的事件到来时,就会通过WebChromeClient中的方法回调通知用法。
通过上面的对比,我们发现WebViewClient和WebChromeClient都是针对不同事件的回调,而google将这些回调进行分类集合,就产生了WebViewClient、WebChromeClient这两个大类,其中管理着针对不同类型的回调而已。

WebViewClient

WebViewClient中函数概述:

/**
 * 在开始加载网页时会回调
 */
public void onPageStarted(WebView view, String url, Bitmap favicon) 
/**
 * 在结束加载网页时会回调
 */
public void onPageFinished(WebView view, String url)
/**
 * 拦截 url 跳转,在里边添加点击链接跳转或者操作
 */
public boolean shouldOverrideUrlLoading(WebView view, String url)
/**
 * 加载错误的时候会回调,在其中可做错误处理,比如再请求加载一次,或者提示404的错误页面
 */
public void onReceivedError(WebView view, int errorCode,String description, String failingUrl)
/**
 * 当接收到https错误时,会回调此函数,在其中可以做错误处理
 */
public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error)
/**
 * 在每一次请求资源时,都会通过这个函数来回调
 */
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
    return null;
}

我们一个个来看:

1. WebViewClient之onPageStarted与onPageFinished

onPageStarted:通知主程序页面当前开始加载。
onPageFinished:通知主程序页面加载结束。

举个例子:开始加载时显示加载圆圈,结束加载时隐藏加载圆圈。

public class MainActivity extends Activity {
    private WebView mWebView;

    private ProgressDialog mProgressDialog;
    private String TAG = "watson";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = (WebView)findViewById(R.id.webview);
        mProgressDialog = new ProgressDialog(this);
        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.loadUrl("http://blog.csdn.net/huaxun66");
        mWebView.setWebViewClient(new WebViewClient(){

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                mWebView.loadUrl(url);
                return true;
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                mProgressDialog.show();
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                mProgressDialog.hide();
            }
        });
    }
}

从图中可以看出,在加载页面的时候会显示圆形加载框,在加载成功以后会隐藏加载框。
这里写图片描述

2. WebViewClient之shouldOverrideUrlLoading

(1)如何在WebView中加载在线网址
上篇文章也说过,如果要在WebView中加载在线网址,必须重写WebViewClient,其实给webview设置一个空的WebViewClient对象即可,没必要重写WebViewClient的方法。使用它的默认回调就可以实现在WebView中加载在线URL了:

mWebView.setWebViewClient(new WebViewClient());

(2)shouldOverrideUrlLoading用途
由于每次超链接在加载前都会先走shouldOverrideUrlLoading回调,所以我们如果想拦截某个URL,将其转换成其它URL可以在这里做。
比如,我们拦截所有包含“blog.csdn.net”的地址,将其替换成”www.baidu.com”:

mWebView.setWebViewClient(new WebViewClient(){
     @Override
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (url.contains("blog.csdn.net")){
                 view.loadUrl("http://www.baidu.com");
            }
            return false;
      }
});

效果图如下:
这里写图片描述

这里需要非常注意的是:返回值是boolean类型,表示是否屏蔽WebView继续加载URL的默认行为。因为这个函数是WebView加载URL前回调的,所以如果我们return true,则WebView接下来就不会再加载这个URL了。如果我们return false,则系统就认为上层没有做处理,接下来还是会继续加载这个URL的。WebViewClient默认就是return false的。
一般建议大家return false,我们只关心我们关心的拦截内容,对于不拦截的内容,让系统自己来处理即可。就像我们上面的代码。

3. WebViewClient之onReceivedError
onReceivedError的完整声明如下:

public void onReceivedError(WebView view, int errorCode,String description, String failingUrl)

加载错误的时候会产生这个回调,在其中可做错误处理,比如我们可以加载一个错误提示页面
这里有四个参数:

  • WebView view:当前的WebView实例
  • int errorCode:错误码
  • String description:错误描述
  • String failingUrl:当前出错的URL

我们可以先写一个错误提示的本地页面:(error.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 id="h">出错了……</h1>
</body>
</html>

然后在加载返回错误时,重新加载错误页面:

mWebView.setWebViewClient(new WebViewClient(){
    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        super.onReceivedError(view, errorCode, description, failingUrl);
        mWebView.loadUrl("file:///android_asset/error.html");
    }
});

最后让webview加载一个错误的URL。

这里写图片描述

4.WebViewClient之onReceivedSslError
我们知道HTTPS协议是通过SSL来通信的,所以当使用HTTPS通信的网址(以https://开头的网站)出现错误时,就会通过onReceivedSslError回调通知过来,它的函数声明为:

/**
 * 当接收到https错误时,会回调此函数,在其中可以做错误处理
 */
public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error)
  • WebView view:当前的WebView实例
  • SslErrorHandler handler:当前处理错误的Handler,它只有两个函数SslErrorHandler.proceed()和SslErrorHandler.cancel(),SslErrorHandler.proceed()表示忽略错误继续加载,SslErrorHandler.cancel()表示取消加载。在onReceivedSslError的默认实现中是使用的SslErrorHandler.cancel()来取消加载,所以一旦出来SSL错误,HTTPS网站就会被取消加载了,如果想忽略错误继续加载就只有重写onReceivedSslError,并在其中调用SslErrorHandler.proceed()
  • SslError error:当前的的错误对象,SslError包含了当前SSL错误的基本所有信息

默认加载SSL出错的网站——出现空白页面
12306是通过Https协议来传输的,但是它的SSL证书不是CA颁发的,不被我们APP认可,所以我们就以12306网站为例:

public class MainActivity extends Activity {
    private WebView mWebView;
    private String TAG = "watson";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = (WebView)findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.loadUrl("https://www.12306.cn/");
        mWebView.setWebViewClient(new WebViewClient(){
            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                super.onReceivedSslError(view, handler, error);
            }
        });
    }
}

在这里仅仅重写onReceivedSslError,并调用super.onReceivedSslError(view, handler, error);来调用默认的处理方式。发现页面显示空白。

我们修改一下代码:

public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
//      一定要注释掉!    
//      super.onReceivedSslError(view, handler, error);
        handler.proceed();
}

这里做了两个改变:
第一:注释掉super.onReceivedSslError(view, handler, error);,取消系统的默认行为,我们看源码,可以发现WebViewClient中onReceivedSslError的默认实现是handler.cancel(); 即取消继续加载。
第二:调用handler.proceed();来忽略错误继续加载页面。

所以此时的效果图为:
这里写图片描述

对于onReceivedSslError结论:
1.当出现SSL错误时,WebView默认是取消加载当前页面,只有去掉onReceivedSslError的默认操作,然后添加SslErrorHandler.proceed()才能继续加载出错页面
2.当HTTPS传输出现SSL错误时,错误会只通过onReceivedSslError回调传过来,不会执行onReceivedError

5. WebViewClient之shouldInterceptRequest
在每一次请求资源时,都会通过这个函数来回调,比如超链接、JS文件、CSS文件、图片等,也就是说浏览器中每一次请求资源时,都会回调回来,无论任何资源!但是必须注意的是shouldInterceptRequest函数是在非UI线程中执行的,在其中不能直接做UI操作,如果需要做UI操作,则需要利用Handler来实现,该函数声明如下:

public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
    return null;
}

该函数会在请求资源前调用,我们可以通过返回WebResourceResponse的处理结果来让WebView直接使用我们的处理结果。如果我们不想处理,则直接返回null,系统会继续加载该资源。
利用这个特性,我们可以解决一个需求:假如网页中需要加载本地的图片,我们就可以通过拦截shouldInterceptRequest,并返回结果即可 。
比如下面的一段HTML代码中,img字段加载图片的地址是:http://localhost/android.png,这是我自定义的一个网址,在Android中,当发现要加载这个地址的资源时,我们将它换成本地的图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 id="h">WebView使用解析</h1>
    <img src="http://localhost/android.png"/>
</body>
</html>
public class MainActivity extends Activity {
    private WebView mWebView;
    private String TAG = "watson";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
                try {
                    if (url.equals("http://localhost/android.png")) {
                        AssetFileDescriptor fileDescriptor = getAssets().openFd("qqq.jpg");
                        InputStream stream = fileDescriptor.createInputStream();
                        WebResourceResponse response = new WebResourceResponse("image/png", "UTF-8", stream);
                        return response;
                    }
                } catch (Exception e) {
                    Log.e(TAG, e.getMessage());
                }
                return super.shouldInterceptRequest(view, url);
            }
        });
        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

这里代码比较容易理解,当发现当前加载资源的url是我们自定义的http://localhost/android.jpg时,就直接将本地的图片qqq.jpg作为结果返回。
这里写图片描述

6. WebViewClient之其余函数

/**
 * 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次
 */
public void onLoadResource(WebView view, String url) 
 /**
 *  (WebView发生改变时调用) 
 *  可以参考http://www.it1352.com/191180.html的用法
 */
 public void onScaleChanged(WebView view, float oldScale, float newScale)
 /**
 * 重写此方法才能够处理在浏览器中的按键事件。
 * 是否让主程序同步处理Key Event事件,如过滤菜单快捷键的Key Event事件。
 * 如果返回true,WebView不会处理Key Event,
 * 如果返回false,Key Event总是由WebView处理。默认:false
 */
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event)
 /**
 * 是否重发POST请求数据,默认不重发。
 */
onFormResubmission(WebView view, Message dontResend, Message resend)
 /**
 * 更新访问历史
 */
doUpdateVisitedHistory(WebView view, String url, boolean isReload)
 /**
 * 通知主程序输入事件不是由WebView调用。是否让主程序处理WebView未处理的Input Event。
 * 除了系统按键,WebView总是消耗掉输入事件或shouldOverrideKeyEvent返回true。
 * 该方法由event 分发异步调用。注意:如果事件为MotionEvent,则事件的生命周期只存在方法调用过程中,
 * 如果WebViewClient想要使用这个Event,则需要复制Event对象。
 */
onUnhandledInputEvent(WebView view, InputEvent event)
 /**
 * 通知主程序执行了自动登录请求。
 */
onReceivedLoginRequest(WebView view, String realm, String account, String args)
/**
 * 通知主程序:WebView接收HTTP认证请求,主程序可以使用HttpAuthHandler为请求设置WebView响应。默认取消请求。
 */
onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)
/**
 * 通知主程序处理SSL客户端认证请求。如果需要提供密钥,主程序负责显示UI界面。
 * 有三个响应方法:proceed(), cancel() 和 ignore()。
 * 如果调用proceed()和cancel(),webview将会记住response,
 * 对相同的host和port地址不再调用onReceivedClientCertRequest方法。
 * 如果调用ignore()方法,webview则不会记住response。该方法在UI线程中执行,
 * 在回调期间,连接被挂起。默认cancel(),即无客户端认证
 */
onReceivedClientCertRequest(WebView view, ClientCertRequest request)

WebChromeClient

WebChromeClient的常用函数:

/**
 * 当网页调用alert()来弹出alert弹出框前回调,用以拦截alert()函数
 */
public boolean onJsAlert(WebView view, String url, String message,JsResult result)
/**
 * 当网页调用confirm()来弹出confirm弹出框前回调,用以拦截confirm()函数
 */
public boolean onJsConfirm(WebView view, String url, String message,JsResult result)
/**
 * 当网页调用prompt()来弹出prompt弹出框前回调,用以拦截prompt()函数
 */
 public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result) 
 /**
 * 打印 console 信息
 */
 public boolean onConsoleMessage(ConsoleMessage consoleMessage)
 /**
 * 通知程序当前页面加载进度
 */
 public void onProgressChanged(WebView view, int newProgress)

1. WebChromeClient之onJsAlert、onJsConfirm、onJsPrompt

我们把这三个函数一起看,因为他们都是为了处理弹出框。

(1)、为何JS中的alert()、confirm()、prompt()无效
首先,我们来举个例子,在网页中加上按钮,在点击时分别调用alert()、confirm()、prompt()来弹出不同的对话框 。
web.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 id="h">WebView使用解析</h1>
<button onclick="confirm('confirm文字')">confirm</button>
<button onclick="alert('alert文字')">alert</button>
<button onclick="prompt('prompt文字')">prompt</button>
</body>
</html>

JAVA

public class MainActivity extends Activity {
    private WebView mWebView;
    private String TAG = "watson";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

这里写图片描述
从效果图中,虽然启用了JavaScript但是在网页中的confrim()、alert()、prompt()却是没有效果!
我们只需要在程序中加上一句话就可以实现confrim()、alert()、prompt()的弹出效果了 。

mWebView.setWebChromeClient(new WebChromeClient());

这里写图片描述

(2)使用onJsAlert拦截alert()函数概述
复写onJsAlert函数:

mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                Toast.makeText(MainActivity.this,"onJsAlert message="+message,Toast.LENGTH_SHORT).show();
                result.confirm();
                return true;
            }
        });

这三句话,句句非常重要:
第一句:

Toast.makeText(MainActivity.this,"onJsAlert message="+message,Toast.LENGTH_SHORT).show();

表示我们拦截html中alert函数之后,做我们自己的操作,这里是弹出一行toast。
第二句:

result.confirm();

这句话非常重要,它表示向WebView通知操作结果,JsResult有两个函数:JsResult.confirm()和JsResult.cancel(),JsResult.confirm()相当于点击了弹出框的确定按钮,JsResult.cancel()则相当于点击了弹出框的取消按钮。
如果没有使用JsResult来告诉WebView处理结果,则WebView就会认为这个弹出框还一直弹在那里,你再点击alert按钮,将会无效;
第三句:

return true;

表示告诉WebView我们已经拦截了alert()函数,不需要再弹出网页中的alert弹出框了,如果我们return false,那么WebView就会认为我们没有拦截alert()函数,会继续弹出alert对话框。

有关confrim()和prompt()的拦截,我们就不再讲了,与拦截alert()一样!

2、WebChromeClient之onConsoleMessage

当html中调用console相关输出的时候,就会通过onConsoleMessage进行通知

public boolean onConsoleMessage(ConsoleMessage consoleMessage)

参数意义:

  • ConsoleMessage consoleMessage:保存着当前消息的类型和消息内容返回值:如果返回true时,就表示拦截了console输出,系统就不再通过console输出出来了,如果返回false则表示没有拦截console输出,调用系统默认处理。

我们来看下正常情况下,console输出的内容及用法
先来看html内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 id="h">WebView使用解析</h1>
<button onclick="log()">log</button>
</body>
<script type="text/javascript">
function log(){
  console.log("console.log");
  console.warn("warnning");
  console.error("error");
}
</script>
</html>

JAVA代码:

public class MainActivity extends Activity {
    private WebView mWebView;
    private String TAG = "watson";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

除了alert,prompt,confirm以外,其它时候都不需要强制设置WebChromeClient 。
当点击log按钮时,会调用console的函数把log输出出来
logcat中可以看到如下日志:
这里写图片描述

下面我们就重写WebChromeClient的onConsoleMessage方法,把console消息拦截掉,然后把消息利用toast弹出来:

mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
                Toast.makeText(MainActivity.this,consoleMessage.message(),Toast.LENGTH_SHORT).show();
                return  true;
            }
        });

效果图如下:
这里写图片描述
由于我们return true,消息拦截成功,控制台将不会再看到我们的消息日志了。

3、WebChromeClient之onProgressChanged

表示当前页面的加载速度,函数声明如下:

public void onProgressChanged(WebView view, int newProgress)
  • WebView view:当前WebView实例
  • int newProgress:当前的加载进度,值从0到100

比如我们加载“http://blog.csdn.net/huaxun66
然后把加载进度用日志打出来:

public void onProgressChanged(WebView view, int newProgress) {
         Log.e(TAG,"progress:"+newProgress);
         super.onProgressChanged(view, newProgress);
}

这里写图片描述

大家一定要注意,底层实现时,是利用handler来定时轮循当前进度的,每隔一定时间查询一次,所以每次拿到的进度数据是不一样的,也就是说如果页面较简单,可能会直接返回100,而跳过中间的各个数据。也就是说,除了100,其它任何一个数值不是一定返回的,所以大家如果要用到进度除了数值100可以用等号来判断,其它一定要用大于号或小于号,如果用了等号,可能永远也不会执行到!

4、WebChromeClient之其它函数

/*
* 通知页面标题变化
*/
nReceivedTitle(WebView view, String title)

/*
* 通知当前页面网站新图标
*/
onReceivedIcon(WebView view, Bitmap icon)

/*
* 通知主程序图标按钮URL
*/
onReceivedTouchIconUrl(WebView view, String url, boolean precomposed)

/*
* 通知主程序当前页面将要显示指定方向的View,该方法用来全屏播放视频。
*/
public interface CustomViewCallback {
       // 通知当前页面自定义的View被关闭
       public void onCustomViewHidden();
   }
onShowCustomView(View view, CustomViewCallback callback)

/*
* 与onShowCustomView对应,通知主程序当前页面将要关闭Custom View
*/
onHideCustomView()

/**
 * 请求主程序创建一个新的Window,如果主程序接收请求,返回true并创建一个新的WebView来装载Window,然后添加到View中,发送带有创建的WebView作为参数的resultMsg的给Target。如果主程序拒绝接收请求,则方法返回false。默认不做任何处理,返回false
 */
onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg)

/*
* 显示当前WebView,为当前WebView获取焦点。
*/
onRequestFocus(WebView view)

/*
* 通知主程序关闭WebView,并从View中移除,WebCore停止任何的进行中的加载和JS功能。
*/
onCloseWindow(WebView window)

/**
 * 告诉客户端显示离开当前页面的导航提示框。如果返回true,由客户端处理确认提示框,调用合适的JsResult方法。如果返回false,则返回默认值true给javascript接受离开当前页面的导航。默认:false。JsResult设置false,当前页面取消导航提示,否则离开当前页面。
 */
onJsBeforeUnload(WebView view, String url, String message, JsResult result)

/**
 *通知主程序web内容尝试使用定位API,但是没有相关的权限。主程序需要调用调用指定的定位权限申请的回调。更多说明查看GeolocationPermissions相关API。
 */
onGeolocationPermissionsShowPrompt(String origin,GeolocationPermissions.Callback callback)

/*
 * 通知程序有定位权限请求。如果onGeolocationPermissionsShowPrompt权限申请操作被取消,则隐藏相关的UI界面。
 */
onGeolocationPermissionsHidePrompt()

/**
*通知主程序web内容尝试申请指定资源的权限(权限没有授权或已拒绝),主程序必须调用PermissionRequest#grant(String[])或PermissionRequest#deny()。如果没有覆写该方法,默认拒绝。
*/
onPermissionRequest(PermissionRequest request)

/**
* 通知主程序相关权限被取消。任何相关UI都应该隐藏掉。
*/
onPermissionRequestCanceled(PermissionRequest request)

/**
* 通知主程序 执行的Js操作超时。客户端决定是否中断JavaScript继续执行。如果客户端返回true,JavaScript中断执行。如果客户端返回false,则执行继续。注意:如果继续执行,重置JavaScript超时计时器。如果Js下一次检查点仍没有结束,则再次提示。
*/
onJsTimeout()

/**
*当停止播放,Video显示为一张图片。默认图片可以通过HTML的Video的poster属性标签来指定。如果poster属性不存在,则使用默认的poster。该方法允许ChromeClient提供默认图片。
*/
getDefaultVideoPoster()

/**
* 当用户重放视频,在渲染第一帧前需要花费时间去缓冲足够的数据。在缓冲期间,ChromeClient可以提供一个显示的View。如:可以显示一个加载动画。
*/
getVideoLoadingProgressView()

/**
* 获取访问历史Item,用于链接颜色。
*/
getVisitedHistory(ValueCallback callback)

/**
* 通知客户端显示文件选择器。用来处理file类型的HTML标签,响应用户点击选择文件的按钮操作。调用filePathCallback.onReceiveValue(null)并返回true取消请求操作。
* FileChooserParams参数的枚举列表:
MODE_OPEN 打开
MODE_OPEN_MULTIPLE 选中多个文件打开
MODE_OPEN_FOLDER 打开文件夹(暂不支持)
MODE_SAVE 保存
*/
onShowFileChooser(WebView webView, ValueCallback filePathCallback,FileChooserParams fileChooserParams)

/**
* 解析文件选择Activity返回的结果。需要和createIntent一起使用。
*/
parseResult(int resultCode, Intent data)

/**
* 创建Intent对象来启动文件选择器。Intent支持可访问的简单类型文件资源。不支持高级文件资源如live media capture媒体快照。如果需要访问这些资源或其他高级文件类型资源可以自己创建Intent对象。
*/
createIntent()

/**
* 返回文件选择模式
*/
getMode()

/**
* 返回可访问MIME类型数组,如audio/*,如果没有指定可访问类型,数组返回为null
*/
getAcceptTypes()

/**
* 返回优先的媒体快照类型值如Camera、Microphone。true:允许快照。false,禁止快照。使用getAcceptTypes方法确定合适的capture设备。
*/
isCaptureEnabled()

/**
* 返回文件选择器的标题。如果为null,使用默认名称。
*/
getTitle()

/**
*指定默认选中的文件名或为null
*/
getFilenameHint()

其它事件处理

上面讲了有关WebViewClient的用法,但其中还有一些小问题是WebViewClient无法解决的,比如返回按键、滚动事件监听等

1、返回按键
如果用webview点链接看了很多页以后,如果不做任何处理,点击系统“Back”键,整个浏览器会调用finish()而结束自身,如果希望浏览的网页回退而不是退出浏览器,需要在当前Activity中处理并消费掉该Back事件。 覆盖Activity类的onKeyDown(int keyCode, KeyEvent event)方法。

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
         //改写物理返回键的逻辑
        if(keyCode==KeyEvent.KEYCODE_BACK) {
            if(mWebView.canGoBack()) {
                mWebView.goBack();//返回上一页面 
                return true;
            } else {
                System.exit(0);//退出程序 
            }
        }
        return super.onKeyDown(keyCode, event);
    }

2、滚动事件监听
我们都知道监听滚动事件一般都是设置setOnScrollChangedListener,可惜的是 WebView并没有给我们提供这样的方法,但是我们可以重写WebView,覆盖里面的一个方法: protected void onScrollChanged(final int l, final int t, final int oldl,final int oldt){} 然后再对外提供一个接口,示例代码如下:

public class MyWebView extends WebView {

    private OnScrollChangedCallback mOnScrollChangedCallback;

    public MyWebView(Context context) {
        super(context);
    }

    public MyWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (mOnScrollChangedCallback != null) {
            mOnScrollChangedCallback.onScroll(l,t,oldl,oldt);
        }
    }

    public OnScrollChangedCallback getOnScrollChangedCallback() {
        return mOnScrollChangedCallback;
    }

    public void setOnScrollChangedCallback(
            final OnScrollChangedCallback onScrollChangedCallback) {
        mOnScrollChangedCallback = onScrollChangedCallback;
    }

    public static interface OnScrollChangedCallback {
        public void onScroll(int left,int top ,int oldLeft,int oldTop);
    }
}

3、如何强制使用外部浏览器打开网页
如果不想在 webview 中显示网页,而是直接跳转到浏览器的话,可以像下边那样调用。

Uri uri = Uri.parse("http://www.example.com"); 
Intent intent = new Intent(Intent.ACTION_VIEW, uri); 
startActivity(intent);

这里是使用隐式Intent的方式来启用外部应用。

  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值