news 2026/10/24 16:08:17

D18_WebView阅读与返回

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
D18_WebView阅读与返回

Android 学习笔记 D18|WebView 阅读页:两条返回栈和一次正确的加载

发布摘要:为文章详情加入原文阅读,重点处理网页历史、应用返回、重复加载、地址校验和资源释放。标签:Android、WebView、Compose、导航。

用户从收藏列表进入详情,再打开原文 A,随后点进网页 B。此时按一次返回,合理行为是回 A;再按一次,才退出阅读页。如果只让应用导航弹栈,网页历史被跳过;如果始终吞掉返回,用户又可能无法离开。WebView 集成的难点在于宿主要管理网页以外的规则。

本文对应 D18 和《第一行代码》第 11 章 WebView、网络部分,AndroidView 是现代补充。示例为教学核心,尚未在用户工程编译运行;需要网络权限、Compose UI、Activity Compose,以及项目已有的导航配置。

一、先定义允许做什么

练习版针对受控、不含表单的页面和普通链接导航,内嵌入口限制为业务确认过的 HTTPS 主机;回调捕获的其他合法 HTTPS 链接交给外部浏览器,异常协议拒绝。主机应解析后精确比较,不能使用“字符串包含本站域名”,否则本站域名.evil.example也会通过。首次加载与回调捕获的网页内跳转使用同一判断。

这里的允许列表不代表自动审查所有子资源,也不是完整浏览器隔离方案。shouldOverrideUrlLoading不覆盖 POST 导航,不能用下面的客户端证明任意网页的全部主框架导航都被限制;不受控的复杂页面优先交给浏览器,若需要更强限制必须另行设计和验证。WebViewClient 回调边界 不要对任意文章页面暴露原生 JavaScript 接口;页面不需要脚本时保持关闭。证书校验失败应中止,不通过调用继续加载来隐藏错误。不安全 URI 加载

第一步写地址校验函数;第二步做纯原生 WebView 小实验;第三步再放入 AndroidView;第四步接入返回逻辑。这样可以区分问题来自网页本身、地址策略,还是 Compose 生命周期。

二、记录业务输入,不要用当前网页地址判断是否重载

网页从 A 跳转到 B 后,WebView 当前地址已经变了。如果update每次都比较“当前地址是否等于文章原始地址”,下一次重组就会把 B 拉回 A。应该记录最后一次接收到的业务入口地址,仅在用户切换文章时重新加载。

以下完整控件类展示这个边界。导入来自 Android 平台,不需要额外 WebView 库。允许列表由调用方提供;onExternal只处理已验证的外部 HTTPS 主页面,并负责处理找不到浏览器的情况。

importandroid.content.Contextimportandroid.net.Uriimportandroid.webkit.WebResourceRequestimportandroid.webkit.WebViewimportandroid.webkit.WebViewClientimportjava.util.LocaleclassArticleWebView(context:Context,privatevalhosts:Set<String>,privatevalonExternal:(Uri)->Unit,privatevalonHistory:(Boolean)->Unit):WebView(context){privatevarrequestedEntry:String?=nullprivatefunvalidHttps(uri:Uri):Boolean=uri.isHierarchical&&uri.scheme.equals("https",true)&&uri.userInfo==null&&!uri.host.isNullOrBlank()&&(uri.port==-1||uri.port==443)privatefunallowed(uri:Uri):Boolean=validHttps(uri)&&uri.host!!.lowercase(Locale.ROOT)inhostsinit{settings.javaScriptEnabled=falsewebViewClient=object:WebViewClient(){overridefunshouldOverrideUrlLoading(view:WebView,request:WebResourceRequest):Boolean{if(!request.isForMainFrame)returnfalseif(allowed(request.url))returnfalseif(validHttps(request.url))onExternal(request.url)returntrue}overridefundoUpdateVisitedHistory(view:WebView,url:String?,isReload:Boolean){onHistory(view.canGoBack())}}}funopenArticle(url:String):Boolean{if(!allowed(Uri.parse(url)))returnfalseif(requestedEntry!=url){requestedEntry=urlloadUrl(url)}returntrue}}

本片段使用 API 24 及以上的请求重载回调,若工程最低版本更低,需要按官方说明补兼容重载。允许当前网页继续加载时返回 false;由宿主拦截后返回 true,不能先手动loadUrl再返回 true,造成重复导航。WebView 导航说明

三、返回与释放分别由明确的边界处理

Compose 用 AndroidView 的 factory 创建该控件,update 调用openArticle。宿主把onHistory的结果保存为可观察状态;当前阅读页可见且能网页后退时启用 BackHandler,调用 goBack。没有网页历史时让应用导航处理返回,工具栏按钮使用同一优先级。

加载反馈可通过 WebChromeClient 更新进度,主页面错误通过 WebViewClient 的错误回调显示。子资源图片失败不能一律把整篇文章替换成错误页;必须判断是否为主框架请求。重试是显式用户事件,重新加载当前入口时应明确调用 reload 或提供专门重试方法,因为上述去重函数会忽略相同入口。

AndroidView 的 onRelease 表示不再使用此 View,可在主线程停止加载、移除宿主监听,从父容器移除后 destroy,并清空宿主持有的实例。销毁后不能再调用该对象。暂停与销毁不是同一件事;onPause 不代表所有脚本都停止,pauseTimers 又可能影响进程内其他 WebView。WebView API、AndroidView 释放回调

练习版旋转后重新打开文章入口,并明确暂不恢复网页历史。需要历史恢复时,再设计 saveState、restoreState 与体积控制,不要把“平时不重载”写成“进程重建后自动保留”。

四、故障实验与预期

先从 A 点击到 B,再改变收藏状态制造一次重组。错误实现会返回 A;修复后预期停留 B。第二次实验连续按返回,记录网页 URL 和应用返回栈长度,预期先改变网页历史,最后才移除阅读目的地。

第三次输入一个协议不支持的地址、一个类似可信主机的假域名、一个无效页面。预期分别被拒绝、交给既定外部策略或拒绝、显示主页面错误,不能靠崩溃结束流程。测试只用自有或受控地址,不需要访问真实恶意站点。

最后重复进入退出阅读页,记录创建和释放次数。日志配对是必要证据,但不能证明所有原生资源都已释放;若内存持续增长,应进一步检查对象引用和 WebView 进程情况。

五、原创面试问答与追问

以下是课程自拟题,可联系题库的Activity 生命周期复习宿主责任。

问:为什么返回不能只交给导航框架?答:WebView 还有内部历史,导航框架不知道产品希望先退出哪一层。追问:顶部返回和系统返回应不同吗?本练习采用相同规则,避免操作结果冲突。

问:如何防止重组把网页拉回入口?答:比较最后一次业务输入,不比较正在浏览的当前地址。追问:同一地址失败后怎样重试?使用独立重试事件,不能让普通状态刷新代替重试。

问:白名单通过就能开启任意原生桥吗?答:不能,桥接权限、页面来源、导航和脚本内容仍有独立边界。追问:本项目需要桥吗?只阅读外部文章,不需要为此新增桥接能力。

六、当天练习与验收

二十分钟画两条栈,四十分钟阅读客户端回调,一百五十分钟实现,三十分钟执行四组实验,一小时复述职责。提交一张栈变化图、地址策略说明和真实运行记录;未执行的故障案例保持“预期”表述。

无参考练习是增加“用浏览器打开当前页面”按钮,复用地址检查和异常提示。通过标准是能解释当前 URL、业务入口和应用详情编号为什么是三份不同的数据。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 12:01:29

基于Django的互联网问诊系统开发实践

1. 项目背景与核心价值 最近在整理技术资料时&#xff0c;翻到了去年指导学弟完成的毕业设计项目 - 一个基于Django框架的互联网问诊系统。这个项目结合了当时比较热门的大数据处理技术&#xff0c;实现了从用户问诊到医生管理的完整闭环。现在回看这个项目&#xff0c;发现它确…

作者头像 李华
网站建设 2026/10/24 16:07:49

多Agent系统中Skill的三层治理:契约、实现与实例

1. 为什么“同一个 skill 存三份”不是冗余&#xff0c;而是多 agent 系统的必然状态你刚在本地跑通一个 agent demo&#xff0c;给它加了个“查天气”的 skill&#xff0c;代码清爽&#xff0c;逻辑清晰。两天后&#xff0c;团队里另一位同事基于同一套框架&#xff0c;也实现…

作者头像 李华
网站建设 2026/10/24 16:08:16

RTL2832U电视棒SDR软件合集:驱动配置与多平台接收实战指南

简介&#xff1a;RTL2832SDR软件合集面向无线电爱好者和软件定义无线电入门用户&#xff0c;将基于RTL2832U芯片所需的驱动、接收软件与分析工具集中打包&#xff0c;解决了从设备安装到信号接收全流程的软件配置难题。压缩包共54个文件&#xff0c;整体约44.08MB&#xff0c;涵…

作者头像 李华
网站建设 2026/10/24 16:08:00

SpringBoot婴幼儿健康问诊平台开发实践

1. 项目背景与核心价值作为一名在医疗信息化领域摸爬滚打多年的开发者&#xff0c;我见证过太多"为了毕业设计而设计"的系统。但这个基于SpringBoot的婴幼儿健康在线问诊平台却让我眼前一亮——它切中了年轻父母在育儿过程中的真实痛点。凌晨三点孩子突发高烧&#x…

作者头像 李华
网站建设 2026/10/24 16:08:02

Torchtext德语英语翻译实战:从数据清洗到ONNX部署

1. 项目概述&#xff1a;为什么德语到英语翻译是检验NLP工程能力的“试金石” 在实际工业场景里&#xff0c;我见过太多人把“能跑通一个Transformer模型”当成掌握了机器翻译——结果一碰真实业务数据就卡在预处理上&#xff0c;或者训练三天发现BLEU分数始终卡在28分不动。这…

作者头像 李华
网站建设 2026/10/20 11:51:11

高分三号SAR影像处理全流程:从辐射定标到地形校正与极化分解

简介&#xff1a;面向 SAR 遥感初学者的 GF-3 高分三号卫星影像处理资料&#xff0c;服务于需要使用 SARscape 完成 SAR 数据预处理的学生、科研人员与工程技术人员&#xff0c;解决从 GF-3 原始数据到可分析强度影像的流程落地问题。文档围绕完整作业链展开&#xff1a;先介绍…

作者头像 李华