前言
- 现在很多
App
里都内置了 Web 网页(Hybrid App
),比如说很多电商平台,淘宝、京东、聚划算等等, - 那么这种该如何实现呢?其实这是
Android
里一个叫 WebView
组件实现 - 今天,我将献上一份全面介绍
WebView
的常见用法。
转载自 https://www.jianshu.com/p/3c94ae673e2a
目录

1. 简介
WebView
是一个基于 webkit
引擎、展现 web
页面的控件。
Android 的 Webview 在低版本和高版本采用了不同的 webkit 版本内核,4.4 后直接使用了 Chrome。
2. 作用
- 显示和渲染 Web 页面
- 直接使用 html 文件(网络上或本地 assets 中)作布局
- 可和 JavaScript 交互调用
WebView 控件功能强大,除了具有一般 View 的属性和设置外,还可以对 url 请求、页面加载、渲染、页面交互进行强大的处理。
3. 使用介绍
3.1 Webview 常用方法
3.1.1 加载 URL
加载方式根据资源分为三种
1 2 3 4 5 6 7 8 9 10 11 12 13
| webView.loadUrl("http://www.google.com/"); webView.loadUrl("file:///android_asset/test.html"); webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html"); WebView.loadData(String data, String mimeType, String encoding)
|
3.1.2 Webview 的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| webView.onResume() ;
webView.onPause();
webView.pauseTimers()
webView.resumeTimers();
rootLayout.removeView(webView); webView.destroy();
|
3.1.3 关于前进 / 后退网页
1 2 3 4 5 6 7 8 9 10 11 12 13
| Webview.canGoBack()
Webview.goBack()
Webview.canGoForward()
Webview.goForward()
Webview.goBackOrForward(intsteps)
|
常见用法:Back 键控制网页后退
- 问题:在不做任何处理前提下 ,浏览网页时点击系统的 “Back” 键,整个 Browser 会调用 finish () 而结束自身
- 目标:点击返回后,是网页回退而不是推出浏览器
- 解决方案:在当前 Activity 中处理并消费掉该 Back 事件
1 2 3 4 5 6 7
| public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KEYCODE_BACK) && mWebView.canGoBack()) { mWebView.goBack(); return true; } return super.onKeyDown(keyCode, event); }
|
3.1.4 清除缓存数据
1 2 3 4 5 6 7 8 9 10
|
Webview.clearCache(true);
Webview.clearHistory();
Webview.clearFormData();
|
3.2 常用工具类
3.2.1 WebSettings 类
- 作用:对 WebView 进行配置和管理
- 配置步骤 & 常见方法:
配置步骤 1:添加访问网络权限(AndroidManifest.xml)
1
| <uses-permission android:name="android.permission.INTERNET"/>
|
配置步骤 2:生成一个 WebView 组件(有两种方式)
1 2 3 4 5
| WebView webView = new WebView(this)
WebView webview = (WebView) findViewById(R.id.webView1);
|
配置步骤 3:进行配置 - 利用 WebSettings 子类(常见方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setPluginsEnabled(true);
webSettings.setUseWideViewPort(true); webSettings.setLoadWithOverviewMode(true);
webSettings.setSupportZoom(true); webSettings.setBuiltInZoomControls(true); webSettings.setDisplayZoomControls(false);
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); webSettings.setAllowFileAccess(true); webSettings.setJavaScriptCanOpenWindowsAutomatically(true); webSettings.setLoadsImagesAutomatically(true); webSettings.setDefaultTextEncodingName("utf-8");
|
常见用法:设置 WebView 缓存
- 当加载 html 页面时,WebView 会在 /data/data/ 包名目录下生成 database 与 cache 两个文件夹
- 请求的 URL 记录保存在 WebViewCache.db,而 URL 的内容是保存在 WebViewCache 文件夹下
- 是否启用缓存:
1 2 3 4 5 6 7 8 9 10
| WebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
WebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
|
1 2 3 4 5 6 7 8 9 10 11 12
| if (NetStatusUtil.isConnected(getApplicationContext())) { webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); } else { webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); }
webSettings.setDomStorageEnabled(true); webSettings.setDatabaseEnabled(true); webSettings.setAppCacheEnabled(true);
String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME; webSettings.setAppCachePath(cacheDirPath);
|
注意: 每个 Application 只调用一次 WebSettings.setAppCachePath (),WebSettings.setAppCacheMaxSize ()
3.2.2 WebViewClient 类
常见方法 1:shouldOverrideUrlLoading ()
- 作用:打开网页时不调用系统浏览器, 而是在本 WebView 中显示;在网页上的所有加载都经过这个方法,这个函数我们可以做很多操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Webview webview = (WebView) findViewById(R.id.webView1);
webView.loadUrl("http://www.google.com/");
webView.loadUrl("file:///android_asset/test.html");
webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
webView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } });
|
常见方法 2:onPageStarted ()
- 作用:开始载入页面调用的,我们可以设定一个 loading 的页面,告诉用户程序在等待网络响应。
1 2 3 4 5 6
| webView.setWebViewClient(new WebViewClient(){ @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { } });
|
常见方法 3:onPageFinished ()
- 作用:在页面加载结束时调用。我们可以关闭 loading 条,切换程序动作。
1 2 3 4 5 6
| webView.setWebViewClient(new WebViewClient(){ @Override public void onPageFinished(WebView view, String url) { } });
|
常见方法 4:onLoadResource ()
- 作用:在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
1 2 3 4 5 6
| webView.setWebViewClient(new WebViewClient(){ @Override public boolean onLoadResource(WebView view, String url) { } });
|
常见方法 5:onReceivedError()
- 作用:加载页面的服务器出现错误时(如 404)调用。
App 里面使用 webview 控件的时候遇到了诸如 404 这类的错误的时候,若也显示浏览器里面的那种错误提示页面就显得很丑陋了,那么这个时候我们的 app 就需要加载一个本地的错误提示页面,即 webview 如何加载一个本地的页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
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 ()
webView 默认是不处理 https 请求的,页面显示空白,需要进行如下设置:
1 2 3 4 5 6 7 8 9 10 11 12 13
| webView.setWebViewClient(new WebViewClient() { @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { handler.proceed(); } });
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); }
|
3.2.3 WebChromeClient 类
- 作用:辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。
- 常见使用:
常见方法 1: onProgressChanged()
1 2 3 4 5 6 7 8 9 10
| webview.setWebChromeClient(new WebChromeClient(){
@Override public void onProgressChanged(WebView view, int newProgress) { if (newProgress < 100) { String progress = newProgress + "%"; progress.setText(progress); } else { } });
|
常见方法 2: onReceivedTitle()
每个网页的页面都有一个标题,比如 www.baidu.com这个页面的标题即 “百度一下,你就知道”,那么如何知道当前 webview 正在加载的页面的 title 并进行设置呢?
1 2 3 4 5 6
| webview.setWebChromeClient(new WebChromeClient(){
@Override public void onReceivedTitle(WebView view, String title) { titleview.setText(title); }
|
常见方法 3: onJsAlert()
一般情况下在 Android 中为 Toast,在文本里面加入 \n 就可以换行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| webview.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { new AlertDialog.Builder(MainActivity.this) .setTitle("JsAlert") .setMessage(message) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }) .setCancelable(false) .show(); return true; }
|
常见方法 4: onJsConfirm()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| webview.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { new AlertDialog.Builder(MainActivity.this) .setTitle("JsConfirm") .setMessage(message) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.cancel(); } }) .setCancelable(false) .show();
return true; }
|
常见方法 5: onJsPrompt()
点击确认返回输入框中的值,点击取消返回 null。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| webview.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) { final EditText et = new EditText(MainActivity.this); et.setText(defaultValue); new AlertDialog.Builder(MainActivity.this) .setTitle(message) .setView(et) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(et.getText().toString()); } }) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.cancel(); } }) .setCancelable(false) .show();
return true; }
|
3.3 Webview 与 JavaScript 的交互
http://blog.tbox.fun/2018/ce16bff8.html
3.4 注意事项:避免内存泄露
3.4.1 不在 xml 中定义 Webview ,而是在需要的时候在 Activity 中创建,并且 Context 使用 getApplicationgContext ()
1 2 3 4
| LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mWebView = new WebView(getApplicationContext()); mWebView.setLayoutParams(params); mLayout.addView(mWebView);
|
3.4.2 在 Activity 销毁( WebView )的时候,先让 WebView 加载 null 内容,然后移除 WebView,再销毁 WebView,最后置空。
1 2 3 4 5 6 7 8 9 10 11 12
| @Override protected void onDestroy() { if (mWebView != null) { mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null); mWebView.clearHistory();
((ViewGroup) mWebView.getParent()).removeView(mWebView); mWebView.destroy(); mWebView = null; } super.onDestroy(); }
|
4. 实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
| 4. 实例 目标:实现显示“www.baidu.com”、获取其标题、提示加载开始 & 结束和获取加载进度 具体实现: 步骤1:添加访问网络权限
这是前提!这是前提!这是前提!
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/> 步骤2:主布局 activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.carson_ho.webview_demo.MainActivity">
<!-- 获取网站的标题--> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=""/>
<!--开始加载提示--> <TextView android:id="@+id/text_beginLoading" android:layout_below="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=""/>
<!--获取加载进度--> <TextView android:layout_below="@+id/text_beginLoading" android:id="@+id/text_Loading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=""/>
<!--结束加载提示--> <TextView android:layout_below="@+id/text_Loading" android:id="@+id/text_endLoading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=""/> <!--显示网页区域--> <WebView android:id="@+id/webView1" android:layout_below="@+id/text_endLoading" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginTop="10dp" /> </RelativeLayout>
步骤3:根据需要实现的功能从而使用相应的子类及其方法(注释很清楚了) MainActivity.java
package com.example.carson_ho.webview_demo;
import android.graphics.Bitmap; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.KeyEvent; import android.view.ViewGroup; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.TextView;
public class MainActivity extends AppCompatActivity { WebView mWebview; WebSettings mWebSettings; TextView beginLoading,endLoading,loading,mtitle;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
mWebview = (WebView) findViewById(R.id.webView1); beginLoading = (TextView) findViewById(R.id.text_beginLoading); endLoading = (TextView) findViewById(R.id.text_endLoading); loading = (TextView) findViewById(R.id.text_Loading); mtitle = (TextView) findViewById(R.id.title);
mWebSettings = mWebview.getSettings();
mWebview.loadUrl("http://www.baidu.com/");
mWebview.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } });
mWebview.setWebChromeClient(new WebChromeClient() {
@Override public void onReceivedTitle(WebView view, String title) { System.out.println("标题在这里"); mtitle.setText(title); }
@Override public void onProgressChanged(WebView view, int newProgress) { if (newProgress < 100) { String progress = newProgress + "%"; loading.setText(progress); } else if (newProgress == 100) { String progress = newProgress + "%"; loading.setText(progress); } } });
mWebview.setWebViewClient(new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { System.out.println("开始加载了"); beginLoading.setText("开始加载了");
}
@Override public void onPageFinished(WebView view, String url) { endLoading.setText("结束加载了");
} }); }
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && mWebview.canGoBack()) { mWebview.goBack(); return true; }
return super.onKeyDown(keyCode, event); }
@Override protected void onDestroy() { if (mWebview != null) { mWebview.loadDataWithBaseURL(null, "", "text/html", "utf-8", null); mWebview.clearHistory();
((ViewGroup) mWebview.getParent()).removeView(mWebview); mWebview.destroy(); mWebview = null; } super.onDestroy(); } }
|
5 总结
