Android WebView

WebView

WebView本身是一个View,以WebKit为引擎核心,来实现一些基本的浏览器功能。

基本使用

1
2
3
4
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
1
2
3
4
5
6
7
8
// 显示外部网页
// 向百度的服务器发送了一条 HTTP 请求,服务器分析出想要访问的是百度的首页,于是把该网页的 HTML 代码进行返回,然后 WebView 再调用手机浏览器的内核对返回的 HTML 代码进行解析,最终将页面展示出来。
webView.loadUrl("https://www.baidu.com/");
// 加载本地资源
webView.loadUrl("file:///android_asset/index.html");
// 显示html语句
String htmlStr = "<html><body>This is html</body></html>";
webView.loadData(htmlStr,"text/html",null);

注意

  • WebView本身是一个View,需要findViewById()。
  • 权限;<uses-permission android:name="android.permission.INTERNET" />
  • 当其他程序接收到意图会启动,使用webView.setWebViewClient(new WebViewClient());来拦截。
  • 重写onKeyDown()方法,实现回退效果;
1
2
3
4
5
6
7
8
9
10
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK){
if (webView.canGoBack()){
webView.goBack();
return true;
}
}
return super.onKeyDown(keyCode, event);
}

WebSettings

常用设置

设置一些浏览器的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    WebSettings webSettings=webView.getSettings();
// 是否允许在WebView中访问内容Url,默认为true。
webSettings.setAllowContentAccess(boolean allow);
// 是否允许访问文件,默认为true。
webSettings.setAllowFileAccess(boolean allow);
// 应用缓存API是否可用,默认为false。
webSettings.setAppCacheEnabled(boolean flag);
// 应用缓存路径,只执行一次。一般与setAppCacheEnabled结合使用。
webSettings.setAppCachePath(String path);
// 是否允许执行JS脚本,默认为false。
// Kotlin 写法:webView.settings.javaScriptEnabled = true
webSettings.setJavaScriptEnabled(boolean flag);
// 是否允许屏幕缩放或手势缩放,默认为true。
webSettings.setSupportZoom(boolean support);
// 缩放比例,默认100%。
webSettings.setTextZoom(int textZoom);

示例

网页缩放
1
2
3
4
5
6
7
WebSettings webSettings=webView.getSettings();
// 允许缩放
webSettings.setSupportZoom(true);
// 设置出现缩放工具
webSettings.setBuiltInZoomControls(true);
// 是否显示缩放按钮
webSettings.setDisplayZoomControls(true);

WebViewClient

帮助WebView处理各种通知,请求事件。

webView.webViewClient = WebViewClient() 的作用是,当需要从一个网页跳转到另一个网页时,希望目标网页仍然在当前 WebView 中显示,而不是打开系统浏览器。

常用方法

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
// Kotlin 写法
webView.webViewClient = WebViewClient()
// Java 写法
webView.setWebViewClient(new WebViewClient(){
@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
super.doUpdateVisitedHistory(view, url, isReload);
// 当更新历史纪录时会调用
}

@Override
public void onFormResubmission(WebView view, Message dontResend, Message resend) {
super.onFormResubmission(view, dontResend, resend);
// 应用重新请求网页时
}

@Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
// 应用加载资源时,每次加载都会调用。
}

@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
// 载入页面时,通常设置像Load条。
}

@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
// 页面加载结束时,通常关闭Load条,进度条等。
}

@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
// 报告错误信息
}

@Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
super.onReceivedHttpAuthRequest(view, handler, host, realm);
// 网页获取授权信息请求时
}

@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
super.onReceivedSslError(view, handler, error);
// 处理一些Http请求
}

@Override
public void onScaleChanged(WebView view, float oldScale, float newScale) {
super.onScaleChanged(view, oldScale, newScale);
// WebView发生改变时
}

@Override
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
super.onUnhandledKeyEvent(view, event);
// 事件未被加载时
}

@Override
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
return super.shouldOverrideKeyEvent(view, event);
// 在浏览器中处理一些按键事件
}

@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return super.shouldOverrideUrlLoading(view, request);
// 点击请求时,链接才会被调用,true代表还是本WebView。
}
});

示例

监听页面的加载与完成
1
2
3
4
5
6
7
8
9
10
11
12
13
webView.setWebViewClient(new WebViewClient(){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
// 正在载入页面,业务逻辑代码
}

@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
// 页面加载完成,业务逻辑代码。
}
});

WebChromeClient

帮助WebView处理JS的对话框,网站图标,网站title,加载进度等。

常用方法

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
webView.setWebChromeClient(new WebChromeClient(){
@Override
public Bitmap getDefaultVideoPoster() {
return super.getDefaultVideoPoster();
// 获取预览图
}

@Override
public View getVideoLoadingProgressView() {
return super.getVideoLoadingProgressView();
// 数据缓冲时显示的视图
}

@Override
public void getVisitedHistory(ValueCallback<String[]> callback) {
super.getVisitedHistory(callback);
// 获取历史项目列表,用于链接着色
}

@Override
public void onCloseWindow(WebView window) {
super.onCloseWindow(window);
// 通知主机WebView关闭了
// 多用于点击链接弹出新窗口
}

@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
return super.onCreateWindow(view, isDialog, isUserGesture, resultMsg);
// 通知主机创建一个新窗口
// 多用于点击链接弹出新窗口
}

@Override
public void onHideCustomView() {
super.onHideCustomView();
// 应用退出全屏,多用于退出全屏模式
}

@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
super.onShowCustomView(view, callback);
// 进入全屏模式
}

@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
// 通告应用程序显示JS警告框
}

@Override
public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
return super.onJsBeforeUnload(view, url, message, result);
// 通告应用程序显示对话框,是否离开当前界面。
}

@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
// 确认对话框
}

@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
return super.onJsPrompt(view, url, message, defaultValue, result);
// 提示对话框
}

@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
// 加载进度
}

@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
// 新图标出现时会调用
}

@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
// title变化时
}

@Override
public void onRequestFocus(WebView view) {
super.onRequestFocus(view);
// 请求焦点,一般由后台到前台时会触发。
}
});

示例

显示网页加载进度,并获取title
1
2
3
4
5
6
7
8
9
10
11
12
13
webView.setWebChromeClient(new WebChromeClient(){
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
Log.e("TAG","newProgress-"+newProgress);
}

@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
Log.e("TAG","title-"+title);
}
});

其它

1
2
3
4
5
6
7
8
9
10
11
// WebView 组件在 Java 中 需要 findViewById,在 Kotlin 中因为插件可直接使用。
// 最简单的方式打开一个网页,但一直是空白页,犯了个智障错误,最后才发现是因为:val wvBrowser = WebView(this)
// 我的想法是:通过 findViewById 是使用 XML 中定义的组件,而 val wvBrowser = WebView(this) 是创建了一个 WebView 的实例。
// 对于后者,那动态创建的组件,可以动态的去添加。
wvBrowser.webViewClient = WebViewClient() // 使用 XML 中的
wvBrowser.loadUrl("https://baidu.com")

val wv = WebView(this) // 使用动态代码的方式
wv.webViewClient = WebViewClient()
wv.loadUrl("https://jianghouren.com")
frameLayout.addView(wv) // XML 中定义了一个布局,动态添加 WebView 进去

使用的是 AS 的模拟器,网页加载不出来,webView 报 net::ERR_NAME_NOT_RESOLVER。
无网络或本地没有缓存等情况下才会出现这个,一般来讲,是因为模拟器默认的 DNS 和电脑的不一致。

指定 DNS 来启动模拟器:(我是用来解决模拟器无网络问题,模拟器默认的 DNS 和电脑的值不一致。)

cd 到指定目录:cd /Users/jianghouren/Library/Android/sdk/emulator

输入命令:./emulator -avd Pixel_API_29 -dns-server 192.168.1.1(可通过网络偏好设置的高级设置里查看 DNS 值,可通过用户名/.android/avd 查看模拟器名称)