Android 官方开始拥抱 WebView

前言

如果你是一名 Android 开发者,那么你大概率经历过这样一个时代:WebView 经常被看成"套壳""H5 页面""临时方案",甚至只要一个 App 里用了大量 WebView,很多人就会下意识觉得它"不够原生"。

老实说,淘宝 App 的糟糕使用体验,我一直觉得就是 Web 没有优化好导致的。

这次 Google I/O 上,官方明确表达了:Build native Android experiences for web apps using WebView

当然,它的主旨并不是"如何简单地把网页塞进 App 里"。它真正讨论的是:当你已经拥有一个成熟的 Web App,如何利用 Android WebView,把它逐步改造成一个更接近原生体验的 Android 应用。

换句话说,这不是一条"WebView 套壳教程",而是一条"如何让 Web App 拥有 Android 原生能力"的工程路线。

WebView 的问题

很多 Android 开发者对 WebView 的第一印象,通常停留在:

kotlin 复制代码
webView.loadUrl("https://example.com")

但这只是 WebView 最基础的能力。真正难的地方,不是把网页显示出来,而是让这个网页在 Android App 里"像一个真正的 App"。

一个普通网页放进 WebView 之后,马上会遇到很多体验断层,例如:

  • 文件上传是不是能自然调用系统照片选择器?
  • 网页触发下载时,是否能交给 Android 的下载管理器?
  • 网页需要通知用户时,能不能触发原生通知?
  • 网络不稳定时,能不能做缓存和离线支持?
  • Web 代码和 Android 原生代码之间,能不能安全、稳定地双向通信?

这些问题,其实都有解法------JS Bridge。只要通过 JS 接口调用原生方法,理论上都能搞定。

但是!这样做很麻烦。大部分开发者在开发 Web App 的时候,一定是先使用一大堆的第三方库或者 Web 打包工具才能完成开发。

不能开箱即用,才是问题的核心,而这,正是这次主题真正关心的重点。

Android 官方文档也强调,WebView 本质上是 Android View 的一个扩展,它默认只负责显示网页,并不包含完整浏览器的地址栏、导航控制等能力。

因此,一旦你想让它承载一个完整的 Web App,就必须额外处理导航、JavaScript、原生通信、窗口管理等问题。

补齐原生体验

Google 介绍了一个更贴近真实业务的示例:一个 Web 形态的笔记应用。

这个选择其实很典型,因为笔记类应用看起来很简单,但它刚好能覆盖 WebView App 常见的几个关键能力:通知、图片选择、文件下载、缓存、离线、以及 Web 与 Native 的互相调用。

Google 想用一个完整场景告诉你:如果你已经有一个 Web App,那么可以通过 WebView 和 Android 原生能力,把它一步一步做得更像真正的 Android App。

一、互相通信

一个 WebView App 想获得原生能力,最重要的一步就是打通 Web 与 Native 的通信。

否则网页永远只是网页,Android 也只是外面那个壳。

在传统 WebView 中,我们经常会看到 addJavascriptInterface() 这种方式:Android 向 WebView 注入一个对象,JavaScript 可以通过这个对象调用 Android 侧的方法(上面提到的 JS Bridge)。

例如网页里点击一个按钮,然后让 Android 侧弹出 Toast、打开系统能力,或者执行某个原生逻辑。

但这里有一个非常重要的安全前提:你必须清楚 WebView 中加载的内容是否可信。

Android 官方文档明确提醒,addJavascriptInterface() 可能带来安全风险,因为它允许 JavaScript 控制 Android App 暴露出来的对象。

因此它更适合用在你完全控制 HTML 和 JavaScript 来源的场景中,而不适合让用户随便打开第三方网页。

这也正是 WebView 工程里最容易被忽略的问题:WebView 不是浏览器。浏览器会帮你处理大量安全边界,而当你把网页放进自己的 App 时,很多边界就需要你自己设计。

我在 15 - 17 年,有过很长一段时间的 Web App 开发经验,我记得当时我们就是编写了一个超级大的 JavascriptInterface,然后注入 WebView,里面的 Web 也是我们本地的网页(没错,本地的,定期会从服务器下载新的网页),现在想起来,搞不好那个已经具备了小程序的原型,只不过可惜技术方面没有继续往下探究了。因为 Web 体验不好,无法无缝地嵌入到地图中。

二、从 Web 触发原生通知

Google 介绍了一个很关键的能力,是让 Web 代码触发原生 Android 通知。

这件事很能说明 WebView 的定位:Web 管业务逻辑和页面,Android 管系统能力。

比如笔记应用里,用户在 Web 页面创建了一个提醒,最终通过 Android 原生通知弹出来。这跟"网页弹个 alert"完全是两回事------它走的是 Android 的通知权限、通知渠道、系统通知样式,是真正的系统级体验。

边界也很清楚:Web 发出意图,Native 执行系统能力。谁也别越界。

三、原生的文件能力

文件选择,尤其是图片选择,在 WebView 里也是个老大难问题。

Web 里一个 <input type="file"> 就搞定了,但放到 Android App 里,弹出来的选择器体验千差万别------有的 App 直接调起一个简陋的文件浏览器,有的甚至什么都弹不出来。

我之前用过一些 App,上传头像的时候弹出来的选择界面跟系统风格完全不搭,一眼就知道这是 WebView 里硬塞进去的。Google 在讲演里给出的方案是接入 Android 系统的 PhotoPicker,体验直接跟系统相册拉齐。

说白了,WebView 不是让 Web 脱离 Android 各玩各的,而是让 Web 借用 Android 已经打磨好的系统能力。头像、笔记图片、商品图片、评论配图------这些都是高频场景,处理得好不好,用户一眼就能感知到。

四、原生的下载体验

下载文件也是 WebView App 里绕不开的场景。

你肯定遇到过这种情况:在某个 App 里点了个下载链接,进度条一闪而过,然后------没了。

文件去哪了?不知道。下载成功了吗?不确定。去文件管理器翻半天,才在某个犄角旮旯找到。

Google 给出的做法是把下载交给系统的 DownloadManager。这样一来,用户在系统通知栏里就能看到下载进度,下载完了能在系统下载列表里找到,体验跟浏览器里下载东西是一样的。

思路跟前面一样:Web 负责说"我要下载这个",具体的下载体验交给 Android 来做。PDF、报表、图片、附件,这些场景太多了,如果每次都自己造轮子处理文件流,既费劲又容易出问题。

一切,都是为了用户体验!

五、拦截网络请求

还有一个更偏工程实战的点:拦截网络请求,做缓存或离线支持。

很多人对 WebView 的理解就是"必须联网才能用"。但你想想真实场景------地铁、电梯、弱网、海外------如果 WebView 一断网就白屏,用户根本不会给你第二次机会。

WebView 提供了拦截网络请求的能力,开发者可以在 Android 侧对部分资源做缓存,或者在断网时返回本地内容。做到这一步,Web App 才真正不是一个"远程网页窗口"。

当然,缓存这件事不是越多越好。你得想清楚哪些资源值得缓存、哪些接口必须实时请求、用户离线时该看到什么、恢复网络后怎么同步。这些问题没有标准答案,得根据具体业务来定。

这么看,我在 15 年左右做的工作还可以,当时对 Web App 做了版本管理,并且可以完全离线运行。

六、标签页导航

最后说一个容易被低估的问题:导航和标签页。

Web App 不是单页面那么简单。它可能会弹新窗口、跳外部链接、触发登录页、跳到第三方授权------如果这些行为没处理好,用户就会遇到各种糟心事:点了链接突然被甩到外部浏览器,按返回键不知道回到哪,登录完了页面回不来。

这些事,正常浏览器都帮你干了,但 WebView 默认只是个"显示网页的 View",你得自己配置 WebViewClientWebChromeClient 来接管这些行为。

所以很多时候大家觉得 WebView 是个低成本方案,其实恰恰相反。loadUrl() 当然便宜,但要让它像一个正经 App 一样跑起来,需要处理的边边角角一点都不少。

WebView 的正确打开方式

看完整个讲演,我觉得它表达的核心意思其实很简单:WebView 不是原生的替代品,但也不是低质量方案。

它适合的场景很明确------你已经有成熟的 Web 体系、Web 团队和 Web 迭代流程,现在想把这些能力带到 Android 上。它不是让你随便写个网页然后套个壳就完事了。

所谓的"补齐原生体验",说白了就是:Web 和 Native 各有各的边界,谁也别假装能干对方的活。Web 擅长业务页面和快速迭代,Native 擅长系统能力------通知、文件、下载、缓存、导航、安全这些。而 WebView 就是把这两边串起来的那根线。

Android 开发者关注什么

对于 Android 开发者来说,我们可能过去一直有这样一个认知:只要一个功能是 Web 做的,Android 侧就只是"套壳"。

但现在越来越多产品会采用混合架构,Android 开发者需要负责的不只是写原生页面,还包括设计 Web 与 Native 的边界。

比如:

  • 哪些能力应该留在 Web?
  • 哪些能力必须放在 Native?
  • JSBridge 如何设计才安全?
  • 文件选择、下载、通知如何接入系统?
  • WebView 的缓存策略如何设计?
  • 返回键和页面历史如何统一?
  • WebView 生命周期如何管理?

这些问题如果处理得好,WebView App 就可能非常接近原生体验;如果处理不好,它就会变成用户熟悉的那种"套壳网页"。

不要妖魔化 WebView

这次讲演,它没有把 WebView 描述成原生开发的替代品,也没有把 WebView 当成低质量方案,而是将 WebView 视为将 Web 内容带入 Android 生态的能力容器。

在国内,WebView 的名声之所以不好,很大程度上是因为它被大量用在了"快速出活"的场景里------不是为了给用户更好的体验,而是为了尽快满足业务需求、完成 KPI。

结果就是,很多 App 里的 WebView 页面体验粗糙、加载缓慢、交互生硬,久而久之,用户和开发者都形成了"WebView 开发的 App 是次等品"的印象。

但这不是 WebView 的问题,而是使用方式的问题。

它适合内容变化快、业务迭代快、已有成熟 Web 体系的产品。

但它不适合所有场景,比如高度依赖复杂动画、重图形、低延迟交互、复杂后台任务、深度硬件能力的应用,纯原生或者其他跨平台方案仍然可能更合适。

一点想法

"WebView = 套壳"这个印象,可能还要持续很久。

但如果你看过这次讲演就会发现,WebView 本身不背这个锅。loadUrl() 一把梭当然会变成套壳,但如果你认真处理通知、文件选择、下载、缓存、离线、导航、JSBridge 和安全边界,它完全可以成为 Web App 进入 Android 生态的一条正经路径。

未来的 Android 应用,纯 Native 或纯 Web 的划分会越来越模糊。业务层用 Web 保持快速迭代,系统体验由 Native 补齐,二者通过 WebView 协作------这大概率会成为很多产品的常态。

Build native Android experiences for web apps using WebView
www.youtube.com/watch?v=4_S...

相关推荐
ujainu小10 小时前
CANN hixl:大模型 PD 分离场景的零拷贝通信库
android·java·缓存
专注VB编程开发20年11 小时前
b4a用VB语言开发安卓APP-图片缩放库ZoomImageView讲解-双指缩放 + 单指拖动核心源码
android·java·前端
恋猫de小郭11 小时前
Dart 大更新,新增语法糖和各种能力,真的难得了
android·前端·flutter
EQ-雪梨蛋花汤12 小时前
【Sceneform-EQR】让Android 原生 3D开发更容易
android·3d
三少爷的鞋12 小时前
Android 架构指南之Data 层不要再暴露 start/stop 了:用 Flow 接管生命周期
android
李艺为12 小时前
Android 14 U盘无法正常显示中文盘符(卷标)问题解决
android
陆业聪12 小时前
Agent智能体:让AI自己调API干活——从Android Service到AI Agent的思维跃迁
android·人工智能·aigc
莞凰1 天前
昇腾CANN的“灵脉根基“:Runtime仓库探秘
android·人工智能·transformer
NiceCloud喜云1 天前
Claude Files API 深入:从上传、复用到配额管理的工程化指南
android·java·数据库·人工智能·python·json·飞书