IPhoneで画面のロック/ロック解除イベントを検出するにはどうすればよいですか?ユーザーがロックを解除したときに、iPhoneアプリからの通知アラートを表示したいと思います。 (Androidの画面ロック解除用のブロードキャストレシーバーと同じように。)
実際には、アプリケーションを終了して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")
}
AppDelegate
に次のメソッドを実装する必要があるかもしれません。
アプリケーションがバックグラウンドにあることをデリゲートに通知します。
- (void)applicationDidEnterBackground:(UIApplication *)application
アプリケーションがアクティブになったことをデリゲートに通知します。
- (void)applicationDidBecomeActive:(UIApplication *)application
アプリケーションが非アクティブになりそうであることをデリゲートに通知します。
- (void)applicationWillResignActive:(UIApplication *)application
アプリをAppStoreに送信するときにcom.Apple.springboard.lockcomplete
またはcom.Apple.springboard.lockstate
を使用することはできません。アプリはプライベートAPIであるため拒否されます。
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
}