☰
删掉 App 也删不掉的痕迹:Loupe 演示 Keychain 如何跨重装记住你的安装次数
2026/10/12 5:58:49 网站建设 项目流程

【免费下载链接】loupe

A privacy-focused iOS app that raises awareness about what native apps can see

项目地址:https://gitcode.com/gh_mirrors/loupe12/loupe
点击查看免费下载

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 把这个机制做成了一个可感知的实验,核心逻辑只有三步:

  1. 长期记忆在 Keychain。App 把历次安装的时间戳以 JSON 数组形式存进一条 Keychain 记录,写入时使用的可访问级别是kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly(本机设备、首次解锁后可读),见 KeychainInstallLog.swift 的writeDates。
  2. 短期记忆在 UserDefaults。每次启动时,App 会先看 UserDefaults 里的hasRecorded标记:这个标记一旦卸载就消失,所以"重装后第一次启动"必然能被识别出来。
  3. 识别到重装,就往长期记忆里追加一条时间戳,再打上标记,见 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

想亲眼看到这条痕迹,步骤非常简单:

  1. 在 App Store 安装Loupe,打开首页,点击Previous Installs Log分类,记下当前的 Install count(首次安装通常为 1)。
  2. 长按桌面图标卸载 Loupe,确认删除。
  3. 重新下载安装 Loupe 并打开,再次进入该分类——你会看到 Install count 变成 2,同时 Install history 多出一条新的时间戳。
  4. 重复几次,历史列表会逐条增长,而它们全都只存在你手机的 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

项目地址:https://gitcode.com/gh_mirrors/loupe12/loupe
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询