孙工的三星手机上,点击“打开音乐”后停在了空白页
孙工在群里发了三段录屏,时间戳分别是 3 月 17 日的 14:22、14:31、14:40,三次结果都不一样。我们逐帧看,发现第二次点击时浏览器右上角闪过一个灰色小图标,之后就没了下文。他最后说了一句:“我以为是网络问题,重连了两次 Wi-Fi。”这句让我意识到,用户对失败原因的归因常常是错的。
scheme失败复现那一页讲的是点击网页上的链接去唤起本地程序,作者在页边空白处画了个箭头,写“有时候不行,多重启几次”。二十三年过去,我把这句话抄进笔记本,发现自己还在问同一件事。
这个页面是我给「qq浏览器打开第三方软件」这个主题做的分类索引,不是结论,更像一份实验记录。起因很朴素:上个月十五号晚上九点多,我在测试一个外部页面上的唤起按钮,同一台安卓机、同一个 qq 浏览器版本、同一条链接,第一次点直接跳到了本地音乐播放器,第二次点却停在浏览器里弹出一句“已阻止打开应用”,第三次又好了。我把三次的截图并排贴在笔记本上,发现自己根本说不清差别在哪。技术文档通常只告诉你“可以用 intent 或 scheme 唤起”,却很少告诉你失败的时候,责任到底落在哪一层——是页面写法、是浏览器策略、还是系统把选择权悄悄收走了。
所以我开始逐条记录:哪些链接在什么机型上失败,哪些设置动过之后恢复,哪些用户的描述和我的观察对得上。下面 11 条是我目前能拿出来给人看的,它们大多没有令人满意的结尾。需要先说明的是,我倾向于认为大部分“打不开”并不是 bug,而是浏览器和系统对“未知唤起”的态度变保守了,这在安全上是对的,但它把解释成本全推给了普通用户和写页面的人。如果你从别的入口进来,可能会想看 免费网站浏览器入口浏览器打开 那条记的入口失效问题,它的症状和我这批记录高度重合。
孙工在群里发了三段录屏,时间戳分别是 3 月 17 日的 14:22、14:31、14:40,三次结果都不一样。我们逐帧看,发现第二次点击时浏览器右上角闪过一个灰色小图标,之后就没了下文。他最后说了一句:“我以为是网络问题,重连了两次 Wi-Fi。”这句让我意识到,用户对失败原因的归因常常是错的。
scheme失败复现这部教程我看了两遍,第 7 分 40 秒处作者说“别在应用里点,复制到浏览器再打开”,当时没懂,后来才明白他说的是避开应用内 WebView 的拦截。视频里的界面是 2021 年的旧版本,很多按钮位置都变了,但那条建议仍然成立。教程的语速很快,我按了 11 次暂停才把那段操作记全。
教程笔记WebView为了弄明白这句话的出处,我拆了一个旧版安装包,用文本工具搜索这六个字,没找到;又去翻系统设置里的应用管理,发现它来自系统层的一个通用提示模板。也就是说,页面作者写什么文案都不影响这句话的出现。这个发现让我有点沮丧,因为它意味着我们只能改触发方式,改不了提示本身。我把结论发在群里,有人回:“那还不如直接告诉用户去设置里找。”
系统提示策略李默是我大学同学,现在在合肥一家网吧做网管。他截图给我看他那台机器:先在系统设置里清了一遍“默认应用”,又在 qq 浏览器里关掉“拦截未知协议”,最后还重启了一次。他说全过程花了 6 分钟,顾客早就不耐烦了。我问他能不能把这套流程写成一页纸贴在墙上,他说贴了,但字太小,没人看。
默认应用实操我做了一组对照:同一条链接,从搜索结果的跳转页进入,唤起成功率明显低于直接在地址栏粘贴。我猜是跳转页多了一层中间重定向,浏览器把它判定为“来源不明”。这个猜测我没有办法严格验证,只能记录下 8 次尝试里有 3 次失败。这让我想起 腾讯qq官方网站入口 那条记录里提到的入口收敛问题,二者也许来自同一种思路:宁可多拦一次。
重定向对照实验这本书第 4 章给了个 92% 的唤起成功率,但脚注里只写了“在测试机型上”。我数了一下,他们测试机型表里一共列了 6 台手机,全部是当年旗舰。这让我怀疑这个数字对中低端机型没有参考价值。我把疑问写在书页空白处,旁边画了个问号。书的作者是某大厂工程师,我理解他为什么要简化,但简化到把测试条件藏进脚注,就有点过了。
读书笔记数据质疑王阿姨住在我家楼下,今年 61 岁。我请她演示怎么在手机上打开一个外部链接,她点了两下发现没反应,就把手机递给我,说“是不是坏了”。我问她平时遇到这种情况怎么办,她说“就关了,换一个”。访谈持续了 14 分钟,她一共说了 4 次“麻烦”。这段录音我反复听了两遍,越听越觉得,我们讨论的那些技术选项,在她那里根本不存在。
用户访谈可用性很多产品文档把“弹出应用选择列表”描述成尊重用户,我不太同意。对多数人来说,多一次选择就是多一次犹豫,而他们并不具备判断能力——他们不知道两个选项哪个安全,也不知道选错之后怎么撤回。我更倾向于让页面把意图写清楚、把失败态兜住,而不是把决策压力转移出去。这个观点在群里被反驳过两次,我没改。
观点交互设计这条是我对照官方文档和实机测试记下来的。安卓 15 上如果不显式声明包名,唤起会被当作“隐式意图”处理,成功率明显下降;而在安卓 13 上,加了包名反而可能触发另一种拦截。我把两个版本的写法并列写在纸上,用红笔圈出差异,然后意识到:任何一份“通用方案”都会在某处失效。所以我在归档里坚持记录机型,而不是只记结论。
intent版本差异那天下午我抓了将近 40 分钟,过滤出 6 次跳转,其中两次是 307 临时重定向,这在一般的经验分享里很少被提到。307 会保留原始请求方法,对唤起这种带着自定义头的请求来说,可能改变最终到达的地址。我没有能力把整条链路完全解释清楚,只能把抓包文件存下来,命名成“2026-02-06-唤起链路”。它现在还在我桌面的一个文件夹里,我偶尔会打开看。
抓包重定向这是目前最困扰我的问题。我在四种失败场景下设计了不同的兜底文案,但每一次测试都发现有人不看文案、直接返回。也许兜底的重点不在“解释”,而在“给一个确定能走通的下一步”:一个可以长按复制的链接,或者一个跳回普通网页的按钮。我还没想清楚。这页归档会一直开着,有新证据就补一条。
兜底设计开放问题