快速入门

WebView 是什么?

WebView是 Android 的一个极其强大但也极其复杂的组件,它本质上是用来展示网页内容的 View,相当于在 App 里嵌入了一个精简版的 Google Chrome 浏览器。主要用来在 App 内显示网页或运行 Web 应用。它基于 Chromium 渲染引擎,和 Chrome for Android 渲染一致性等同。

  • Q1: WebView 和 WebViewCompat 什么区别?

A:WebView是 Android 系统提供的核心控件,而WebViewCompat是 AndroidX 库提供的兼容性工具类。

由于 Android 系统碎片化严重,很多新特性(如深色模式支持、安全检查 Safe Browsing 等)是在较新的 Android 版本中才加入的。如果直接调用WebView的新 API,在旧手机上运行会直接导致 Crash(崩溃)。它类似一个转换头,会去检测手机里那个独立的 WebView 内核 App 是否支持某个功能。Android 官方也建议尽可能通过WebViewCompatandroidx.webkit:webkit库来操作 WebView。

  • Q2: android.webkit.WebView 和WebView 内核 (Chromium) 什么区别?

A: android.webkit.WebView是 Android 系统提供给开发者的标准接口,暴露方法给开发者调用,存在于 Android 系统固件(Framework)中。

WebView 内核 (Chromium) 作为一个独立的 APK 存在(Android System WebView),通过 Google Play 商店独立更新。

WebView 发展历程

  • Android 4.4 之前:使用 WebKit 内核
  • Android 4.4 及以上:直接使用 Chrome 内核(基于 Chromium)

布局和基础 API

AndroidManifest.xml中添加网络权限

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

布局文件中添加 WebView

<!-- res/layout/activity_main.xml -->
<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Activity 中初始化 WebView

public class MainActivity extends AppCompatActivity {
    private WebView myWebView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 获取 WebView 实例
        myWebView = (WebView) findViewById(R.id.webview);
        // 启用 JavaScript
        WebSettings webSettings = myWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        // 启用缩放
        webSettings.setSupportZoom(true);
        webSettings.setBuiltInZoomControls(true);
        webSettings.setDisplayZoomControls(false);
        // 设置 WebViewClient 处理页面导航
        myWebView.setWebViewClient(new WebViewClient());
        // 加载网页
        myWebView.loadUrl("https://www.example.com");
    }
}

基础 API

// 加载网络页面
myWebView.loadUrl("https://www.example.com");
 
// 加载本地 HTML 文件
myWebView.loadUrl("file:///android_asset/index.html");
 
// 加载字符串内容
String htmlContent = "<html><body><h1>Hello WebView</h1></body></html>";
myWebView.loadData(htmlContent, "text/html", "UTF-8");

QA 常见问题

Q:loadData 和 loadUrl什么区别?

A:loadData()是直接加载 HTML 字符串,loadUrl()是加载URL对应的网页。二者适用于不同的场景,比如:

// 场景1:显示错误页面
public void showErrorPage(String message) {
    // ❌ loadUrl方式不方便
    // webView.loadUrl("file:///android_asset/error.html?msg=" + message);
    // 需要额外传递参数,复杂
    
    // ✅ loadData方式更合适
    String errorHtml = """
        <html>
        <body style='padding:20px;'>
            <h2 style='color:red;'>出错了</h2>
            <p>%s</p>
            <button onclick='window.Android.retry()'>重试</button>
        </body>
        </html>
        """.formatted(escapeHtml(message));
    webView.loadData(errorHtml, "text/html", "UTF-8");
}
 
// 场景2:加载固定帮助文档
// ✅ loadUrl方式更简单
webView.loadUrl("file:///android_asset/help/user_guide.html");

WebView 配置与高级设置

WebView 设置详解

WebSettings webSettings = myWebView.getSettings();
 
// 基础设置
webSettings.setJavaScriptEnabled(true); // 启用 JavaScript
webSettings.setDomStorageEnabled(true); // 启用 DOM 存储
webSettings.setAppCacheEnabled(true); // 启用应用缓存
webSettings.setDatabaseEnabled(true); // 启用数据库
webSettings.setGeolocationEnabled(true); // 启用地理位置
 
// 缓存设置
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); // 默认缓存模式
// LOAD_DEFAULT: 使用默认缓存策略
// LOAD_CACHE_ELSE_NETWORK: 先使用缓存,没有缓存则从网络加载
// LOAD_NO_CACHE: 不使用缓存,直接从网络加载
// LOAD_CACHE_NORMAL: 优先使用缓存,但可以使用网络更新缓存
 
// 自定义缓存大小
int cacheSize = 10 * 1024 * 1024; // 10MB
myWebView.getSettings().setAppCacheMaxSize(cacheSize);
myWebView.getSettings().setAppCachePath(getCacheDir().getAbsolutePath());
 
// 支持多窗口
webSettings.setSupportMultipleWindows(true);
 
// 自定义 User-Agent
webSettings.setUserAgentString("MyApp/1.0");
 
// 允许访问文件
webSettings.setAllowFileAccess(true);
webSettings.setAllowContentAccess(true);

User-Agent

User-Agent是 HTTP 请求头的一部分,用于让客户端向服务器标识其自身的相关信息。这个信息主要包括客户端的应用程序类型、操作系统、软件版本、浏览器类型和版本等。服务器可以利用这些信息来决定向客户端提供怎样的内容或服务,从而优化用户体验。在最简单的情况下,User-Agent就是一个字符串,描述了请求的来源。

组成结构

一个典型的 User-Agent 字符串通常由以下几部分组成:

  1. 应用名称和版本:
    指定客户端的类型和版本号。例如:Mozilla/5.0
  2. 操作系统信息:
    描述客户端运行的操作系统及版本。例如:Windows NT 10.0; Win64; x64
  3. 渲染引擎信息:
    提供浏览器使用的渲染引擎(如WebKitBlink等)。例如:AppleWebKit/537.36 (KHTML, like Gecko)
  4. 浏览器名称和版本:
    提供浏览器的名称和版本号。例如:Chrome/117.0.0.0
  5. 其他信息:
    可能包含一些扩展信息(如设备类型、环境等)。例如:Safari/537.36
常见浏览器的 User-Agent 示例:
  1. Chrome 浏览器 (Windows)
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36
  1. Chrome 浏览器 (Android 手机)
Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Mobile Safari/537.36
  1. 微信内置浏览器
Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.15(0x18000f23) NetType/WIFI Language/zh_CN
作用和用途
  1. 内容定制:
    根据 User-Agent 提供不同的网页内容。例如:为移动设备提供精简的页面、为桌面设备提供完整的页面。
  2. 兼容性支持:
    网站可以根据 User-Agent 提供兼容的功能。例如:如果识别到是老旧浏览器,可以提供兼容的版本;如果识别到是现代浏览器,可以启用最新的特性。
  3. 统计分析:
    网站可以通过分析 User-Agent 来统计用户使用的设备、操作系统和浏览器类型。
  4. 防止恶意请求:
    通过检测 User-Agent,网站可以屏蔽掉一些自动化脚本或爬虫程序。
userAgentString

在 Android 中,WebView默认会使用系统自带的 User-Agent。也可以通过以下方式自定义:

webView.settings.userAgentString = "YourCustomUserAgent"

如果想追加自定义信息而保留默认 User-Agent,可以这样获取并修改:

val defaultUserAgent = webView.settings.userAgentString
webView.settings.userAgentString = "$defaultUserAgent MyApp/1.0"

WebViewClient

WebViewClient 用于控制**网页加载行为,**处理页面导航和加载事件,比如:

  • 拦截链接点击(防止跳转到外部浏览器)
  • 监听页面开始 / 结束 / 错误
  • 自定义处理特定 URL(如myapp://协议)

如果不设置 WebViewClient 会使用默认的 Client 可能会导致某些资源无法加载或者某些内容不渲染或渲染不完整

myWebView.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
        // 页面开始加载
        Log.d("WebView", "Page started loading: " + url);
        // 可以在这里显示加载进度条
    }
 
    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        // 页面加载完成
        Log.d("WebView", "Page finished loading: " + url);
        // 可以在这里隐藏加载进度条
    }
 
    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        super.onReceivedError(view, request, error);
        // 页面加载错误
        Log.e("WebView", "Error loading page: " + error.getDescription());
        // 可以在这里显示错误页面
    }
 
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        // 处理链接点击
        String url = request.getUrl().toString();
        if (url.startsWith("http://") || url.startsWith("https://")) {
            return false; // 在 WebView 中加载
        } else {
            // 处理其他协议,如 tel:、mailto:
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(intent);
            return true; // 不在 WebView 中加载
        }
    }
});

shouldOverrideUrlLoading

shouldOverrideUrlLoading是一个常用的方法,用于拦截 WebView 内部加载的 URL 请求,并决定是否在 WebView 中加载此 URL,或者将其交由外部应用处理。可以通过重写这个方法来实现一些自定义的行为,比如拦截某些 URL、打开另一个 Activity 或调起 DeepLink。

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    // Custom logic to handle URL loading
}

参数

  • view:当前的WebView实例
  • url:即将加载的 URL。

返回值

  • true:表示开发者处理了 URL,WebView 不需要再进行加载
  • false:表示 WebView 应该继续加载这个 URL

典型用法

  1. **打开外部浏览器:**当检测到某些特定的 URL(比如某些外部链接或者某些协议)时,可以选择打开外部浏览器:
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.startsWith("http://") || url.startsWith("https://")) {
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        view.getContext().startActivity(intent);
        return true;
    }
    return false;
}
  1. **内部处理 URL:**开发者可以根据业务需要在 WebView 内部处理某些 URL,而不是让 WebView 加载:
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.contains("baiduboxapp://")) {
        // Handle the URL internally
        return true;
    }
    return false;
}
  1. **拦截不需要的 URL:**可以通过这个方法拦截一些不需要的链接,防止加载:
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.contains("baidu.com")) {
        // Block the URL
        return true;
    }
    return false;
}

注意事项

shouldOverrideUrlLoading是在 UI 线程中执行的,应该避免在shouldOverrideUrlLoading里做耗时操作,造成阻塞 UI。

shouldInterceptRequest()

拦截 WebView 发出的所有资源请求(包括 JS、CSS、图片、XHR、fetch 等)

WebChromeClient

WebChromeClient 用于处理浏览器相关的事件,比如 WebView 的 UI 相关事件 和 **JavaScript 交互,**比如:

  • 网页标题变化
  • 加载进度条
  • JavaScript 弹窗(alert, confirm, prompt
  • 全屏视频播放(如 HTML5 <video>
myWebView.setWebChromeClient(new WebChromeClient() {
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        super.onProgressChanged(view, newProgress);
        // 更新加载进度
        if (newProgress == 100) {
            // 加载完成
        } else {
            // 显示进度
        }
    }
 
    @Override
    public void onReceivedTitle(WebView view, String title) {
        super.onReceivedTitle(view, title);
        // 页面标题变化
        setTitle(title);
    }
 
    @Override
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
        // 自定义弹窗样式,处理 JavaScript 警告
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
        builder.setTitle("Alert")
               .setMessage(message)
               .setPositiveButton("OK", (dialog, which) -> result.confirm())
               .create()
               .show();
        return true;
    }
});

WebViewRenderProcessClient

从 Android 8.0(Oreo)开始,WebView 默认在独立的沙盒进程中渲染网页(称为 “渲染进程”),与 App 主进程分离。这样即使网页崩溃,也不会导致整个 App 闪退。

但在 Android 13(API 33) 之前,只能通过onRenderProcessGone()(在WebViewClient中)知道“进程已经挂了”,无法提前预警或获取详细信息。而WebViewRenderProcessClient提供了更细粒度的控制,更好地监控和处理 WebView 的稳定性问题

官方定义:
WebViewRenderProcessClient是一个回调接口,用于监听 WebView 渲染进程(Render Process)的生命周期事件,比如:

  • 渲染进程是否无响应(ANR)
  • 渲染进程是否崩溃(Crash)
功能旧方式(API 26+)新方式(API 33+)
检测崩溃onRenderProcessGone()✅ 更早检测 + 原因分析
检测无响应(ANR)❌ 不支持✅ 支持!
多 WebView 管理困难可绑定到特定 WebView
示例:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    WebViewRenderProcessClient renderProcessClient =
        new WebViewRenderProcessClient() {
            @Override
            public void onRenderProcessUnresponsive(
                WebView webView,
                WebViewRenderProcess renderer
            ) {
                // 当渲染进程变得无响应(例如 JS 死循环、长时间阻塞)
                Log.w("WebView", "渲染进程无响应!");
 
                // 可选:弹出提示让用户重试
                new AlertDialog.Builder(this)
                    .setTitle("页面无响应")
                    .setMessage("网页已停止响应,是否重新加载?")
                    .setPositiveButton("重试", (d, w) -> webView.reload())
                    .setNegativeButton("关闭", (d, w) -> finish())
                    .show();
 
                // 或者直接终止该渲染进程(谨慎!)
                // renderer.terminate();
            }
 
            @Override
            public void onRenderProcessResponsive(
                WebView webView,
                WebViewRenderProcess renderer
            ) {
                 // 当渲染进程已终止(崩溃或被系统杀死)
                Log.i("WebView", "渲染进程已恢复响应");
                // 可隐藏 loading 或提示
            }
        };
 
    // 将 client 绑定到 WebView
    webView.setWebViewRenderProcessClient(renderProcessClient);
}
  • onRenderProcessUnresponsive(WebView view, WebViewRenderProcess renderer)当 WebView 的渲染进程卡住(无响应)时调用。
  • onRenderProcessResponsive(WebView view, WebViewRenderProcess renderer)当之前卡住的渲染进程恢复正常时调用。

这两个方法是成对出现的:

  • onRenderProcessUnresponsive
  • 如果恢复onRenderProcessResponsive
  • 如果崩溃,直接结束,可能不会回调 responsive

官方文档:Android 官方文档

void onRenderProcessUnresponsive(WebView view, WebViewRenderProcess renderer)

Called when the given renderer is no longer responsive.

void onRenderProcessResponsive(WebView view, WebViewRenderProcess renderer)

Called when the given renderer becomes responsive again after being unresponsive.

与旧方法onRenderProcessGone的区别

特性onRenderProcessGone
(API 26+)
WebViewRenderProcessClient
(API 33+)
触发时机进程已经崩溃进程无响应(ANR)或恢复
能否干预❌ 只能事后处理✅ 可选择 terminate()
或等待恢复
是否支持 ANR 检测
精确性较低更高(可绑定到具体 WebView)

即使用了WebViewRenderProcessClient,也建议保留onRenderProcessGone作为兜底:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
        // 兜底处理:进程彻底挂了
        return true;
    }
});

总结

类名作用最低 API
WebViewRenderProcessClient监听 WebView 渲染进程 无响应(ANR)和恢复API 33(Android 13)
onRenderProcessGone监听渲染进程 崩溃API 26(Android 8.0)

适用场景

  • App 重度依赖 WebView(如混合开发、H5 应用)
  • 需要提升稳定性,避免用户遇到“白屏卡死”
  • 想在 Android 13+ 设备上提供更好的错误恢复体验

addJavascriptInterfacepostWebMessageevaluateJavascript的用法与风险。重点读安全指南。Android Developers

Android 调用 JavaScript

// 通过 evaluateJavascript 执行 JavaScript
myWebView.evaluateJavascript("javascript:alert('Hello from Android')", null);

4.2 JavaScript 调用 Android

// 注册 Android 对象供 JavaScript 调用
myWebView.addJavascriptInterface(new JavaScriptInterface(), "Android");
 
// 定义接口类
public class JavaScriptInterface {
    @JavascriptInterface
    public void showToast(String message) {
        Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
    }
}
 
// 在 JavaScript 中调用
// Android.showToast("Hello from JavaScript");
958a230ff68ec898bda7c3fcb6c3e076.svg 75e316ebf19d87160a5ef4eaea56c200.svg

f1b488829cb888866c44f9b6d5d33744.svg ## 进阶特性 文件上传、表单权限(地理位置/摄像头)、Cookie 管理、缓存/离线策略、混合应用架构(桥接模式)。 ## 调试与性能优化 缓存机制

WebView.setWebContentsDebuggingEnabled(true) + chrome://inspect 调试 DOM/Network/Console。Chrome for Developers

安全最佳实践

模拟不可信内容注入、验证 addJavascriptInterface 的安全边界、启用 Safe Browsing(可用 AndroidX / WebView 提供的功能)。

主子框架模型 isForMainFrame

更新: 2026-04-11 17:57:16
原文: https://www.yuque.com/dongpozhouzi-mshe3/zhm85g/aew5rfhe5odgmqz9


相关笔记

此文件夹下有1条笔记。