Есть ли способ проверить, заблокировано / разблокировано устройство iOS?
Я использовал обновления местоположения GPS в моем приложении. Я хочу определить, находится ли устройство iOS в спящем режиме, чтобы можно было отключить обновления местоположения GPS и оптимизировать использование батареи. Я уже пробовал pausesLocationupdates в iOS 6, но он не работает должным образом. Я хочу отключить обновления местоположения GPS, как только устройство перейдет в спящий режим. Я хочу обнаружить событие блокировки / разблокировки в устройстве.
Есть ли способ достичь этой функциональности?
до сих пор я получил уведомления Дарвина, как указано ниже
-(void)registerForall
{
//Screen lock notifications
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.iokit.hid.displayStatus"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.springboard.lockstate"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.springboard.hasBlankedScreen"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.springboard.lockcomplete"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
}
//call back
static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
NSLog(@"IN Display status changed");
NSLog(@"Darwin notification NAME = %@",name);
}
Я могу получить уведомления Дарвина, когда устройство заблокировано / разблокировано, но реальная проблема заключается в том, как определить, пришло ли уведомление от блокировки или разблокировки устройства. Консольные журналы:
LockDetectDemo[2086] <Warning>: IN Display status changed
LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.springboard.lockcomplete
LockDetectDemo[2086] <Warning>: IN Display status changed
LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.springboard.lockstate
LockDetectDemo[2086] <Warning>: IN Display status changed
LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.springboard.hasBlankedScreen
LockDetectDemo[2086] <Warning>: IN Display status changed
LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.iokit.hid.displayStatus
Любого частного API также будет достаточно. Заранее спасибо.
6 ответов
Я решил это так:
//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
CFStringRef nameCFString = (CFStringRef)name;
NSString *lockState = (NSString*)nameCFString;
NSLog(@"Darwin notification NAME = %@",name);
if([lockState isEqualToString:@"com.apple.springboard.lockcomplete"])
{
NSLog(@"DEVICE LOCKED");
//Logic to disable the GPS
}
else
{
NSLog(@"LOCK STATUS CHANGED");
//Logic to enable the GPS
}
}
-(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);
}
Примечание. Уведомление " com.apple.springboard.lockcomplete" всегда будет появляться после уведомления "com.apple.springboard.lockstate".
Обновить
На порядок двух уведомлений больше нельзя полагаться, поскольку в последних версиях iOS
Приложения не могут прослушивать уведомления о блокировке устройства сейчас!
Я должен был получить это:
Уважаемый разработчик,
Мы обнаружили одну или несколько проблем с вашей недавней отправкой "xxxx". Чтобы обработать вашу заявку, необходимо исправить следующие проблемы:
Неподдерживаемая операция - приложения не могут прослушивать уведомления о блокировке устройства.
После исправления этих проблем используйте Xcode или Application Loader для загрузки нового двоичного файла в iTunes Connect. Выберите новый двоичный файл на странице "Сведения о приложении" в разделе "Мои приложения" в iTunes Connect и нажмите "Отправить на проверку".
С Уважением,
Команда App Store
26 апреля 2017 в 10:56
/* Зарегистрировать приложение для определения состояния блокировки */
-(void)registerAppforDetectLockState {
int notify_token;
notify_register_dispatch("com.apple.springboard.lockstate", ¬ify_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];
});
}
Для вашего конкретного случая использования может быть полезна проверка яркости экрана.
var isScreenLocked: Bool {
return UIScreen.main.brightness == 0.0
}
Вот лучшее решение
#import <notify.h>
#define kNotificationNameDidChangeDisplayStatus @"com.apple.iokit.hid.displayStatus"
@interface YourClass ()
{
int _notifyTokenForDidChangeDisplayStatus;
}
@property (nonatomic, assign, getter = isDisplayOn) BOOL displayOn;
@property (nonatomic, assign, getter = isRegisteredForDarwinNotifications) BOOL registeredForDarwinNotifications;
@end
- (void)registerForSomeNotifications
{
//
// Display notifications
//
__weak YourClass *weakSelf = self;
uint32_t result = notify_register_dispatch(kNotificationNameDidChangeDisplayStatus.UTF8String,
&_notifyTokenForDidChangeDisplayStatus,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0l),
^(int info) {
__strong YourClass *strongSelf = weakSelf;
if (strongSelf)
{
uint64_t state;
notify_get_state(_notifyTokenForDidChangeDisplayStatus, &state);
strongSelf.displayOn = (BOOL)state;
}
});
if (result != NOTIFY_STATUS_OK)
{
self.registeredForDarwinNotifications = NO;
return;
}
self.registeredForDarwinNotifications = YES;
}
- (void)unregisterFromSomeNotifications
{
//
// Display notifications
//
uint32_t result = notify_cancel(_notifyTokenForDidChangeDisplayStatus);
if (result == NOTIFY_STATUS_OK)
{
self.registeredForDarwinNotifications = NO;
}
}
Я получил решение для проверки кнопки блокировки, нажмите или переведите приложение в фоновый режим.
Цикл приложения для блокировки нажмите и переведите приложение в фоновый режим.
КОГДА ЗАМКИ НАЖМИТЕ
applicationWillResignActive
applicationDidEnterBackground
КОГДА РАЗБЛОКИРУЙТЕ ПРЕССУ
applicationWillEnterForeground
applicationDidBecomeActive
///////////////////// КОГДА ПОСТАВИТЬ В ФОН
applicationWillResignActive
applicationDidEnterBackground
КОГДА ЗАБЫЛИ
applicationWillEnterForeground
applicationDidBecomeActive
Вы можете наблюдать, как в обоих сценариях вызывается один и тот же метод. В этом случае это сложная задача - нажать кнопку блокировки или поместить приложение в фоновый режим. Небольшой взлом есть, когда мы нажимаем кнопку блокировки
applicationWillResignActive
applicationDidEnterBackground
эти методы будут вызваны немедленно, но когда мы поместим приложение в фоновый режим, между обоими методами будет временной интервал в миллисекунду. мы можем получить разницу во времени и поставить условие. лайк....
var dateResignActive : Date?
var dateAppDidBack : Date?
func applicationWillResignActive(_ application: UIApplication) {
dateResignActive = Date()
}
func applicationDidEnterBackground(_ application: UIApplication) {
dateAppDidBack = Date()
}
func applicationDidBecomeActive(_ application: UIApplication) {
let el1 = getCurrentMillis(date: dateResignActive!)
let el2 = getCurrentMillis(date: dateAppDidBack!)
let diff = el2 - el1
if diff < 10 { //// device was locked // 10 is aprox
// device was locked
}
else {
let elapsed = Int(Date().timeIntervalSince(date!))
if elapsed > 15 { // put app in background
}
}
}
func getCurrentMillis(date : Date)->Int64 {
return Int64(date.timeIntervalSince1970 * 1000)
}
**This code is tested in iPhone X(Notch) and iPhone 6(Home button device). Because notch device and home button device have small difference in above two method calling.**
Джимми предоставил отличное решение, но безопаснее пройти (__bridge const void *)(self)
в качестве наблюдателя.
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
displayStatusChanged,
CFSTR("com.apple.springboard.lockcomplete"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
Это позволяет правильно удалить наблюдателя.
На устройстве, которое использует защиту контента, защищенные файлы хранятся в зашифрованном виде и становятся доступными только в определенное время, обычно, когда устройство разблокировано. Это уведомление позволяет вашему приложению узнать, что устройство собирается заблокировать и что любые защищенные файлы, к которым оно в данный момент обращается, могут вскоре стать недоступными.
Вы можете подписаться на уведомления о applicationProtectedDataWillBecomeUnavailable
который, скорее всего, срабатывает, когда пользователь только что заблокировал свой iPhone.
Сам я никогда этого не делал, но это просто альтернативное решение...