Обнаружение включения / выключения экрана из сервиса iOS

Я занимаюсь разработкой приложения для мониторинга сети, которое работает в фоновом режиме в качестве службы. Можно ли получить уведомление / звонок при включении или выключении экрана?

Он существует в Android с помощью следующего кода:

private void registerScreenOnOffReceiver()
{
   IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
   filter.addAction(Intent.ACTION_SCREEN_OFF);
   registerReceiver(screenOnOffReceiver, filter);
}

Затем вызывается screenOnOffReceiver, когда экран включается / выключается. Есть ли подобное решение для iOS?

Редактировать: лучшее, что я нашел на данный момент, это UIApplicationProtectedDataWillBecomeUnavailable ( определить, включен ли экран iPhone), но для этого требуется, чтобы пользователь включил защиту данных (защиту паролем) на устройстве.

3 ответа

Решение

Вы можете использовать уведомления Дарвина, чтобы прослушивать события. Я не уверен на 100%, но мне кажется, после запуска на взломанном iOS 5.0.1 iPhone 4, что одним из этих событий может быть то, что вам нужно:

com.apple.iokit.hid.displayStatus
com.apple.springboard.hasBlankedScreen
com.apple.springboard.lockstate

Обновление: также, следующее сообщение отправляется, когда телефон блокируется (но не когда он разблокируется):

com.apple.springboard.lockcomplete

Чтобы использовать это, зарегистрируйтесь для такого события (это регистрируется только для одного события, но если это не работает для вас, попробуйте другие):

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                NULL, // observer
                                displayStatusChanged, // callback
                                CFSTR("com.apple.iokit.hid.displayStatus"), // event name
                                NULL, // object
                                CFNotificationSuspensionBehaviorDeliverImmediately);

где displayStatusChanged Ваш обратный вызов события:

static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
    NSLog(@"event received!");
    // you might try inspecting the `userInfo` dictionary, to see 
    //  if it contains any useful info
    if (userInfo != nil) {
        CFShow(userInfo);
    }
}

Если вы действительно хотите, чтобы этот код выполнялся в фоновом режиме как служба, и вы взломаны, я бы порекомендовал изучить демоны запуска iOS. В отличие от приложения, которое вы просто запускаете в фоновом режиме, демон запуска может запускаться автоматически после перезагрузки, и вам не нужно беспокоиться о правилах iOS для приложений, выполняющих задачи в фоновом режиме.

Дайте нам знать, как это работает!

Используя низкоуровневый API уведомлений, вы можете запросить состояние блокировки при получении уведомления:

#import <notify.h>

int notify_token;
notify_register_dispatch("com.apple.springboard.lockstate", &notify_token, dispatch_get_main_queue(), ^(int token) {
    uint64_t state = UINT64_MAX;
    notify_get_state(token, &state);
    NSLog(@"com.apple.springboard.lockstate = %llu", state);
});

Конечно, ваше приложение должно будет запустить UIBackgroundTask для получения уведомлений, что ограничивает полезность этой техники из-за ограниченного времени выполнения, разрешенного iOS.

Пока экран iPhone заблокирован appdelegate, будет вызван метод "- (void)applicationWillResignActive:(UIApplication *)application", это можно проверить. Надеюсь, это поможет вам.

Другие вопросы по тегам