Обнаружение, когда приложение становится активным с lockscreen vs other на iOS7

У моего приложения другое поведение, когда он активируется с заблокированного экрана (заблокирован в активном состоянии) или становится активным из всего остального.

На 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 в обоих сценариях. Это предполагаемое поведение? Как я могу правильно определить, запускается ли приложение с экрана блокировки сейчас?

Зарегистрированные разработчики, я уже разместил это на devforums до отмены NDA, см. здесь

Ответ 1

Я смог разобраться с этим и пока что кажется надежным. Он работает только на устройстве, а не на симуляторе, и был протестирован на iPhone 5, 5 и 4S под управлением iOS 7.

Похоже, что нет способа определить, где приложение запускается с iOS 7, но есть способ определить, собираетесь ли вы на экран блокировки и трамплина. Хитрость заключается в считывании яркости экрана в applicationDidEnterBackground. Когда приложение попадает в фоновое изображение из-за нажатия кнопки блокировки или таймаута автоматической блокировки, яркость будет равна 0.0 на iOS 7. В противном случае это будет > 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;
}

Я не уверен, насколько надежным является чтение яркости, или будет ли он изменяться в будущих версиях ОС, но в то же время этот взлом кажется лучшим, что мы можем получить. Надеюсь, это поможет.

Ответ 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.
}

Эти два вызываются, когда приложение работает в фоновом режиме и активируется либо через многозадачный интерфейс, либо после вызова или другого прерывания.

Когда приложение открыто из Springboard и не работает в фоновом режиме, этот метод вызывается:

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