克魔助手
全部文章

iOS App 沙盒里到底装了什么

3 分钟阅读应用数据调试

每个 iOS App 都有一个沙盒:一棵它能读写、别人看不到的私有目录树。绝大多数“数据清不掉”、“卸载重装后设置还在”、“文件一夜之间消失了”的 bug,追到最后都是东西放错了地方。

各个目录

Documents/ —— 用户产出的、丢了会生气的内容。会备份到 iCloud 和电脑备份里。如果 App 声明了,会出现在“文件”App 中。系统永远不会清理它。

Library/Application Support/ —— App 需要但不是用户直接创建的数据。会备份,永不被清理。数据库应该放这里。

Library/Preferences/ —— UserDefaults。会备份。只放小值,这不是存储。

Library/Caches/ —— 可再生的数据。会备份吗?不会。系统在存储吃紧时会清理它,不预警也不通知你。下载的图片和接口响应放这里是对的;任何拿不回来的东西放这里是错的。

tmp/ —— 临时空间。不备份,清理很激进,可能在两次启动之间就没了。任何你希望活过一次运行的东西都不该放这里。

由此推出的规则

放在 Documents/ 里的缓存永远清不掉。 如果用户反馈占用一直涨、清缓存没有任何效果,先看缓存到底在哪。在 Documents/ 里的话,它不是缓存,是一份变量名起错了的永久数据,而且还会被备份 —— 用户的 iCloud 备份因此大得离谱。

放在 Caches/ 里的数据库会消失。 不常发生,而且测试期间从来不发生 —— 这正是这个 bug 能进生产环境的原因。它表现为“App 把一切都忘了”,出现在存储空间紧张的设备上。

放在 tmp/ 里的东西说没就没。 重启后从 tmp/ 续传的下载,有时会发现那里什么都没有。

Documents/ 会被备份,所以要让它小。 Documents/ 里 4 GB 的媒体缓存,意味着用户的备份凭空大了 4 GB,恢复手机要多花一个小时。

直接去看沙盒

上面所有争论,最快的解决办法是打开来看。通过一条受信任的 USB 连接,可以浏览某个 App 的沙盒、把它存的数据解密出来、把文件拉回本地。

这样每项大约一分钟就能回答:

  • 缓存到底在不在 Caches/,还是在某个永久目录里?
  • App 有没有写入新的响应,还是在返回一个从来没被替换过的旧的?
  • 那个数据库文件是不是你预期的大小,还是某张表一直在涨没人裁剪?
  • 迁移产出的表结构,是不是你以为的那个?
  • 下载下来的资源是完整的还是被截断了?

上面每一条,否则都是一轮“加条日志再发一版”。

复现用户的状态

这个领域最有用的一招:把用户的沙盒从他设备上导出来,灌进你自己设备上的一个包 —— 那个“只有这一个账号会出”的 bug,就在你桌上复现了。

这也是最需要谨慎的一招。于是就说到比上面所有内容都更重要的部分。

这是某个人的数据

App 沙盒里装着聊天记录、照片、位置历史、令牌,以及这个 App 存过的一切。导出它不是一个没有后果的技术操作。

  • 只在你拥有或已获明确授权检查的设备上做。
  • 动手之前告诉设备所有者你要取什么、为什么取。
  • 取能回答问题的最小范围 —— 一个文件,而不是整个沙盒,除非你真的需要整个沙盒。
  • 工单关闭就删掉导出文件。笔记本上放着的一份沙盒导出,等的只是一个被偷走的包。
  • 永远不要不加处理就把它当附件传到共享工单里。

在这件事上出问题的团队,通常并非恶意。他们只是为了排查导出了一份,查完了,然后忘了那个文件夹的存在。

顺带说一句:有一样东西不在里面

钥匙串。凭证、令牌,以及其他被正确存储的东西都在沙盒之外,不会跟着导出来。如果你正在 Documents/ 里找会话令牌,要么它不在那儿,要么这个 App 有一个比你原来那个更值得关注的安全问题。