如何获取iOS应用首次安装/下载日期以保留老用户免费权益?
搞定iOS应用首次安装日期的靠谱方案
嘿,我完全懂你的需求——要把现在免费的功能商业化,但得让老用户继续免费,核心就是要准确拿到用户首次安装/下载应用的时间对吧?你之前看到的用UserDefaults存首次启动日期的方法,确实有个坑:用户要是卸载重装,这个记录就没了,没法真正识别“老用户”。下面给你几个更稳妥的方案:
1. 用Keychain存,卸载不丢失
Keychain里的数据不会随应用卸载清空(除非用户重置设备或者手动删除所有应用数据),完美适合存首次安装时间:
- 首次启动时,先检查Keychain里有没有
firstInstallTimestamp这个键 - 没有的话,就把当前日期存进去;有的话直接读取用就行
- 给你一段Swift的示例代码:
import Security func fetchFirstInstallDate() -> Date? { // 查询Keychain let query: [CFString: Any] = [ kSecClass: kSecClassGenericPassword, kSecAttrAccount: "firstInstallTimestamp", kSecReturnData: kCFBooleanTrue!, kSecMatchLimit: kSecMatchLimitOne ] var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) switch status { case errSecSuccess: // 解析已存储的日期 guard let data = result as? Data else { return nil } return try? JSONDecoder().decode(Date.self, from: data) case errSecItemNotFound: // 首次启动,存储当前日期 let now = Date() guard let data = try? JSONEncoder().encode(now) else { return nil } let addQuery: [CFString: Any] = [ kSecClass: kSecClassGenericPassword, kSecAttrAccount: "firstInstallTimestamp", kSecValueData: data ] let addStatus = SecItemAdd(addQuery as CFDictionary, nil) return addStatus == errSecSuccess ? now : nil default: return nil } }
2. 解析App Store收据,拿官方首次购买日期
这是最准确的方法——通过验证App Store的应用收据,能拿到original_purchase_date字段,这个字段是用户首次下载(购买)应用的日期,哪怕卸载重装也不会变:
- 先从App Store获取应用收据(注意区分测试环境和生产环境的处理逻辑)
- 解析收据里的
original_purchase_date,转换成Date格式 - 优点是完全依赖苹果官方数据,绝对准确;缺点是需要处理收据验证的逻辑,而且离线状态下没法获取收据
3. 后端服务器记录,数据更可控
如果你的应用有自己的后端,可以在用户首次打开应用时,把设备的合规标识(比如IDFA,记得要符合隐私政策)和当前日期传到服务器存起来
- 后续每次启动,先向服务器查询该设备对应的首次安装日期
- 优点是数据完全在你掌控中,不受客户端操作影响;缺点是需要后端支持,还要注意隐私合规,别踩Apple的红线
小补充:UserDefaults的兜底用法
要是你想先用UserDefaults快速实现,也可以结合Keychain做兜底:先查UserDefaults,没有的话再查Keychain,都没有就记录当前日期并同时存在两个地方——这样既能覆盖普通场景,又能解决卸载重装的问题
内容的提问来源于stack exchange,提问作者nontomatic




