Вопрос по gps, ios, core-location, sleep – Есть ли способ проверить, заблокировано ли устройство iOS?

12

Я использовал обновления местоположения 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 также будет достаточно. Заранее спасибо.

Это такой простой и отличный ответ. CanonicalBear
Вы можете попробовать и использовать наблюдателя наUIApplication.shared.isProtectedDataAvailable который вернетсяtrue когда устройство разблокировано iwasrobbed

Ваш Ответ

7   ответов
4

Вот'лучшее решение

#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;
    }
}
Что делать, если я тоже хочу работать в фоновом режиме? Vandit Mehta
Спасибо за публикацию этого! Насколько я могу сказать, другой метод неНа самом деле, я не говорю вам, на что меняется состояние экрана или блокировки (словарь userInfo всегда равен нулю), и делать это на основе порядка проблематично, тем более что порядок, в котором я получаю эти уведомления, фактически противоположен тому, о котором говорилось в сообщении они будут - возможно, новое поведение в iOS 7. GuyGizmo
8

Приложения не могут прослушивать уведомления о блокировке устройства сейчас!

Я должен был получить это:

Уважаемый разработчик,

Мы обнаружили одну или несколько проблем с вашим недавним представлением для "хххх», Чтобы обработать вашу заявку, необходимо исправить следующие проблемы:

Неподдерживаемая операция - приложения не могут прослушивать уведомления о блокировке устройства.

Как только эти проблемы были исправлены, используйте Xcode или Application Loader, чтобы загрузить новый бинарный файл в iTunes Connect. Выберите новый бинарный файл в приложенииs На странице «Сведения» в разделе «Мои приложения» в iTunes Connect выберите «Отправить на проверку».

С Уважением,

Команда App Store

26 апреля 2017 в 10:56

Это кажется не столько ответом, сколько дополнительным ограничением на вопрос. Nathan Tuggy
14

Я решил это так:

//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

мы тоже. но если вы хотите сэкономить энергию в фоновом режиме, обновления местоположения соответствуют фоновому состоянию. ваши утверждения противоречат. AlexWien
Именно на основе событий я хочу приостановить / возобновить обновления местоположения в приложении, чтобы предотвратить разрядку аккумулятора. Rohit Kashyap
Что делать, если я тоже хочу работать в фоновом режиме? Vandit Mehta
простой логический флаг, который вы сохраните, тоже будет работать. сохранить этот флаг в didEnterbackground, и будет willEnterForeground AlexWien
0

Джимми предоставил отличное решение, но онобезопаснее пройти в(__bridge const void *)(self) в качестве наблюдателя.

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                (__bridge const void *)(self),
                                displayStatusChanged,
                                CFSTR("com.apple.springboard.lockcomplete"),
                                NULL,
                                CFNotificationSuspensionBehaviorDeliverImmediately);

Это позволяет правильно удалить наблюдателя.

6

/ * Зарегистрировать приложение для определения состояния блокировки * /

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

  });

 }
@VanditMehta Vandit - я вижу, что вы разместили вопрос об обнаружении фона в нескольких вопросах SO. Вы когда-нибудь находили решение, которое работает в фоновом режиме для обнаружения заблокированного состояния? Praxiteles
Что делать, если я тоже хочу работать в фоновом режиме? Vandit Mehta
просто импортируйте #import notify.h, прежде чем использовать этот код, иначе вы получите ошибку компиляции Nits007ak
Я думаю, что вы можете использовать этот метод ... это может быть полезно Nits007ak
1

Я получил решение для проверки кнопки блокировки, нажмите или переведите приложение в фоновый режим.

Цикл приложения для блокировки нажмите и переведите приложение в фоновый режим.

КОГДА ЗАМКИ НАЖМИТЕ

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.**  
1

Для вашего конкретного случая использования может быть полезна проверка яркости экрана.

var isScreenLocked: Bool {
    return UIScreen.main.brightness == 0.0
}

Похожие вопросы