在 iOS 15 公开推出后, 我们开始从用户端收到反馈报告:在打开我们的应用程序(Cookpad) 时他们被莫名其妙的反复退出到登录页。非常令人惊讶的是,这并不是我们在测试 iOS 15 beta 版的时候发现的问题。

如果你是来找修复方法的,那就直接向下滚动到结论,但如果你想了解更多关于我们如何调试这个特定问题,那就开始吧。

复现反馈的问题

用户报告中的具体信息有限,我们唯一知道的是:从 iOS 15 开始,用户打开程序后会发现自己已经退出登录。

我们没有视频,也没有具体的步骤来重现这个问题,所以我努力尝试以各种方式启动应用程序,希望能亲眼看到它。我试着重新安装应用程序,我试着在有网络连接和没有网络连接的情况下启动,我试着强制退出,经过30分钟的努力,我放弃了,我开始回复用户说我没找到具体问题。

直到我再次解锁手机,没有做任何操作,就启动了 Cookpad,我发现APP就像我们的用户所反馈的那样,直接退出到了登录界面!

在那之后,我无法准确的复现该问题,但似乎与暂停使用手机一段时间后再次使用它有关。

缩小问题范围

我担心从 Xcode 重新安装应用程序可能会影响问题的复现,所以在这样做之前,是时候查看代码并试图缩小问题的范围。根据我们的实现,我想出了三个潜在的原因。

  • 1、UserDefaults 中的数据被清除。
  • 2、一个意外的API调用返回HTTP 401并触发退出登录。
  • 3、Keychain 抛出了一个错误。

我能够排除前两个潜在的原因,这要归功于我在自己重现该问题后观察到的一些微妙行为。

  • 登录界面没有要求我选择地区——这表明UserDefaults中的数据没有问题,因为我们的 "已显示地区选择 "偏好设置仍然生效。
  • 主用户界面没有显示,即使是短暂的也没有——这表明没有尝试进行网络请求,所以 API 是问题原因可能还为时过早。

这就把Keychain留给了我们,指引我进入下一个问题。是什么发生了改变以及为什么它如此难以复现?

是什么发生了改变以及为什么它如此难以复现?

我粗略地看了一下发布说明,在谷歌上快速搜索了一下,我找不到任何东西,所以我不得不继续挖掘以更好地了解这个问题。

Keychain数据的访问是通过 Security 框架提供的,这是一个众所周知的棘手的问题。虽然有很多第三方库来包装这个框架以使事情变得更容易,但我们还是基于一些苹果的示例代码来维护我们自己的简单封装。

看一下这段代码,我们调用 SecItemCopyMatching 方法来加载我们的访问令牌,它返回数据以及描述结果的 OSStatus 代码。然而,不幸的是,虽然我们的封装器会将不成功的结果与状态代码一起抛出,用于调试,但我们在下一层中却抛弃了这些信息,只是将错误视为 nil

我们实行了每周一次的发布计划,多亏了大量的自动化。此时,我们即将发布的下一个截止点(代码冻结)是在第二天。因为我们还没有完全了解这个问题有多普遍,而且我们也不确定是否能够在代码冻结前发布一个修复程序,所以我利用这个机会通过使用Crashlytics(崩溃日志记录工具) 增加一些额外的非致命性日志来解决缺乏可观察性的问题。

这个结果给了我们一些很好的观察点,然后我们可以在接下来的几周内观察。

此时,我能够捕捉到返回的确切错误代码。罪魁祸首是errSecInteractionNotAllowed:

不允许与 Security Server 交互。

这个错误告诉我们,我们正试图在数据不可用的时间点上从Keychain中读取数据。这通常会发生在你试图读取已存储的数据,并将其可访问性设置为kSecAttrAccessibleWhenUnlocked,而设备仍处于锁定状态。

现在这完全说得通了,但唯一的问题是,在 Cookpad 中,我们只在应用启动时从Keychain中读取信息,而我的假设是,用户一定是点击了应用图标来启动应用,因此设备在这时应该总是解锁的,对吗?

那么,究竟发生了什么变化呢?即使我能够重现这个问题,我也100%确定我的手机在我点击应用图标的时候是解锁的,所以我不明白为什么会出现这个Keychain错误。

我决心找到原因,用一个调试工具替换了我们的应用程序的实现,该工具将尝试并记录其生命周期中不同节点的Keychain读取。

在能够复现问题的场景中,我观察到以下结果:

  • main.swift — 失败 (errSecInteractionNotAllowed)
  • AppDelegate.init() — 失败 (errSecInteractionNotAllowed)
  • AppDelegate.applicationProtectedDataDidBecomeAvailable(_:)
    — 成功
  • AppDelegate.application(_:didFinishLaunchingWithOptions:) — 成功
  • ViewController.viewDidAppear(_:) — 成功

所以这(一半)解释了它。为了避免在我们的AppDelegate上持有一些隐式解包的可选属性,我们在init()方法中进行了一些设置,其中一部分涉及从Keychain中读取访问令牌。这就是为什么读取会失败,以及最终为什么一些用户会发现自己被登出了。

我在这里学到了重要的一课,即我不应该假设受保护的数据在AppDelegate初始化时是可用的,但说实话,我还是不高兴,因为我不明白为什么它不可用。毕竟,我们已经很多年没有改变过这部分代码了,而且它在iOS 12、13和14系统中一直运行良好,那么是什么原因呢?

寻找根本原因

我的调试界面很有用,但它缺少了一些有助于回答所有问题的重要信息:时间

我知道在AppDelegate.application(_:didFinishLaunchingWithOptions:)之前,“受保护的数据” 是不可用的,但它仍然没有意义,因为为了重现这个问题,我正在执行以下操作:

1、启动应用程序
2、简单使用
3、强制退出应用
4、锁定我的设备并将其放置约 30 分钟
5、解锁设备
6、再次启动应用

每当我在第 6 步中再次启动应用程序时,我 100% 确定设备已解锁,因此我坚信我应该能够从 AppDelegate.init()中的Keychain读取数据。

直到我看了所有这些步骤的时间,事情才开始变得有点意义。

再次仔细查看时间戳:

  • main.swift — 11:38:47
  • AppDelegate.init() — 11:38:47
  • AppDelegate.application(_:didFinishLaunchingWithOptions:) — 12:03:04
  • ViewController.viewDidAppear(_:) — 12:03:04

在我真正解锁手机并点击应用图标之前的25分钟,应用程序本身就已经启动了!

现在,我实际上从未想过有这么大的延迟,实际上是@_saagarjha建议我检查时间戳,之后,他指给我看这条推特。

推特翻译:
有趣的iOS 15优化。Duet 现在试图先发制人地 “预热” 第三方应用程序,在你点击一个应用程序图标前几分钟,通过dyld和预主静态初始化器运行它们。然后,该应用程序被暂停,随后的 "启动"似乎更快。

现在一切都说得通了。我们最初没有测试到它,因为我们很可能没有给 iOS 15 beta 版足够的时间来 “学习” 我们的使用习惯,所以这个问题只在现实世界的场景中再现,即设备认为我很快就要启动应用程序。我仍然不知道这种预测是如何形成的,但我只想把它归结为 “Siri智能”,然后就到此为止了。

结论

从iOS 15开始,系统可能决定在用户实际尝试打开你的应用程序之前对其进行 “预热”,这可能会增加受保护的数据在你认为应该无法使用的时候的被访问概率。

通过等待application(_:didFinishLaunchingWithOptions:)委托回调来保护自己,如果可能的话,留意UIApplication.isProtectedDataAvailable(或对应委托的回调/通知)并相应处理。

我们仍然发现了非常少的非致命问题,在application(_:didFinishLaunchingWithOptions:)中报告isProtectedDataAvailablefalse,在我们可以推迟从钥匙串阅读的访问令牌之外,这将是一个大规模的任务,现在它不值得进行进一步调查。

这是一个相当难调试的bug,而且行为的变化似乎完全没有记录,这对我来说真的没有帮助。如果你也被这个问题所困扰,请考虑复制FB9780579。

我从中学到了很多东西,我希望你也一样!

更新: 自从发表这篇文章以来,实际上很多人都向我指出了苹果公司关于预热行为的相对完善的文档。然而,其他人也告诉我,他们仍然观察到与某些场景中记录的行为不同的行为,因此请谨慎行事。

译自:Solving Mysterious Logout Issues on iOS 15

关于我们

Swift社区是由 Swift 爱好者共同维护的公益组织,我们在国内以微信公众号的运营为主,我们会分享以 Swift实战SwiftUlSwift基础为核心的技术内容,也整理收集优秀的学习资料。

解决 iOS 15 上 APP 莫名其妙地退出登录相关推荐

  1. exif.js解决ios手机上传照片后显示为旋转90度问题(兼容ios13.4之前的版本 )

    exif.js解决ios手机上传照片后显示为旋转90度问题(兼容ios13.4 ) 问题描述: 在做手机移动端app时,发现iOS12.5.1版本(iphone6)上传照片出现顺时针旋转90问题,ip ...

  2. 如何让iOS设备上App定时执行后台任务(上)

    功能需求 很多情况下,我们希望自己的App可以每小时或每天的特定时间在 iPhone 或 iPad 自动执行后台任务,比如:后台定时下载新数据或清理CoreData数据库等. 移动设备不像PC或服务器 ...

  3. 微信JSSDK多图片上传并且解决IOS系统上传一直加载的问题

    微信JSSDK多图片上传并且解决IOS系统上传一直加载的问题 参考文章: (1)微信JSSDK多图片上传并且解决IOS系统上传一直加载的问题 (2)https://www.cnblogs.com/co ...

  4. HTML实现点击时的阴影(:active)(已解决iOS微信上无法使用)

    一般是用这个委类:active 参考:http://www.w3school.com.cn/cssref/selector_active.asp 但是业界上实现的效果中,今日头条的手机端网页却不是这样 ...

  5. iOS线上APP崩溃(Crash)分析

    这两周一直在研究如何追踪线上的bug,如何快速分析出程序到底崩溃在什么地方,从底层了解Crash是如何产生的.如何传递的.以及是如何分析出来的.虽然项目组并没有对这些要求很严格,但是作为一个高级开发人 ...

  6. 解决iOS开发中App启动广告的功能

    前不久有朋友需要一个启动广告的功能,我说网上有挺多的,他说,看的不是很理想.想让我写一个,于是乎,抽空写了一个,代码通俗易懂,简单的封装了一下,各种事件用block回调的,有俩种样式的广告,一种是全屏 ...

  7. iPhone升级iOS 15后无法正常开机,怎么解决?

    iOS 15更新为苹果用户带来了许多新功能.但是,不少用户反馈,他们的iPhone在iOS 15更新后无法正常开机使用. 不用担心,今天小编就来给大家分享一些iOS 15更新后iPhone无法开机时可 ...

  8. 苹果退款网页一直显示服务器,iOS 15 新增退款入口,在应用内即可退款~

    果粉之家,专业苹果手机技术研究十年!您身边的苹果专家~ 在今年WWDC21开发者大会上,苹果在介绍iOS 15系统重大变化时,还曾提到一个不太引人注目的小变化.那就是在iOS 15上,用户可以直接在A ...

  9. 升级iOS 15后iPhone相机无法正常使用怎么办?

    iOS 15发布已经有一段时间了,相信不少果粉已经将设备更新到iOS 15.升级iOS 15后,iPhone相机是否无法正常工作? 如果你遇到相机无法正常打开.在加载时显示黑屏.镜头模糊或应用闪退等问 ...

最新文章

  1. 【转】一个Java程序员应该掌握的10项技能
  2. 干掉状态:从session到token
  3. 如何用excel筛选相似内容_Excel筛选你用好了么?别再下拉点点点了
  4. 计算机七年级书籍段落,七年级下册片段.doc
  5. php 删除相对应的id,PHP 在下面这个留言板代码中加入删除按钮,每一个删除按钮删除相对应一行数据,这怎么弄...
  6. 怎样才能在前端职场中拥有更强的竞争力?
  7. 企业落地Kubernetes的问题与对策
  8. LVDS 屏 format
  9. python扫雷游戏代码_基于Python实现的扫雷游戏实例代码
  10. Python模块selenium实例:电影分类排名数据生成json,sqlite和excel(openpyxl)文件(二)
  11. 层叠上下文(stacking context)
  12. Win10笔记本开热点供移动端连接后电脑无法连网
  13. 31:几何算法--点集的凸包
  14. htcm7刷linux,htc one m7刷官方zip包的教程
  15. 注意力机制学习 BAM
  16. 什么是冷备份和热备份
  17. NTC热敏电阻计算温度之C代码
  18. C#:实现字数统计函数算法(附完整源码)
  19. linux 网卡绑定team和删除team
  20. PHP编程与系统开发

热门文章

  1. matlab之保存和读取mat文件
  2. 高通骁龙处理器排行榜_一加9系列手机将于明年3月发布 搭载高通骁龙875处理器...
  3. python-urllib模块【下载图片】
  4. html显示柱形图,07完整的柱形图.html
  5. 策略模式和工厂模式给开发人员带来了哪些好处
  6. 计算机屏幕出现GT,传奇亮机卡GT710又诈尸?这次居然可同时带16个显示器
  7. 智链万源CEO董宁:企业数字化建设迫在眉睫 | 链人物
  8. java fileinputstream_java – 需要将AssetInputStream转换为FileInputStream
  9. lol服务器维护8月6日,LOL云顶之弈8月6日更新维护公告 10.16新版本更新内容汇总...
  10. 华夏银行软件测试,华夏银行测试信息管理系统项目