凌晨1点,比赛正酣,你鬼使神差地打开DraftKings,想再下一注。屏幕亮起,Pawl的拦截页面出现。钥匙在你姐姐家,穿过半个城市才能拿到,拿到后还要再等15分钟。等你能操作时,那股冲动通常已经过去了。这就是Pawl的全部设计理念——它不试图让你永远戒赌,它只是让"凌晨1点的那个你"慢下来。
Pawl是一个开源的iOS应用,专门拦截体育博彩、赌场等App和网站。它用Apple的Screen Time机制实现拦截,但和市面上所有其他拦截器有个根本区别:**应用里没有任何解锁按钮**。想解除拦截,你必须插入一个物理FIDO2安全密钥(比如YubiKey,一种USB-C接口的硬件认证设备),这个密钥在设置时插过一次,之后就被你放在某个够得着但需要费一番功夫的地方。即便有钥匙,解锁后还要等15分钟的冷静期,而且拦截会自动恢复。
这个设计的精妙之处在于它直面了一个所有戒断类工具都绕不开的困境:**大多数拦截器都能被设置它的那个人在30秒内解除**——恰恰是在他们最想解除的那一刻。Pawl把解除拦截的成本从"划一下屏幕"提升到"物理上拿到钥匙+等待15分钟",利用的是冲动本身的时间衰减特性。
从技术实现上看,Pawl有几个值得玩味的设计决策。
首先是拦截机制。Pawl通过Apple的Screen Time框架工作,用户通过系统自带的Picker选择要拦截的App和网站。这里有个隐私细节:Pawl永远不会知道你到底拦了哪些App——Apple递给它的是一个不透明的令牌(opaque token,即一个无法反推出原始内容的标识符),它只负责转发。
其次是解锁流程。Pawl向iOS请求一个安全密钥断言(security key assertion,即向系统验证物理密钥存在的凭证),然后检查凭证ID是否匹配你注册的那把钥匙。但作者在README里非常坦诚地指出:**它不验证断言的签名**。在未越狱的iPhone上,iOS自己负责和钥匙通信,所以这能证明钥匙物理上在场,但这不是密码学意义上的严格证明。作者明确标注这是审查者应该首先关注的地方。
第三是那个15分钟冷静期。Pawl的解锁循环被实现为一个纯函数(pure function,即不依赖外部状态、输入相同输出必然相同的函数),放在`UnlockMachine.swift`里,配套19个单元测试。这个循环的核心逻辑是:插入钥匙→请求解锁→等待15分钟→解锁生效→30分钟后拦截自动恢复。你可以随时把等待时间调得更长,但**调短这个操作本身也有延迟**——防止你在冲动时刻把冷静期改成0。
最让我意外的是作者对"失败"的态度。Pawl内置了一个复发日志(relapse log),记录你每次没忍住的情况。这个日志完全私有,应用里没有任何功能会因为你复发了而责备你。作者在README里写得很直白:"复发是康复过程的一部分"。这种设计哲学在戒断类工具里相当罕见——大多数同类产品都在做道德评判,而Pawl只关心一件事:降低你冲动时刻的行动能力。
当然,作者也没有回避这个方案的局限性。iOS允许手机所有者关闭Screen Time,没有任何App能阻止这一点。Pawl能做的只是在下次运行时发现,然后如果有赞助人(sponsor,你信任的另一个人,通过邀请码和你关联),就推送一条警报。真正的"硬锁"流程是:赞助人当面设置Screen Time的密码并自己保管——这时是iOS在强制执行,而不是Pawl。
另一个已知弱点是时钟锁定功能还没启用。代码里有一段`setClockLock`用来强制要求系统自动日期时间,但还没有任何地方调用它。在那之前,把手机时钟往前拨可能会缩短冷静期。作者说这个行为还没测试过。
Pawl的架构也值得一看。整个项目分为几个清晰的层次:`Pawl/Domain/`是纯逻辑(解锁循环、连续天数、模型),`Pawl/Services/`是iOS和后台代码(拦截、钥匙、iCloud、Supabase、StoreKit),`Pawl/Features/`是SwiftUI界面,`PawlShield/`是拦截页面本身。后端用Supabase(一个开源的BaaS平台,提供数据库和认证服务),但只用于可选的赞助人功能——单机拦截完全不需要账号。
数据隐私方面,作者做了很细致的区分。你拦截了哪些App和网站、连续天数、复发日志都存在你的手机和iCloud里,只有你能看。账号信息、解锁请求和批准记录存在Supabase,只有你和你的赞助人能看。每个Supabase表都开了行级安全(row level security,即数据库层面拒绝向非授权用户返回数据),规则写在`schema.sql`里。作者特别强调,Supabase的URL和匿名密钥是公开的——它们本来就在每个App副本里,真正保护数据的是行级安全规则,而不是那个密钥。
Pawl目前是单人开发,没有公司、没有融资、没有投资人。没有独立审计,没有可复现构建(reproducible builds,即无法证明App Store的二进制文件确实由这份源码编译而来),大部分代码没有自动化测试。作者把这些全部列在README里,语气平静,不掩饰。
这个项目的思路能直接迁移到哪些场景?任何"需要对抗即时冲动"的领域。比如:限制自己刷短视频、限制游戏时间、限制社交媒体。核心方法论是:**把解除限制的摩擦成本提高到超过冲动持续的时间**。物理钥匙+冷静期这个组合,比任何"意志力模式"都可靠,因为它不依赖你那一刻的理智。
要注意的坑也很明确:任何你完全拥有的设备上的拦截器都能被绕过(另一台手机、笔记本、朋友的设备)。Pawl做的只是让"凌晨1点的版本"变慢,不是让它不可能。另外,如果你打算自己构建,需要Xcode 26、iOS 18以上的iPhone(Screen Time在模拟器里不工作)、付费的Apple开发者账号,还得让Apple批准Family Controls权限。安全密钥需要一个你拥有的域名,配置`apple-app-site-association`文件。
Pawl的代码采用MPL 2.0许可证(Mozilla Public License,一种允许商用但要求修改后的源码继续开源的许可证),作者特意选了MPL而不是GPL,因为GPL系列许可证和App Store的条款冲突——一个上不了App Store的拦截器帮不了任何人。唯一的例外是赌博域名黑名单,大部分来自HaGeZi的列表,保持GPL-3.0。
如果你对戒断类工具的技术实现感兴趣,或者想看看一个单人开发者如何用iOS的系统能力做出真正有深度的产品,Pawl的代码仓库是个很好的阅读材料。作者在README里给出了阅读路径:从`UnlockMachine.swift`开始,然后是它的19个测试,再看`SecurityKeyService.swift`了解已知弱点,最后看`ShieldService.swift`理解拦截的施加与解除。安全修复都在代码注释里标注了`SECURITY FIX`,可以直接搜索。
最打动我的是作者在贡献指南里写的一句话:"任何涉及用户屏幕上文字的内容,都应该保持平实和善意:使用这个应用的人正在经历困难时期,应用绝不能因为复发而羞辱任何人。"技术方案可以复制,但这个态度很难得。
内容与图片版权归原作者所有 · 原文: https://github.com/jasonepage/Pawl