Android WebView总结

沈建柏
2023-12-01

什么是WebView?

WebView是Android中的原生UI控件,主要用于在app应用中方便地访问远程网页或本地html资源。同时,WebView也在Android中充当Java代码和JS代码之间交互的桥梁。实际上,也可以将WebView看做一个功能最小化的浏览器。

WebView的应用场景

目前很多公司的 App 使用一个 WebView 作为网页加载, App 中的所有网页内容使用 HTML5 进行展示,这样只需要写一次 HTML5 代码,就可以在 Android 和 iOS 平台上运行,这就是所谓的跨平台 。随着 HTML5 的普及,很多 App 都会内嵌 WebView 来加载 HTML5 页面,即 原生和HTML5 共存,这就是当下最流行的「 混合开发 」。HTML5 最大的优势是迭代方便, 只需要修改服务端的 HTML5 页面,App 会同步更新,无论是做活动推广 App 还是及时修复 Bug 都带来的极大的便利。不过 HTML5 劣势也很明显,当网速不尽如人意时候,加载速度会很慢(不知道5G出现后结果会带来什么变革),也就是HTML5 加载受限于网络,没有原生控件流畅,用户体验相对较差, 所以目前完全使用 HTML5 开发 App 并没有成为主流。

基本使用

先加入权限

<uses-permission android:name="android.permission.INTERNET" />

创建WebView

<WebView
         android:id="@+id/webview"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />

获取WebView实例

		//获得控件
        WebView webView = (WebView) findViewById(R.id.wv_webview);
        //加载网页
        webView.loadUrl("http://www.baidu.com");

WebView的状态

	mWebView.onResume();// 生命周期onResume
    mWebView.resumeTimers();//生命周期resumeTimers
    mWebView.onPause();//生命周期onPause
    mWebView.pauseTimers();//生命周期pauseTimers (上数四个方法都是成对出现)
    mWebView.stopLoading();// 停止当前加载
    mWebView.clearMatches();// 清除网页查找的高亮匹配字符。
    mWebView.clearHistory();// 清除当前 WebView 访问的历史记录
    mWebView.clearSslPreferences();//清除ssl信息
    mWebView.clearCache(true);//清空网页访问留下的缓存数据。需要注意的时,由于缓存是全局的,所以只要是WebView用到的缓存都会被清空,即便其他地方也会使用到。该方法接受一个参数,从命名即可看出作用。若设为false,则只清空内存里的资源缓存,而不清空磁盘里的。
    mWebView.loadUrl("about:blank");// 清空当前加载
    mWebView.removeAllViews();// 清空子 View
    mWebView.destroy();// 生命周期销毁

前进、后退网页

	Webview.canGoBack();//是否可以后退
	Webview.goBack();//后退网页
	Webview.canGoForward();//是否可以前进
	Webview.goForward();//前进网页
	Webview.goBackOrForward(intsteps);//以当前的index为起始点前进或者后退到历史记录中指定的steps,如果steps为负数则为后退,正数则为前进

Back键控制网页后退

如果不做任何的处理,触发到Back的时候会直接退出
拦截Back做到后退效果

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

WebView三个重要的部分

1.WebSettings
作用:对WebView进行配置和管理;
2.WebViewClient
作用:处理各种通知 & 请求事件
3.WebChromeClient
作用:辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。

WebSettings类

//声明WebSettings子类
WebSettings webSettings = webView.getSettings();

//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);
//开启DOM缓存,默认状态下是不支持LocalStorage的
webSettings.setDomStorageEnabled(true);

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

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

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

//缓存
//缓存模式如下:
    //LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
    //LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据。
    //LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
    //LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据
//不使用缓存
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);


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

WebViewClient类

1.shouldOverrideUrlLoading()

//处理WebView到底是本身进行处理,还是跳转手机自带的浏览器
/**
* 1、 默认返回:return super.shouldOverrideUrlLoading(view, url); 这个返回的方法会调用父类方法,也就是跳转至手机浏览器,平时写webview一般都在方法里面写 webView.loadUrl(url);  然后把这个返回值改成下面的false。 
* 2、返回: return true;  webview处理url是根据程序来执行的。 
* 3、返回: return false; webview处理url是在webview内部执行。 
*/
webView.setWebViewClient(new WebViewClient(){
     @Override
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
           view.loadUrl(url);
           return true;
      }
});

在这个地方还有一个坑给大家说明一下:
1.由于兼容性问题,在Android7.0以上系统访问shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
2.Android7.0以下系统访问shouldOverrideUrlLoading(WebView view, String url)

2.onPageStarted()

//开始载入页面时调用此方法,在这里可以设定一个loading的页面,告诉用户程序正在等待网络响应。
webView.setWebViewClient(new WebViewClient(){
     @Override
      public void onPageStarted(WebView view, String url, Bitmap favicon) {
           //设定加载开始的操作
     }
});

3.onPageFinished()

//在页面加载结束时调用。可以关闭loading 条,切换程序动作。
webView.setWebViewClient(new WebViewClient(){
     @Override
     public void onPageFinished(WebView view, String url) {
           //设定加载结束的操作
     }
});

4.onLoadResource()

//在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次,除非本地有当前 url 对应有缓存,否则就会加载。
webView.setWebViewClient(new WebViewClient(){
     @Override
     public boolean onLoadResource(WebView view, String url) {
           //设定加载资源的操作
     }
 });

5.onReceivedError()

//加载页面的服务器出现错误时(如404)调用。
// App里面使用webview控件的时候遇到了诸如404这类的错误的时候,若也显示浏览器里面的那种错误提示页面就显得很丑陋了,那么这个时候我们的app就需要加载一个本地的错误提示页面,即webview如何加载一个本地的页面

//步骤1:写一个html文件(error_handle.html),用于出错时展示给用户看的提示页面
//步骤2:将该html文件放置到代码根目录的assets文件夹下
//步骤3:复写WebViewClient的onRecievedError方法 //该方法传回了错误码,根据错误类型可以进行不同的错误分类处理
webView.setWebViewClient(new WebViewClient(){
     @Override
     public void onReceivedError(WebView view, int errorCode, String description, String failingUrl){
           switch(errorCode) {
               case HttpStatus.SC_NOT_FOUND:
                    view.loadUrl("file:///android_assets/error_handle.html");
                    break;
           }
     }
});

6.onReceivedSslError()

//处理https请求 
//webView默认是不处理https请求的,页面显示空白
webView.setWebViewClient(new WebViewClient() {
     @Override
     public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
          handler.proceed(); //表示等待证书响应
          // handler.cancel(); //表示挂起连接,为默认方式
          // handler.handleMessage(null); //可做其他处理
      }
});

7.shouldInterceptRequest()这是一个很重要的方法

//WebView拦截请求,重定向
/**
* 代码中重写了两个shouldInterceptRequest方法
* 1.shouldInterceptRequest (WebView view, String url);
* 2.shouldInterceptRequest(WebView view, android.webkit.WebResourceRequest request):
* 其中shouldInterceptRequest (WebView view, String url)在API 21过时。
*/
webView.setWebViewClient(new WebViewClient() {
     @Override
     public void shouldInterceptRequest(WebView view, android.webkit.WebResourceRequest request) {
          //WebView中有JS、PNG图片等资源可以截取并更换资源文件
      }
});

WebChromeClient类

1.onProgressChanged()

//获得网页的加载进度
webview.setWebChromeClient(new WebChromeClient(){
     @Override
     public void onProgressChanged(WebView view, int newProgress) {
          // 可以与progressBarView类似的View绑定加载进度
});

2.onReceivedTitle()

//接收web页面的 Title。
/**
* 每个网页的页面都有一个标题,比如www.baidu.com这个页面的标题即“百度一下,你就    知道”,那么如何知道当前webview正在加载的页面的title并进行设置呢?
*/
webview.setWebChromeClient(new WebChromeClient(){
     @Override
      public void onReceivedTitle(WebView view, String title) {
      titleview.setText(title);
 }

WebView和JavaScript的交互

1、使用系统方法 addJavascriptInterface 注入 java 对象来实现。
2、利用 WebViewClient 中 shouldOverrideUrlLoading (WebView view, String url) 接口,拦截操作。这个就是很多公司在用的 scheme 方式,通过制定url协议,双方各自解析,使用iframe来调用native代码,实现互通。
3、利用 WebChromeClient 中的 onJsAlert、onJsConfirm、onJsPrompt 提示接口,同样也是拦截操作。

示例代码:

//开启Js可用
mWebView.getSettings().setJavaScriptEnabled(true);

// 创建要注入的 Java 类
public class NativeInterface {

    private Context mContext;

    public NativeInterface(Context context) {
        mContext = context;
    }

    @JavascriptInterface
    public void hello() {
        Toast.makeText(mContext, "hello", Toast.LENGTH_SHORT).show();
    }

    @JavascriptInterface
    public void hello(String params) {
        Toast.makeText(mContext, params, Toast.LENGTH_SHORT).show();
    }

    @JavascriptInterface
    public String getAndroid() {
        Toast.makeText(mContext, "getAndroid", Toast.LENGTH_SHORT).show();
        return "Android data";
    }
}

// WebView 注入即可
mWebView.addJavascriptInterface(new NativeInterface(this), "AndroidNative");

//Js编写
<script>
    function callHello(){
        AndroidNative.hello();
    }

    function callHello1(){
        AndroidNative.hello('hello Android');
    }

    function callAndroid(){
        var temp = AndroidNative.getAndroid();
        console.log(temp);
        alert(temp);
    }  

</script>

WebView内存泄漏问题

//mWebView=new WebView(this);
mWebView=new WebView(getApplicationContext());
LinearLayout linearLayout  = findViewById(R.id.xxx);
linearLayout.addView(mWebView);

// onDestroy()方法中调用:
@Override
protected void onDestroy() {
    if( mWebView!=null) {
       mWebView.setVisibility(View.GONE);
       mWebView.removeAllViews();
       mWebView.destroy();
    }
    super.onDestroy();
}

感谢大家能够看完本篇文章,如果有说的不正确的地方或者有疑问,可以互相交流。

 类似资料: