Блокировка разблокировать события iphone

Как я могу обнаружить события блокировки / разблокировки на iPhone? Предполагая, что это возможно только для взломанных устройств, вы можете указать мне правильный API?

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

10 ответов

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

com.apple.springboard.lockstate
com.apple.springboard.lockcomplete

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

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

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                (void*)self, // observer (can be NULL)
                                lockStateChanged, // callback
                                CFSTR("com.apple.springboard.lockstate"), // event name
                                NULL, // object
                                CFNotificationSuspensionBehaviorDeliverImmediately);

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

static void lockStateChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
    NSLog(@"event received!");
    if (observer != NULL) {
        MyClass *this = (MyClass*)observer;
    }

    // you might try inspecting the `userInfo` dictionary, to see 
    //  if it contains any useful info
    if (userInfo != nil) {
        CFShow(userInfo);
    }
}

lockstate событие происходит, когда устройство заблокировано и разблокировано, но lockcomplete событие срабатывает только при блокировке устройства. Другой способ определить, относится ли событие к событию блокировки или разблокировки, заключается в использовании notify_get_state(), Вы получите другое значение для блокировки против разблокировки, как описано здесь.

Раунд об ответе:

Приложение будет автоматически подавать в отставку, его будут вызывать во всех сценариях... и из всех моих тестов, даже если ваше приложение не спит, находясь в фоновом режиме, нет никаких способов определить, что экран заблокирован (скорость процессора не отображается, скорость шины остается тем же, число_члена / число не изменяется)...

Тем не менее, кажется, что Apple действительно выключает акселерометр, когда устройство заблокировано... Включить акселерометр iPhone, когда экран заблокирован(такое поведение протестировано на iOS4.2 на iPhone 4)

Таким образом,...

В вашем приложении делегат:

- (void)applicationWillResignActive:(UIApplication *)application
{
    NSLog(@"STATUS - Application will Resign Active");
    // Start checking the accelerometer (while we are in the background)
    [[UIAccelerometer sharedAccelerometer] setDelegate:self];
    [[UIAccelerometer sharedAccelerometer] setUpdateInterval:1]; // Ping every second
    _notActiveTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(deviceDidLock) userInfo:nil repeats:NO]; // 2 seconds for wiggle

}
//Deprecated in iOS5
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
    NSLog(@"STATUS - Update from accelerometer");
    [_notActiveTimer invalidate];
    _notActiveTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(deviceDidLock) userInfo:nil repeats:NO];
}

- (void)deviceDidLock
{
    NSLog(@"STATUS - Device locked!");
    [[UIAccelerometer sharedAccelerometer] setDelegate:nil];
    _notActiveTimer = nil;
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSLog(@"STATUS - Application did become active");
    [[UIAccelerometer sharedAccelerometer] setDelegate:nil];
    [_notActiveTimer invalidate];
    _notActiveTimer = nil;
}

Я знаю... Это что-то вроде хака, но до сих пор это работало для меня как обаяние. Пожалуйста, обновите, если вы видите какие-либо проблемы, которые мешают этому работать.

На момент написания статьи существует два достаточно надежных способа обнаружения блокировки устройства:


Защита данных

Включив разрешение Data Protection, ваше приложение может подписаться на applicationProtectedDataWillBecomeUnavailable: а также applicationProtectedDataDidBecomeAvailable: уведомления для определения с высокой вероятностью, когда устройство, которое использует пароль / аутентификацию TouchID, заблокировано / разблокировано. Чтобы определить, использует ли устройство код доступа /TouchID LAContext можно запросить.

Предостережения: этот метод основан на том, что "защищенные данные становятся недоступными", совпадающими с блокировкой телефона. Когда телефон использует TouchID и нажата кнопка "Режим сна" / "Блокировка", телефон блокируется, защищенные данные становятся недоступными, и для его разблокировки немедленно потребуется пароль. Это означает, что защищенные данные, становящиеся недоступными, по существу указывают, что телефон был заблокирован. Это не обязательно верно, когда кто-то использует только пароль, так как он может установить время "требуется пароль" в любом месте от немедленного до примерно 4 часов. В этом случае телефон сообщит о возможности обработки защищенных данных, но блокировка телефона не приведет к тому, что защищенные данные станут недоступными в течение некоторого времени.


Сроки жизненного цикла

Если ваше приложение находится на переднем плане, между двумя событиями жизненного цикла произойдет заметное изменение во времени UIApplicationWillResignActiveNotification а также UIApplicationDidEnterBackgroundNotification в зависимости от того, что вызывает их.

(Это было протестировано в iOS 10 и может измениться в будущих выпусках)

Нажатие кнопки "домой" приводит к значительной задержке между ними (даже если включена настройка "Уменьшенное движение"):

15:23:42.517 willResignActive
15:23:43.182 didEnterBackground
15:23:43.184 difference: 0.666346

Блокировка устройства при открытом приложении создает более тривиальную (<~ 0,2 с) задержку между двумя событиями:

15:22:59.236 willResignActive
15:22:59.267 didEnterBackground
15:22:59.267 difference: 0.031404

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

Когда приложение переходит в фоновый режим, делегату приложения сначала отправляется applicationWillResignActive:затем applicationDidEnterBackground:, Когда приложение прерывается нажатием кнопки блокировки или входящим телефонным звонком, последний метод не вызывается. Мы можем использовать эту информацию, чтобы различать два сценария.

Скажем, вы хотите, чтобы вам перезвонили в screenLockActivated метод, если экран заблокирован. Вот волшебство:

- (void)applicationWillResignActive:(UIApplication*)aApplication
{
    [self performSelector:@selector(screenLockActivated)
               withObject:nil
               afterDelay:0];
}

- (void)applicationDidEnterBackground:(UIApplication*)aApplication
{
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
}

- (void)screenLockActivated
{
    NSLog(@"yaay");
}

Объяснение:

По умолчанию мы предполагаем, что каждый вызов applicationWillResignActive: происходит из-за активного-> неактивного перехода состояния (как при блокировке экрана), но мы щедро позволяем системе доказать обратное в течение тайм-аута (в данном случае, одного цикла выполнения цикла), задерживая вызов screenLockActivated, Если экран заблокирован, система завершает текущий цикл выполнения цикла, не затрагивая другие методы делегата. Если, однако, это активный-> фоновый переход состояния, он также вызывает applicationDidEnterBackground: до конца цикла, что позволяет нам просто отменить ранее запланированный запрос оттуда, тем самым предотвращая его вызов, когда он не должен.

Наслаждайтесь!

В iOS 8 вы блокируете экран или нажимаете кнопку "Домой", все они заставляют приложение работать в фоновом режиме, но вы не знаете, какой оператор приведет к этому. Мое решение то же самое с Nits007ak, используйте notify_register_dispatch, чтобы получить состояние.

#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);
                                 if(state == 0) {
                                     NSLog(@"unlock device");
                                 } else {
                                     NSLog(@"lock device");
                                 }
                             }
                             );

Пока приложение работает, на переднем плане или в фоновом режиме. не приостановить, вы можете получить это событие.

И вы можете использовать notify_token в качестве параметра notify_get_state, чтобы получить текущее состояние в любом месте, это полезно, когда вы хотите знать состояние и состояние экрана не меняется.

Если установлен пароль, вы можете использовать эти события в AppDelegate

-(void)applicationProtectedDataWillBecomeUnavailable:(UIApplication *)application
{
}

- (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application
{
}

Просто импортируйте #import notify.h перед использованием этого кода. наслаждаться!!

-(void)registerAppforDetectLockState {

    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);

        if(state == 0) {
            NSLog(@"unlock device");
        } else {
            NSLog(@"lock device");
        }

        NSLog(@"com.apple.springboard.lockstate = %llu", state);
        UILocalNotification *notification = [[UILocalNotification alloc]init];
        notification.repeatInterval = NSDayCalendarUnit;
        [notification setAlertBody:@"Hello world!! I come becoz you lock/unlock your device :)"];
        notification.alertAction = @"View";
        notification.alertAction = @"Yes";
        [notification setFireDate:[NSDate dateWithTimeIntervalSinceNow:1]];
        notification.soundName = UILocalNotificationDefaultSoundName;
        [notification setTimeZone:[NSTimeZone  defaultTimeZone]];

        [[UIApplication sharedApplication] presentLocalNotificationNow:notification];

    });
}

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

// call back
void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
    // notification comes in order of
    // "com.apple.springboard.hasBlankedScreen" notification
    // "com.apple.springboard.lockcomplete" notification only if locked
    // "com.apple.springboard.lockstate" notification

    AppDelegate *appDelegate = CFBridgingRelease(observer);

    NSString *eventName = (__bridge NSString*)name;
    NSLog(@"Darwin notification NAME = %@",name);

    if([eventName isEqualToString:@"com.apple.springboard.hasBlankedScreen"])
    {
        NSLog(@"SCREEN BLANK");

        appDelegate.bDeviceLocked = false; // clear
    }
    else if([eventName isEqualToString:@"com.apple.springboard.lockcomplete"])
    {
        NSLog(@"DEVICE LOCK");

        appDelegate.bDeviceLocked = true; // set
    }
    else if([eventName isEqualToString:@"com.apple.springboard.lockstate"])
    {
        NSLog(@"LOCK STATUS CHANGE");

        if(appDelegate.bDeviceLocked) // if a lock, is set
        {
            NSLog(@"DEVICE IS LOCKED");
        }
        else
        {
            NSLog(@"DEVICE IS UNLOCKED");
        }
    }
}

-(void)registerforDeviceLockNotif
{
    // screen and lock notifications
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                    CFBridgingRetain(self), // observer
                                    displayStatusChanged, // callback
                                    CFSTR("com.apple.springboard.hasBlankedScreen"), // event name
                                    NULL, // object
                                    CFNotificationSuspensionBehaviorDeliverImmediately);

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                    CFBridgingRetain(self), // observer
                                    displayStatusChanged, // callback
                                    CFSTR("com.apple.springboard.lockcomplete"), // event name
                                    NULL, // object
                                    CFNotificationSuspensionBehaviorDeliverImmediately);

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                    CFBridgingRetain(self), // observer
                                    displayStatusChanged, // callback
                                    CFSTR("com.apple.springboard.lockstate"), // event name
                                    NULL, // object
                                    CFNotificationSuspensionBehaviorDeliverImmediately);
}

Чтобы индикаторы блокировки экрана работали в фоновом режиме, вам нужно реализовать фоновую обработку, вызывающую следующее при запуске приложения.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.backgroundTaskIdentifier =
    [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{

        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];
    }];

    [self registerforDeviceLockNotif];
}

Если ваше приложение работает, и пользователь блокирует устройство, ваш делегат приложения получит вызов "приложение будет отставать активным:". Если ваше приложение было запущено в заблокированном состоянии, оно получит вызов "Приложение стало активным:", когда устройство разблокировано. Но вы получаете те же звонки на ваше приложение, если пользователь получает телефонный звонок, а затем решает игнорировать его. Насколько я знаю, вы не можете понять разницу.

И если ваше приложение не было запущено ни в одно из этих времен, нет способа получить уведомление, так как ваше приложение не запущено.

Самый простой способ получить события блокировки и разблокировки экрана - добавить наблюдателей событий, используя NSNotificationCenter в вашем viewcontroller. Я добавил следующий наблюдатель в метод viewdidload. Вот что я сделал:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(applicationEnteredForeground:)
                                             name:UIApplicationWillEnterForegroundNotification
                                           object:nil];

Затем я добавил следующий селектор в viewcontroller. Этот селектор будет вызываться, когда экран разблокирован.

 - (void)applicationEnteredForeground:(NSNotification *)notification {
    NSLog(@"Application Entered Foreground");
    }

Если вы хотите обнаружить событие, когда экран заблокирован, вы можете заменить UIApplicationWillEnterForegroundNotification на UIApplicationDidEnterBackgroundNotification.

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