web-dev-qa-db-ja.com

ロック解除イベントiphone

IPhoneでロック/ロック解除イベントを検出するにはどうすればよいですか?ジェイルブレイクされたデバイスでのみ可能であると仮定して、正しいAPIを教えていただけますか?

lock eventsとは、ロック画面の表示または非表示を意味します(ロックを解除するにはパスワードが必要かどうか)。

35
Panos

Darwin notifications を使用して、イベントをリッスンできます。ジェイルブレイクされたiOS 5.0.1 iPhone 4での私のテストから、私はこれらのイベントの1つがあなたが必要とするものかもしれないと思います:

_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()を使用することです。ここで説明するように、ロックとロック解除では異なる値 が表示されます

22
Nate

回答についてラウンド:

アプリケーションはすべての種類のシナリオでアクティブな取得を拒否します...そして、私のすべてのテストから、バックグラウンドでアプリケーションが起動している場合でも、画面がロックされていると判断する方法はありません(CPU速度は報告せず、BUS速度)同じまま、mach_time denom/numerは変更されません)...

ただし、Appleは加速度計をオフにします... 画面がロックされているときにiPhoneの加速度計を有効にします (iPhone 4でテスト済みのiOS4.2はこの動作)

したがって...

アプリケーションデリゲートで:

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

私は知っています...それは一種のハックですが、今のところ私にとっては魅力のように機能しています。これが機能しない問題を見つけた場合は更新してください。

13
BadPirate

タスクの切り替えと画面のロックに起因するapplicationWillResignActive:コールバックを区別する、より洗練された方法があります。これには、加速度計の状態などの文書化されていない機能さえ含まれていません。

アプリがバックグラウンドに移動すると、アプリデリゲートには最初にapplicationWillResignActive:、次にapplicationDidEnterBackground:が送信されます。ロックボタンを押すか、電話の着信によってアプリが中断された場合、後者のメソッドは呼び出されません。この情報を使用して、2つのシナリオを区別できます。

画面がロックされた場合、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:へのすべての呼び出しはアクティブから非アクティブへの状態遷移(画面のロック時など)が原因であると想定していますが、タイムアウト(この場合は1回のrunloopサイクル)screenLockActivatedへの呼び出しを遅らせることによって。画面がロックされた場合、システムは他のデリゲートメソッドに触れずに現在の実行ループサイクルを終了します。ただし、これがアクティブからバックグラウンドへの状態遷移である場合は、サイクルの終了前にapplicationDidEnterBackground:も呼び出されます。これにより、以前にスケジュールされたリクエストをそこから単にキャンセルできるため、リクエストが呼び出されたときに呼び出されなくなります。想定されていません。

楽しい!

7
Lvsti

執筆時点では、デバイスのロックを検出するための2つのかなり信頼できる方法があります。


データ保護

データ保護資格 を有効にすると、アプリは applicationProtectedDataWillBecomeUnavailable: および applicationProtectedDataDidBecomeAvailable: パスコード/ TouchID認証を使用するデバイスがロック/ロック解除されたときに高い確率で判断する通知。デバイスがパスコード/ TouchIDを使用しているかどうかを確認するには、 LAContext を照会できます。

警告:この方法は、電話がロックされているのと同時に、「保護されたデータが利用できなくなる」ことに依存しています。電話機がTouchIDを使用しているときにスリープ/ロックボタンを押すと、電話機がロックされ、保護されたデータが使用できなくなります。再びロックを解除するには、パスコードがすぐに必要になります。つまり、保護されたデータが利用できなくなることは、本質的に電話がロックされていることを示します。 誰かがパスコードのみを使用している場合、「パスコードが必要」の時間をのどこにでも設定できるため、これは必ずしも当てはまりません。すぐから4時間のようなものにこの場合、電話は保護されたデータを処理できることを報告しますが、電話をロックしても、しばらくの間保護されたデータが使用できなくなることはありません。


ライフサイクルのタイミング

アプリがフォアグラウンドにある場合、2つのライフサイクルイベント UIApplicationWillResignActiveNotificationUIApplicationDidEnterBackgroundNotification に応じて、時間差に顕著な変化がありますそれらをトリガーするもの。

(これはiOS 10でテストされ、将来のリリースで変更される可能性があります)

ホームボタンを押すと、2つの間に大幅な遅延が生じます([低減モーション]設定が有効になっている場合でも)。

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

アプリが開いているときにデバイスをロックすると、2つのイベントの間にわずかな遅延(<〜0.2秒)が生じます。

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

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のパラメーターとして使用して、現在の状態をどこでも取得できます。これは、状態と画面の状態が変化しないことを知りたい場合に役立ちます。

5
david

このコードを使用する前に、#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];

    });
}
4
Nits007ak

パスコードが設定されている場合、これらのイベントをAppDelegateで使用できます

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

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

多くの試行錯誤の結果、空白の画面、ロック完了、およびロック状態イベントの監視が発見され、一貫したロック画面インジケーターが提供されます。状態遷移を監視する必要があります。

// 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];
}
2
CFreymarc

アプリが実行中で、ユーザーがデバイスをロックすると、アプリの代理人は「application Will Resign Active:」の呼び出しを受け取ります。ロックされているときにアプリが実行されていた場合、デバイスがロック解除されると、「application Did Become Active:」の呼び出しが届きます。ただし、ユーザーが電話を受けた後、それを無視することを選択した場合は、同じアプリが呼び出されます。私の知る限り、その違いはわかりません。

また、これらの時間帯にアプリが実行されていなかった場合、アプリが実行されていないため、通知を受ける方法はありません。

1
user738960