Как я могу обнаружить события блокировки / разблокировки экрана на iPhone?

Как я могу обнаружить события блокировки / разблокировки экрана на iPhone? Когда пользователь разблокирует его, я хочу показать уведомление уведомления от моего приложения iPhone. (Так же, как Broadcast Receiver для разблокировки экрана в Android.)

7 ответов

Решение

На самом деле я хочу, если я выйду из приложения и заблокирую iPhone, и через некоторое время я разблокирую iPhone, а затем выйду из Приложения, отобразят уведомления или оповестят о запуске приложений.

Вы не можете сделать это на iPhone.

Проверьте это, я хотел обнаружить события блокировки / разблокировки, я решил это с помощью уведомлений Дарвина. Вы можете обнаружить событие, когда устройство заблокировано "com.apple.springboard.lockcomplete",

//call back
static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
    // the "com.apple.springboard.lockcomplete" notification will always come after the "com.apple.springboard.lockstate" notification

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

    if([lockState isEqualToString:@"com.apple.springboard.lockcomplete"])
    {
        NSLog(@"DEVICE LOCKED");
    }
    else
    {
        NSLog(@"LOCK STATUS CHANGED");
    }   
}


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

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

Чтобы обнаружить блокировку / разблокировку внутри приложения в Swift 5, только это сработало для меня:

override func viewDidLoad() {
    super.viewDidLoad()

     NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplication.willEnterForegroundNotification, object: nil)
     NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
}

@objc func applicationDidBecomeActive(notification: NSNotification) {
    print("ACTIVE")
}
@objc func applicationDidEnterBackground(notification: NSNotification) {
    print("BACKGROUND")
}
  1. Вы не можете использовать com.apple.springboard.lockcomplete или com.apple.springboard.lockstate при отправке вашего приложения в App Store ваше приложение будет отклонено, потому что это частный API.

  2. В com.apple.springboard.lockcomplete уведомление НЕ всегда приходит после com.apple.springboard.lockstateуведомление, это может произойти рано или поздно. Вам нужно установить таймер, чтобы дождаться этого события.

Итак, вот как вы можете определить статус блокировки и разблокировки экрана в Swift 5:

struct NotificationName {
    // Listen to CFNotification, and convert to Notification
    public static let lockComplete = Notification.Name("NotificationName.lockComplete")
    public static let lockState = Notification.Name("NotificationName.lockState")

    // Handle lockComplete and lockState Notification to post locked or unlocked notification.
    public static let locked = Notification.Name("NotificationName.locked")
    public static let unlocked = Notification.Name("NotificationName.unlocked")
}

func addNotificationObservers() {
    let lockCompleteString = "com.apple.springboard.lockcomplete"
    let lockString = "com.apple.springboard.lockstate"

    // Listen to CFNotification, post Notification accordingly.
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                    nil,
                                    { (_, _, _, _, _) in
                                        NotificationCenter.default.post(name: NotificationName.lockComplete, object: nil)
                                    },
                                    lockCompleteString as CFString,
                                    nil,
                                    CFNotificationSuspensionBehavior.deliverImmediately)

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                    nil,
                                    { (_, _, _, _, _) in
                                        NotificationCenter.default.post(name: NotificationName.lockState, object: nil)
                                    },
                                    lockString as CFString,
                                    nil,
                                    CFNotificationSuspensionBehavior.deliverImmediately)

    // Listen to Notification and handle.
    NotificationCenter.default.addObserver(self,
                                            selector: #selector(onLockComplete),
                                            name: NotificationName.lockComplete,
                                            object: nil)

    NotificationCenter.default.addObserver(self,
                                            selector: #selector(onLockState),
                                            name: NotificationName.lockState,
                                            object: nil)
}

// nil means don't know; ture or false means we did or did not received such notification.
var receiveLockStateNotification: Bool? = nil
// when we received lockState notification, use timer to wait 0.3s for the lockComplete notification.
var waitForLockCompleteNotificationTimer: Timer? = nil
var receiveLockCompleteNotification: Bool? = nil

// When we received lockComplete notification, invalidate timer and refresh lock status.
@objc
func onLockComplete() {
    if let timer = waitForLockCompleteNotificationTimer {
        timer.invalidate()
        waitForLockCompleteNotificationTimer = nil
    }

    receiveLockCompleteNotification = true
    changeIsLockedIfNeeded()
}

// When we received lockState notification, refresh lock status.
@objc
func onLockState() {
    receiveLockStateNotification = true
    changeIsLockedIfNeeded()
}

func changeIsLockedIfNeeded() {
    guard let state = receiveLockStateNotification, state else {
        // If we don't receive lockState notification, return.
        return
    }

    guard let complete = receiveLockCompleteNotification else {
        // If we don't receive lockComplete notification, wait 0.3s.
        // If nothing happens in 0.3s, then make sure we don't receive lockComplete, and refresh lock status.
        waitForLockCompleteNotificationTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: false, block: { _ in
            self.receiveLockCompleteNotification = false
            self.changeIsLockedIfNeeded()
        })
        return
    }

    // When we determined lockState and lockComplete notification is received or not.
    // We can update the device lock status by 'complete' value.
    NotificationCenter.default.post(
        name: complete ? NotificationName.locked : NotificationName.unlocked,
        object: nil
    )

    // Reset status.
    receiveLockStateNotification = nil
    receiveLockCompleteNotification = nil
}

Может быть, вам нужно реализовать следующие методы в AppDelegate:

Сообщает делегату, что приложение теперь находится в фоновом режиме.

- (void)applicationDidEnterBackground:(UIApplication *)application

Сообщает делегату, что приложение стало активным.

- (void)applicationDidBecomeActive:(UIApplication *)application

Сообщает делегату, что приложение собирается стать неактивным.

- (void)applicationWillResignActive:(UIApplication *)application

Оригинальный вопрос довольно старый, поэтому для всех, кто наткнется на это:

На современных устройствах с Face ID и Touch ID можно использовать методы AppDelegate applicationProtectedDataDidBecomeAvailable(_:)(документы ) и applicationProtectedDataWillBecomeUnavailable(_:)(документы ).

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

Однако это, конечно, работает только до тех пор, пока ваше приложение активно работает.

Из текущего контроллера представления вы должны добавить наблюдателя для UIApplicationDidEnterBackgroundNotification и удалить наблюдателя во время закрытия контроллера представления.[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];

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