【免费下载链接】loupe
A privacy-focused iOS app that raises awareness about what native apps can see
Loupe是一款面向 iPhone 与 iPad 的隐私科普 App,它会从公开 iOS API 读取真实数据,直接展示"任何第三方 App 都能在你的手机上悄悄读到什么"。其中最反直觉的一项演示是:即使你彻底卸载再重装一个 App,只要它把时间戳写进了Keychain,它就能跨重装记住"自己在你设备上装过几次"。本文将带你弄懂这套机制的原理,并手把手在 Loupe 里亲手验证。
什么是 Keychain:为什么卸载 App 后数据还会留下
先说结论:
- App 的沙盒文件、UserDefaults 里的设置:卸载 App 时会被 iOS 一并清除,这是大多数人的默认认知。
- Keychain(钥匙串)里的条目:由系统安全层统一保管,卸载 App 并不会自动删除它写入的 Keychain 记录。
Keychain 原本是 iOS 保管密码、证书、令牌的安全保险库,App 通过通用密码(generic password)条目往里读写数据完全合规。KeychainInstallLog.swift 文件开头的注释把这层对比写得非常直白:
UserDefaults are wiped on uninstall; Keychain entries survive. By comparing the two we detect fresh installs. (卸载会清空 UserDefaults,但 Keychain 条目会存活;对比两者即可识别"全新安装"。)
换句话说,Keychain 是 App 为数不多可以"跨越重装"的本地存储,这也正是"删 App 删不掉的痕迹"的技术根源。
Loupe 的演示原理:用两个"记事本"对账
Loupe 把这个机制做成了一个可感知的实验,核心逻辑只有三步:
- 长期记忆在 Keychain。App 把历次安装的时间戳以 JSON 数组形式存进一条 Keychain 记录,写入时使用的可访问级别是
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly(本机设备、首次解锁后可读),见 KeychainInstallLog.swift 的writeDates。 - 短期记忆在 UserDefaults。每次启动时,App 会先看 UserDefaults 里的
hasRecorded标记:这个标记一旦卸载就消失,所以"重装后第一次启动"必然能被识别出来。 - 识别到重装,就往长期记忆里追加一条时间戳,再打上标记,见 KeychainInstallLog.swift 的
recordInstallIfNeeded。
这样,两个"记事本"一短一长:短的每次重装都会重置,长的却一路累积。App 不需要联网、不需要任何权限,就能精确数出自己的"安装次数"。
打开 Loupe 你会看到什么:4 张安装记录卡片
在 Loupe 首页列表里,这个演示对应Previous Installs Log分类,副标题就是"Reinstall history kept in Keychain"(保存在 Keychain 中的重装历史),分类定义在 SignalCategory.swift。它被归在Advanced(进阶)层级,因为 Keychain 跨重装持久化属于"对公开 API 的巧妙用法"之一。
进入该分类后,PreviousInstallsProvider.swift 会采集并展示 4 张信号卡片:
| 卡片 | 含义 |
|---|---|
| Install count(安装次数) | 这个 App 在这台设备上累计安装过的次数 |
| First install date(首次安装日期) | Keychain 里记录的最早一次安装 |
| Current install date(当前安装日期) | 本次安装的启动时间 |
| Install history(安装历史) | 历次安装时间戳的完整列表 |
每张卡片下方都有一句解释,比如安装次数卡片写的是:"Number of times this app has been installed. Keychain entries persist across uninstalls."(这个 App 被安装过的次数。Keychain 条目在卸载之间持续保留。)
为什么"被记住装过几次"值得警惕
单独看,"装过 3 次"似乎无关紧要。但它揭示的是一种普遍模式:
- 你以为的"重新开始",App 记得清清楚楚。卸载重装常被用户当作清除 App 本地状态的手段,而 Keychain 让 App 能够识破这一点。
- 为定向行为提供信号。"这是老用户重装"和"这是首次安装"可以驱动完全不同的引导流程、推送策略或广告定价。
- 与其他指纹叠加。安装次数本身不唯一,但和 Loupe 展示的设备型号、系统版本、字体、时区等信号组合后,就成为"跟随你跨 App 的设备指纹"的一块拼图。
更关键的是:这一切发生在完全离线、零权限的状态下,不触发任何系统弹窗,用户无从感知。
如何亲手验证:重装一次,数字就 +1
想亲眼看到这条痕迹,步骤非常简单:
- 在 App Store 安装Loupe,打开首页,点击Previous Installs Log分类,记下当前的 Install count(首次安装通常为 1)。
- 长按桌面图标卸载 Loupe,确认删除。
- 重新下载安装 Loupe 并打开,再次进入该分类——你会看到 Install count 变成 2,同时 Install history 多出一条新的时间戳。
- 重复几次,历史列表会逐条增长,而它们全都只存在你手机的 Keychain 里。
和 Loupe 的整体设计一致:所有读数都保留在本地、原样展示,除非你主动导出,否则不会上传、同步或分享给任何人。
想深入源码?关键文件都在这里
- code/Loupe/Support/KeychainInstallLog.swift:Keychain 读写实现,
readDates/writeDates展示了如何用SecItemCopyMatching查询、SecItemAdd/SecItemUpdate写入。 - code/Loupe/Providers/PreviousInstallsProvider.swift:把安装日志转换成 4 张用户可见的信号卡片。
- code/Loupe/Models/SignalCategory.swift:
previousInstalls被标记为 Advanced 敏感级别。 - code/Loupe/Support/Sensitivity.swift:三个敏感层级(Passive / Needs Permission / Advanced)的完整定义。
小结
- Keychain 是 iOS 上少数卸载 App 后依然存活的本地存储,这是"删掉 App 也删不掉痕迹"的根源。
- Loupe 用 UserDefaults(会消失)+ Keychain(会存活)的对账技巧,把不可见的重装历史变成看得见的数字。
- 这个演示零权限、离线完成,提醒我们:设备指纹里最容易被忽视的,往往是那些"系统默许、无需授权"的读取。
【免费下载链接】loupe
A privacy-focused iOS app that raises awareness about what native apps can see
相关推荐
Readest 同步引擎的 deleted_at 游标不变量:何时能删掉 `OR deleted_at > since`,何时删了会让已删除的高亮“复活”
Readest 同步引擎的 deleted_at 游标不变量:何时能删掉 OR deleted_at since ,何时删了会让已删除的高亮“复活” 导读 Re
桌面应用跨平台前端':all:' 的危险面:tmux-resurrect 为什么可能在你重启后删掉硬盘,如何自我保护
':all:' 的危险面:tmux resurrect 为什么可能在你重启后删掉硬盘,如何自我保护 tmux resurrect 是一款开源 tmux 插件,核
开发工具awesome-agentic-ai-zh 之 Agent Memory 实战:只记值得记、允许记、能删掉的事
awesome agentic ai zh 之 Agent Memory 实战:只记值得记、允许记、能删掉的事 本指南对应 awesome agentic ai
教程文档AI Agent人工智能大模型
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考