Verrouiller Déverrouiller les événements de l'iphone

Comment puis-je détecter des événements de verrouillage/déverrouillage sur l'iPhone? En supposant que ce ne soit possible que pour les appareils jailbroken, pouvez-vous m'indiquer la bonne API?

par événements de verrouillage , je veux dire afficher ou cacher l'écran de verrouillage (qui pourrait avoir besoin d'un mot de passe pour déverrouiller, ou non).

29
demandé sur Nate 2009-04-01 20:29:23

10 réponses

vous pouvez utiliser notifications Darwin , pour écouter les événements. De mes essais sur un jailbroken iOS 5.0.1 iPhone 4, je pense que l'un de ces événements pourrait être ce dont vous avez besoin:

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

Note: selon les commentaires de l'affiche à une question similaire j'ai répondu ici , cela devrait fonctionner sur un téléphone non-jailbroken, aussi.

pour utiliser cette, inscrivez-vous à la événement comme celui-ci (il enregistre pour le premier cas ci-dessus, mais vous pouvez ajouter un observateur pour lockcomplete ):

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

lockStateChanged est votre rappel d'événement:

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

l'événement lockstate se produit lorsque l'appareil est verrouillé et déverrouillé, mais l'événement lockcomplete ne se déclenche que lorsque l'appareil se verrouille. Une autre façon de déterminer si l'événement est pour verrouiller ou déverrouiller l'événement est d'utiliser notify_get_state() . Vous obtiendrez une valeur différente pour verrouiller vs déverrouiller, comme décrit ici .

19
répondu Nate 2017-05-23 11:47:05

tout autour de réponse:

Application va démissionner active obtient appelé dans toutes sortes de scénarios... et de tous mes tests, même si votre application reste éveillée pendant le background, il n'y a aucun moyen de déterminer que l'écran est verrouillé (la vitesse CPU ne signale pas, la vitesse du BUS reste la même, mach_time denom / numer ne change pas)...

Cependant, il semble qu'Apple n'désactiver l'accéléromètre lorsque l'appareil est verrouillé... Activer l'accéléromètre iPhone pendant que l'écran est verrouillé (testé iOS4.2 sur iPhone 4 A ce comportement)

ainsi...

dans votre demande délégué:

- (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;
}

je sais... C'est une sorte de hack, mais il a fonctionné comme un charme pour moi jusqu'à présent. Veuillez mettre à jour si vous voyez des problèmes qui empêchent ce travail.

15
répondu BadPirate 2017-05-23 12:34:21

il y a une façon plus jolie de distinguer les appels de commutation de tâches et de verrouillage d'écran applicationWillResignActive: qui n'impliquent même pas des caractéristiques non documentées telles que l'état de l'accéléromètre.

Lorsque l'application passe en arrière-plan, le délégué d'application est d'abord envoyé un applicationWillResignActive: , puis un applicationDidEnterBackground: . Lorsque l'application est interrompue en appuyant sur le bouton de Verrouillage ou par un appel téléphonique entrant, cette dernière méthode n'est pas appelée. Nous pouvons utiliser cette information pour la distinction entre les deux scénarios.

Dites que vous voulez être rappelé dans la screenLockActivated méthode si l'écran est verrouillé. Voici la magie:

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

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

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

explication:

par défaut, nous supposons que chaque appel à applicationWillResignActive: est en raison d'une transition d'état actif->inactif (comme lors du verrouillage de l'écran), mais nous laissons généreusement le système prouver le contraire dans un délai d'expiration (dans ce cas, un cycle d'exécution simple) par retard de l'appel à screenLockActivated . En cas de verrouillage de l'écran, le système termine le cycle d'exécution courant sans toucher à aucune autre méthode déléguée. Si, par contre, il s'agit d'une transition d'état active->background, elle invoque aussi applicationDidEnterBackground: avant la fin du cycle, ce qui nous permet simplement d'annuler la requête programmée précédemment de là, l'empêchant ainsi d'être appelée alors qu'elle n'est pas supposée l'être.

Profitez-en!

7
répondu Lvsti 2012-01-22 22:43:21

il suffit d'Importer #Importer notifier.h avant d'utiliser ce code. profitez-en!!

-(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];

    });
}
4
répondu Nits007ak 2015-04-13 10:11:48

au moment de la rédaction du présent document, il existe deux moyens assez fiables de détecter le verrouillage des dispositifs:


Protection Des Données

en activant le droit à la Protection des données votre application peut souscrire aux notifications applicationProtectedDataWillBecomeUnavailable: et applicationProtectedDataDidBecomeAvailable: pour déterminer avec une forte probabilité quand un dispositif qui utilise l'authentification passcode/TouchID est verrouillé/déverrouillé. Pour déterminer si un appareil utilise un mot de passe/TouchID LAContext peut être interrogé.

mises en garde : cette méthode repose sur la "non-disponibilité des données protégées" qui coïncide avec le verrouillage du téléphone. Lorsque le téléphone utilise TouchID et que le bouton sleep/lock est enfoncé, le téléphone est verrouillé, les données protégées ne sont plus disponibles, et un code d'accès sera immédiatement nécessaire pour le déverrouiller à nouveau. Cela signifie que les données protégées deviennent indisponibles indique essentiellement que le téléphone a été verrouillé. ce n'est pas nécessairement vrai quand quelqu'un utilise juste un mot de passe car ils peuvent définir le" requires passcode "time to anywhere de immédiatement à quelque chose comme 4 heures . Dans ce cas, le téléphone déclarera être en mesure de traiter des données protégées, mais verrouiller le téléphone n'entraînera pas de données protégées devenant indisponible pour assez un certain temps.


Cycle De Vie

si votre application est au premier plan, il y aura un changement notable dans le décalage horaire entre les deux événements du cycle de vie UIApplicationWillResignActiveNotification et UIApplicationDidEnterBackgroundNotification selon ce qui les déclenche.

(cela a été testé dans iOS 10 et peut changer dans les versions futures)

appuyer sur le bouton d'accueil entraîne un délai important entre les deux (même lorsque le réglage de mouvement réduit est activé):

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

le verrouillage du dispositif pendant que l'application est ouverte crée un délai plus trivial (<~0.2 s) entre les deux événements:

15:22:59.236 willResignActive
15:22:59.267 didEnterBackground
15:22:59.267 difference: 0.031404
4
répondu Warpling 2018-08-20 17:09:01

dans iOS 8, vous verrouillez l'écran ou appuyez sur le bouton d'accueil, tous ces faire APP push en arrière-plan, mais vous ne savez pas quel opérateur résultat dans ce. Ma solution est la même avec Nits007ak,utilisez notify_register_dispatch pour obtenir l'état.

#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");
                                 }
                             }
                             );

aussi longtemps que l'application est en cours d'exécution, en premier plan ou en arrière plan. ne pas suspendre, vous pouvez obtenir cet événement.

et vous pouvez utiliser notify_token comme paramètre de notify_get_state pour obtenir l'état actuel n'importe où, ceci est utile quand vous voulez savoir l'état et l'état de l'écran ne changent pas.

3
répondu david 2015-05-19 03:07:30

si passcode est défini, vous pouvez utiliser ces événements dans AppDelegate

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

- (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application
{
}
2
répondu Eyal 2014-07-03 11:12:22

si votre application est en cours d'exécution et que l'utilisateur bloque l'appareil, votre délégué d'application recevra un appel à 'application démissionnera Active:'. Si votre application était en cours d'exécution lorsque verrouillé, il recevra un appel à 'application Did Become Active:' lorsque l'appareil est déverrouillé. Mais vous obtenez les mêmes appels de votre application si l'utilisateur reçoit un appel téléphonique, puis choisit de l'ignorer. Vous ne pouvez pas faire la différence, autant que je sache.

et si votre application ne fonctionnait pas à l'un de ces moments il n'y a aucun moyen d'être informé puisque votre application ne fonctionne pas.

1
répondu user738960 2011-05-06 00:39:32

à partir d'un grand nombre d'essais et d'erreurs, découvert en surveillant l'écran blanc, lock complete et lock état événements donne un indicateur de l'écran de verrouillage cohérente. Vous aurez besoin de surveiller une transition d'état.

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

pour faire tourner les indicateurs de verrouillage d'écran en arrière-plan, vous devez mettre en œuvre le traitement d'arrière-plan appelant ce qui suit lors du lancement de l'application.

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

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

    [self registerforDeviceLockNotif];
}
1
répondu CFreymarc 2016-04-28 07:32:34

la façon la plus simple d'obtenir le verrouillage d'écran et déverrouiller des événements est d'ajouter des observateurs d'événements en utilisant NSNotificationCenter dans votre viewcontroller. J'ai ajouté l'observateur suivant dans la méthode viewdidload. C'est ce que j'ai fait:

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

puis j'ai ajouté le sélecteur suivant au viewcontroller. Ce sélecteur sera appelée lorsque l'écran est déverrouillé.

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

Si vous voulez détecter le cas lorsque l'écran est verrouillé, vous pouvez remplacer par Uiapplicationdidenterbackgroundnotification .

-2
répondu Jossy Paul 2015-05-07 07:24:47