Вопрос по gps, ios, core-location, sleep – Есть ли способ проверить, заблокировано ли устройство 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] : IN Display status changed
LockDetectDemo[2086] : Darwin notification NAME = com.apple.springboard.lockcomplete
LockDetectDemo[2086] : IN Display status changed
LockDetectDemo[2086] : Darwin notification NAME = com.apple.springboard.lockstate
LockDetectDemo[2086] : IN Display status changed
LockDetectDemo[2086] : Darwin notification NAME = com.apple.springboard.hasBlankedScreen
LockDetectDemo[2086] : IN Display status changed
LockDetectDemo[2086] : Darwin notification NAME = com.apple.iokit.hid.displayStatus
Любого частного API также будет достаточно. Заранее спасибо.
UIApplication.shared.isProtectedDataAvailable
который вернетсяtrue
когда устройство разблокировано
iwasrobbed
Вот'лучшее решение
#import
#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;
}
}
Приложения не могут прослушивать уведомления о блокировке устройства сейчас!
Я должен был получить это:
Уважаемый разработчик,
Мы обнаружили одну или несколько проблем с вашим недавним представлением для "хххх», Чтобы обработать вашу заявку, необходимо исправить следующие проблемы:
Неподдерживаемая операция - приложения не могут прослушивать уведомления о блокировке устройства.
Как только эти проблемы были исправлены, используйте Xcode или Application Loader, чтобы загрузить новый бинарный файл в iTunes Connect. Выберите новый бинарный файл в приложенииs На странице «Сведения» в разделе «Мои приложения» в iTunes Connect выберите «Отправить на проверку».
С Уважением,
Команда App Store
26 апреля 2017 в 10:56
Я решил это так:
//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
Джимми предоставил отличное решение, но онобезопаснее пройти в(__bridge const void *)(self)
в качестве наблюдателя.
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
displayStatusChanged,
CFSTR("com.apple.springboard.lockcomplete"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
Это позволяет правильно удалить наблюдателя.
/ * Зарегистрировать приложение для определения состояния блокировки * /
-(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];
});
}
Я получил решение для проверки кнопки блокировки, нажмите или переведите приложение в фоновый режим.
Цикл приложения для блокировки нажмите и переведите приложение в фоновый режим.
КОГДА ЗАМКИ НАЖМИТЕ
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.**