后台状态后打开应用程序时出现黑屏



我的任务是调试为什么有些用户在打开应用程序时有时会遇到黑屏问题。我是这个特定应用程序的新手,所以我不知道整个流程,但我可以看出这个应用程序具有后台功能。有些任务是在晚上执行的。

当涉及到后台模式时,我很难理解iOS应用程序的整个生命周期。

当一个应用程序从终止状态在后台启动时,我假设didFinishLaunchingWithOptions仍然会被调用。我看到我们在代码中对此进行了一个小的检查,在这种情况下,它省略了整个UI初始化:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
/*{ Initial setup }*/
if UIApplication.shared.applicationState == .background {
// App was launched due to Background Fetch event. No need for UI.
return true
}
/*{ Start UI }*/
return true
}

我怀疑,当应用程序当前或最近在后台运行时,无论何时手动打开应用程序,该代码都会导致应用程序出现UI;系统"(从最初终止的状态)。这是正确的吗?这意味着在某些边缘情况下,人们打开应用程序时不会"打开";{启动UI}";永远被召唤。

我们还实现了applicationDidBecomeActive,我认为应该使用它来确保在这种情况下呈现UI。然而,现在这里只有一些可达性的东西:

func applicationDidBecomeActive(_ application: UIApplication) {
reachabilityManager?.startObserving()
}

我发现的大多数在线资源并没有具体显示应用程序是如何在后台启动的,比如这张图,在所有情况下总是转换到didBecomeActive

所以问题1;在didFinishLaunchingWithOptions中评估状态的最佳实践方法是什么?在.background的情况下,省略UI的当前实现是最优的吗?如果是,我是否应该执行检查以查看UI是否在didBecomeActive中运行,如果不是,则启动UI?

引出问题2;如果我们应该在didBecomeActive中加载UI,我们是否也应该卸载或取消分配didEnterBackground中的任何活动UI?

额外的问题:是否有可能用调试器真正复制这个?每次我用调试器启动应用程序时,它显然不在后台。如何调试从后台到前台的生命周期?

或者我可能完全偏离了目标,有时可能有不同的原因导致某些用户没有UI?

除了这里的注释之外,还有一种答案:

显然,我们不知道情况是否如此,但我想说你走在了正确的轨道上。根据你的描述,我认为会发生以下情况:

计划的任务启动应用程序,并且未生成任何UI。iOS没有太多事情要做,所以它决定让你的应用程序处于暂停模式,而不是在计划任务完成后完全终止它。我想说,这实际上是意料之中的事,因为只有当它真的缺乏资源时,它才会终止它(我假设一个挂起的应用程序几乎不需要任何东西,内存被交换到磁盘,没有CPU周期,那么为什么要完全终止它呢?)。

然后,在稍后的时间,用户点击应用程序,它就会被放在前台。由于CCD_ 9被挂起并且没有被终止;哦,不";没有构建UI。


因此,具体回答您的Q1(警告,固执己见!):

好吧,检查状态的最佳实践在您的实现中显然是可以的(if检查):基于状态构建UI不是的好做法。事实上;启动";在我看来,从代码本身构建UI是个坏主意,通常。Swift(UI)应用程序和UIKit&基于情节提要的应用程序可以做到这一点。我知道有些人喜欢";在代码中执行UI";,但我不同意。那些成功做到这一点的人通常并不意味着太过字面化,有很多人误解了这一点,并因此一行又一行地相互推诿。这会变得效率低下,所以像你这样的解决方案会突然出现;好吧,在后台任务中,我们必须快速,所以让我们把它骗出去吧",而正确的删除应该是"删除";也许我们对乏味的手动UI构建";。。。

那么,这对你有什么帮助(因为我想你不能仅仅为了修复这个bug而完全重做所有的UI内容)?不幸的是;这取决于";。我尝试的第一件事实际上只是省略了UI的状态检查,即无论应用程序是否从后台启动,都要构建它。希望在这个过程中没有任何东西真正需要应用程序在屏幕上可见才能成功完成。如果有效,那又怎样?当应用程序执行后台任务时,它会有一个尚未显示的UI,但那又怎样呢?不管怎样,一旦用户把它放到前台,它就会在以后使用。

如果这不起作用,那么尝试将UI构建移动到didBecomeActive中,同时进行一些检查以确保它不是";重建";在应用程序已经执行该代码的情况下。在您的团队中公开质疑整个UI方法可能是值得的。

关于问题2:

我想这是一件艰难而古怪的事情。。。

正如评论中所解释的,调试的技巧是让调试器为不是由Xcode启动的应用程序启动做好准备,而是由计划的BG任务启动。这意味着两件事:

  1. 您必须以某种方式将任务安排到未来或多或少已知的时间点。这很可能需要添加一些调试代码(除非你想熬夜完成夜间计划的实际任务……结果却错过了它)。只需在一分钟左右的时间内从didFinishLaunchingWithOptions中安排一个运行即可。现在,我知道你不能保证它在那时执行,但我现在看不到其他方法。我自己还没有试过,如果不起作用,呃。。。你可能运气不好(或者要等很长一段时间才能真正调用任务)
  2. 启动应用程序以安排任务,然后在目标时间过去之前立即再次终止应用程序
  3. 更改Xcode方案"运行-信息-启动";至";等待可执行文件被启动";。按下运行按钮。调试器现在等待应用程序通过其他方式启动。除非你自己点击图标,否则这将有望成为预定任务

顺便说一句,苹果有一个具体的方法来帮助你调试BG任务,但看起来它不会在安排应用程序和启动任务处理程序之间终止你的应用程序(所以didFinishLaunchingWithOptions不会以你需要的方式调用)。不过,你可能想自己调查一下(这个答案足够长了……很抱歉)。


更新因为我是个白痴:

虽然以上所有内容可能都很有用,但我有点忽略了您真正想要测试的内容:基于状态的UI设置是否是造成问题的原因。有一种方法可以通过";注入";通过启动参数的状态。您需要对didFinishLaunchingWithOptions实现进行最低限度的更改,并对应用程序方案进行一些改动,但它应该能做到:

  1. 给你的应用程序方案一个自定义的启动参数,例如"fakeBGState";。要执行此操作,请编辑方案,转到";Run-Arguments"并将该字符串添加到";Arguments Passed On Launch">
  2. didFinishLaunchingWithOptions中,将UI设置代码封装到
if ProcessInfo.processInfo.arguments.contains("fakeBGState") {
// ...
}

通过这种方式,您可以按照BG任务启动的方式启动,具体取决于启动参数。虽然这完全消除了操作系统为BG任务触发的实际启动,但它仍然足以让您弄清楚这种特定的启动流程会导致黑屏。

最后,如果你的应用程序也支持后台获取,你可以使用它通过Xcode触发应用程序从操作系统启动到后台模式。该方法与我在回答问题2时描述的方法类似,但您不安排任何任务。相反,您只需按照步骤3让调试器等待,然后在Xcode中选择";模拟背景提取";从"调试"菜单。也许这对你也有帮助,祝你好运!

最新更新