现在很多app都会内置H5页面,其中也会涉及到跟android原生交互,这就需要用到我们的webView控件,该控件功能十分强大,作用如下:

  1. 显示和渲染Web页面
  2. 也可以直接使用html(网络跟本地)作为布局
  3. 可以跟JavaScript交互调用

WebView的使用介绍内容:

  1. WebView类的自身常见方法
  2. WebView常见工具类WebSetting、WebChromeClient、WebViewClient。
  3. js跟android 之间相互调用

1.WebView类常见方法

   创建webView有两种办法 :WebView webview = new WebView(getApplicationContext());WebView作为控件放在布局中,通   过findById获取控件。第二种方式容易导致内存泄漏因为创建的WebView会一直存在,不能被销毁,第一种方式可以避免。

   加载url,  loadurl

//方式1. 加载一个网页:
webView.loadUrl("http://www.baidu.com/");

//方式2:加载apk包中的html页面
webView.loadUrl("file:///android_asset/uploadImgForH5.html");

//方式3:加载手机本地的html页面
webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");

// 方式4: 加载 HTML 页面的一小段内容
WebView.loadData(String data, String mimeType, String encoding)

设置WebView的状态

@Override
protected void onResume() {
    super.onResume();
    //激活WebView为活跃状态,能正常执行网页的响应
    webView.onResume();
}

@Override
protected void onPause() {
    super.onPause();
    //当页面被失去焦点被切换到后台不可见状态,需要执行onPause
    //通过onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。
    webView.onPause();
}

protected void onDestroy() {
    super.onDestroy();
    if (webView != null) {
        webView.setWebViewClient(null);
        webView.setWebChromeClient(null);
        //加载null内容
        webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
        //清除历史记录
        webView.clearHistory();
        //移除webView
        ((ViewGroup) webView.getParent()).removeView(webView);
        //销毁
        webView.destroy();
        webView = null;
    }
}

WebView控制网页页面回退

//是否可以回退

webView.canGoBack()

//页面回退

webView.goBack()

//是否可以前进                     
Webview.canGoForward()
//前进网页
Webview.goForward()

工具类WebSetting

WebSettings webSettings = webView.getSettings();
//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);

// 若加载的 html 里有JS 在执行动画等操作,会造成资源浪费(CPU、电量)
// 在 onStop 和 onResume 里分别把 setJavaScriptEnabled() 给设置成 false 和 true 即可

//支持插件
//webSettings.setPluginsEnabled(true);

//设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小

//缩放操作
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件

//其他细节操作
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
webSettings.setAllowFileAccess(true); //设置可以访问文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
if (isNetworkConnected(this)) {
    webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
} else {
    webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
}

WebViewClient类

public boolean shouldOverrideUrlLoading(WebView view, String url)

网页跳转拦截

public void onPageFinished(WebView view, String url)

网页加载完成调用

public void onPageStarted(WebView view, String url, Bitmap favicon)

网页开始加载调用

public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error)

WebView默认使用http,当使用https时就需要验证证书安全,就会回调这个方法

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

WebView加载异常时回调


// For Android 3.0-
public void openFileChooser(ValueCallback<Uri> uploadMsg)
// For Android 3.0+
public void openFileChooser(ValueCallback uploadMsg, String acceptType)
//For Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
// For Android 5.0+
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams)


该方法是当h5页面想要操作本地文件时调用,android 5.0+版本跟之前版本写法一致

WebViewClient类

public void onProgressChanged(WebView view, int newProgress)

网页加载进度

public void onReceivedTitle(WebView view, String title)

网页页面标题


//拦截警告弹窗,返回true表示拦截并且需要做result.cancle  or result.confirm,false相反
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    return super.onJsAlert(view, url, message, result);
}

//拦截提示弹窗,返回true表示拦截并且需要做result.cancle  or result.confirm,false相反
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
    return super.onJsPrompt(view, url, message, defaultValue, result);
}

//拦截确认弹窗,返回true表示拦截并且需要做result.cancle  or result.confirm,false相反
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
    return super.onJsConfirm(view, url, message, result)
}


js与android原生互调

js调用android 原生,android 4.2之前跟之后的有些区别,因为4.2之前的写法有安全漏洞,而且现如今4.2以下版本机型很少了,就不做介绍了,又兴趣可以自行了解。


//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript webSettings.setJavaScriptEnabled(true); webView.addJavascriptInterface(MainActivity.this,"android");


这个是调用之前的设置


@JavascriptInterface public void jsCallAndroidArgs(String text){ Toast.makeText(this,"js调用安卓:"+text,Toast.LENGTH_SHORT).show(); }


上述可以看出需要设置注解@JavascriptInterface,并且jsCallAndroidArgs方法名也需要在h5调用保持一致。

android 调用js


webView.loadUrl("javascript:javacalljswith('Android传过来的参数')");


上述可知android调用js是通过loadUrl  ,而javacalljswith(‘Android传过来的参数’)是js中声明的带参函数名,需要注意的是当我们调用时需要与webView其他方法保持在同一个线程。我们在混合开发时需要跟H5开发的同学多多沟通。h5页面代码如下:


<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="Generator" content="EditPlus®">
    <meta name="Author" content="">
    <meta name="Keywords" content="">
    <meta name="Description" content="">
    <title>H5页面上传手机照片</title>
    <script type="text/javascript">
            function javacalljs(){
                 document.getElementById("showmsg").innerHTML = "JAVA调用了JS的无参函数";
            }
            function javacalljswith(arg){
                 document.getElementById("showmsg").innerHTML = (arg);
            }
     </script>
</head>
<body>
<form action="">
    <p>图片1: <input type="file" name="uploadImg1" /></p>
    <p>图片2: <input type="file" name="uploadImg2" /></p>
    <h3 id="showmsg">调用js显示结果</h3>
    <input type="submit" value="Submit" />
    <input type="button" value="Js调用Java代码" οnclick="window.android.jsCallAndroid()"/>
    <input type="button" value="Js调用Java代码并传参数" οnclick="window.android.jsCallAndroidArgs('Js传过来的参数')"/>
    <input type="button" value="Js调用JS代码" οnclick="javacalljswith('sdfsdfs')"/>
</form>

</body>
</html>


说了这么多,然后就贴上实例,注意问题:在回调onShowFileChooser后,需要做取消filePathCallback操作,不然会出现只回调一次onShowFileChooser方法的问题;还有个问题是android7.0之后去除了项目中传递file://类似格式的uri,我们必需使用FileProvider适配,因为FileProvider是ContentProvider的子类,所以需要在AndroidManifest.xml中注册,而又因为需要对真实的filepath进行映射,所以需要编写一个xml文档,用于描述可使用的文件夹目录,以及通过name去映射该文件夹目录