【问题标题】:Detecting when app is becoming active from lockscreen vs other on iOS7检测应用程序何时从锁屏与 iOS7 上的其他应用程序变为活动状态
【发布时间】:2013-10-27 11:25:57
【问题描述】:

我的应用在从锁屏变为活动状态(活动时锁定)或从其他任何地方变为活动状态时具有不同的行为。

在 iOS 6 及更低版本上我可以检测到这一点

UIApplicationState state = [[UIApplication sharedApplication] applicationState];
if (UIApplicationStateInactive == state)
    // Coming from locked screen (iOS 6)
else
    // Coming from Springboard, another app, etc...

但在 iOS 7 上,两种情况下的状态值都是 UIApplicationStateBackground。这是预期的行为吗?如何正确检测应用程序现在是否从锁屏启动?

注册开发者,我已经在 NDA 取消之前在开发者论坛上发布了这个,请参阅 here

【问题讨论】:

  • 我不相信你能做到这一点。事实上,即使是在 iOS 6 上,你也在做出你不能随便做出的假设。例如,如果您被电话打断,应用程序状态也是UIApplicationStateInactive
  • 它实际上对我的用例来说非常可靠,直到 iOS 7。为了这个问题,我简化了代码。
  • 我想说的是,这段代码(在 iOS 6 中)可以可靠地检测到您何时来自锁定屏幕,但也可以检测到用户何时在电话后返回。如果您能够以某种方式区分这些事件,那就太好了(而且我实际上对如何区分这些事件很感兴趣,因为据我所知,这是/不可能的)。
  • 就我的目的而言,该应用程序处理这些情况的方式相同。我只对来自跳板的行为感兴趣

标签: ios cocoa-touch background multitasking uiapplicationdelegate


【解决方案1】:

我能够对此进行破解,到目前为止似乎是可靠的。它只能在设备上运行,不能在模拟器上运行,并且已经在运行 iOS 7 的 iPhone 5s、5 和 4S 上进行了测试。

在 iOS 7 上似乎无法检测应用程序的启动位置,但一种方法可以检测您是否要去锁屏与跳板。诀窍是在applicationDidEnterBackground 中读取屏幕亮度。当应用程序由于按下锁定按钮或自动锁定超时而进入后台时,iOS 7 上的亮度将为 0.0。否则,当按下主页按钮或从多任务选择器启动另一个应用程序时,亮度将 > 0或通知中心。

- (void)applicationDidEnterBackground:(UIApplication *)application {
    CGFloat screenBrightness = [[UIScreen mainScreen] brightness];
    NSLog(@"Screen brightness: %f", screenBrightness);
    self.backgroundedToLockScreen = screenBrightness <= 0.0;
}

现在我有一个保存此信息的 ivar,我可以在 applicationWillEnterForeground 中使用它来确定我的应用流程。

- (void)applicationWillEnterForeground:(UIApplication *)application {
    if (self.backgroundedToLockScreen) {
        ... // app was backgrounded to lock screen
    } else {
        ... // app was backgrounded on purpose by tapping the home button or switching apps.
    }
    self.backgroundedToLockScreen = NO;
}

但它与 iOS 6 的行为并不完全相同。在 iOS 6 上,您可以检查 UIApplicationState 以检测您来自哪里,这个解决方案回答了类似但不完全相同的问题,即应用程序后台运行时您要去哪里。例如,应用程序可能由于屏幕锁定超时而处于后台,但随后另一个应用程序的通知唤醒了设备,用户直接从锁定屏幕转到那里,然后返回我的应用程序。我的应用程序会在后台确定用户进入锁屏,但是当他们回来时,他们实际上来自活动屏幕。对于我的应用,这种差异可以忽略不计,但您的里程可能会有所不同。

那么旧操作系统支持呢?我的应用程序还支持 iOS 6,所以我也需要获得旧的行为。简单的。只是应用状态监控到前台方法:

- (void)applicationWillEnterForeground:(UIApplication *)application {
    UIApplicationState state = [[UIApplication sharedApplication] applicationState];
    if (UIApplicationStateInactive == state ||  // detect if coming from locked screen (iOS 6)
        self.backgroundedToLockScreen)          // detect if backgrounded to the locked screen (iOS 7)
    {
        ... // app is coming from or was backgrounded to lock screen
    } else {
        ... // app was backgrounded on purpose by tapping the home button or switching apps
    }
    self.backgroundedToLockScreen = NO;
}

我不确定亮度读数有多可靠,或者它是否会在未来的操作系统版本中发生变化,但与此同时,这个 hack 似乎是我们能得到的最好的。希望这会有所帮助。

【讨论】:

  • 感谢分享。我在 iOS 7.0 上使用 iPhone 5。当我按下锁定按钮时,我每次都会得到 0.9965 或关闭的读数。我想知道是否还有时间变量。在您读取亮度之前,您是否有很多代码被执行(因此允许屏幕前几毫秒变暗)......
  • 我不知道,但我几乎可以肯定这是一个竞争条件。我有一个伙伴实现了这一点,并添加了几毫秒的后台执行延迟以使其工作。在实施相同的延迟之前,我仍在等待 Apple 审查以从客户那里获得一些数据点(在生产中进行测试,耶!)
  • 所以我在一个空白项目上使用 NSTimer 进行了测试(以及选择器中的亮度读数),当我按下锁定按钮时仍然获得 1.0 的亮度。我用后台队列进行了测试,没有运气。一旦您对其他变量有更多了解,请更新我们。祝你审核顺利。
  • 我在带有 iOS 7.0.4 的 iPHone 5 上试过这个。不工作。 [ [UIScreen mainScreen] 亮度] 始终返回在设置-> 亮度上设置的值。我什至尝试在延迟 5 秒后调用此方法 - 结果相同。
【解决方案2】:

实际上,在激活时设置应用行为的唯一正确方法是通过应用委托方法。

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

这两个在应用程序在后台运行时调用,并通过多任务 UI 或在调用或其他中断后变为活动状态。

当应用程序从 Springboard 打开并且不在后台运行时,将调用此方法:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    return YES;
}

【讨论】:

  • applicationWillEnterForeground 是使用上述逻辑的地方,当来自 springboard 上的后台或应用程序在自动锁定超时后恢复时调用相同。问题与应用程序的来源(跳板或解锁)有关,这可以在 iOS 6 中检测到,而不是在 7 中(似乎)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多