6

I would like to have my app monitor when phone becomes locked and unlocked, as well as when it turns blank (after longer inactivity), all this while my app is not focused, but running in the background.

I can receive lock/unlock/blank events with ease while app is focused:

-(void) startListeningForPhoneLockEvent
{
    NSLog(@"Start listening to lock/unlock and screen-goes-black events.");

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                (void*)self,
                                lockStateChanged,
                                CFSTR("com.apple.springboard.lockstate"),
                                NULL,
                                CFNotificationSuspensionBehaviorDeliverImmediately);

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                (void*)self,
                                hasBlankedScreen,
                                CFSTR("com.apple.springboard.hasBlankedScreen"),
                                NULL,
                                CFNotificationSuspensionBehaviorDeliverImmediately);
}

And callback functions:

static void lockStateChanged( CFNotificationCenterRef center, void*observer, CFStringRef name, const void *object, CFDictionaryRef userInfo )
{
    NSLog(@"Lock event received!");
}

static void hasBlankedScreen( CFNotificationCenterRef center, void*observer, CFStringRef name, const void *object, CFDictionaryRef userInfo )
{
    NSLog(@"Blanked screen event received!");
}

I've enabled background mode:

  • Background fetch.

However, once app goes into background, it does not receive lock/unlock/blank screen events.

I've tried with other background modes, such as sound playback, location updates etc. but app is still not receiving lock/unlock/blank screen events when in background.

I'm not sure if this is actually possible, or if I am doing something wrong.

I'm testing it on real device that is updated to iOS9, using latest XCode with iOS9 SDK.

Siniša
  • 2,988
  • 4
  • 24
  • 36
  • I wouldn't mind a solution in Swift as well. – Sumner Evans Nov 23 '15 at 04:07
  • Just having background mode enabled in the application does not help, the application should actually be running in background. Can you confirm that you application is actually running in the background when you lock/unlock the phone? – user3334059 Nov 25 '15 at 23:08
  • @SumantHanumante, are there any restrictions from Apple on running in the background, listening to lock, unlock events? – Sumner Evans Nov 27 '15 at 22:24
  • Unfortunately, I don't have access to a physical device at this point, so I cannot test it out. But did you try keeping the app running in background and then check for the callback. One quick way to keep app running in background is to start location updates in foreground and then put app into background with "location updates" mode ON. – user3334059 Nov 30 '15 at 03:00
  • have you figured it out then ? is there any way possible to monitor the device lock screen ? i mean when user enters wrong password then our app should react or enter into some notification or method , while it is in background state . is that functionality is possible to implement in iOS ? in android it is possible , so . is anyone knows how to do that ? please guide me through this . – Moxarth Dec 13 '17 at 06:22

1 Answers1

-1

Even though your app is configured to run in the background, it won't actually run if it has no work to be done. To get it to run in background with location updates, follow these instructions by Ricky:

  1. I restart the location manager every 1 minute in function didUpdateLocations.
  2. I allow the location manager to get the locations from the device for 10 seconds before shut it down (to save battery).

Partial Code Below:

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{

for(int i=0;i<locations.count;i++){
    CLLocation * newLocation = [locations objectAtIndex:i];
    CLLocationCoordinate2D theLocation = newLocation.coordinate;
    CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;
    NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];

    if (locationAge > 30.0)
        continue;

    //Select only valid location and also location with good accuracy
    if(newLocation!=nil&&theAccuracy>0
       &&theAccuracy<2000
       &&(!(theLocation.latitude==0.0&&theLocation.longitude==0.0))){
        self.myLastLocation = theLocation;
        self.myLastLocationAccuracy= theAccuracy;
        NSMutableDictionary * dict = [[NSMutableDictionary alloc]init];
        [dict setObject:[NSNumber numberWithFloat:theLocation.latitude] forKey:@"latitude"];
        [dict setObject:[NSNumber numberWithFloat:theLocation.longitude] forKey:@"longitude"];
        [dict setObject:[NSNumber numberWithFloat:theAccuracy] forKey:@"theAccuracy"];
        //Add the vallid location with good accuracy into an array
        //Every 1 minute, I will select the best location based on accuracy and send to server
        [self.shareModel.myLocationArray addObject:dict];
    }
}

//If the timer still valid, return it (Will not run the code below)
if (self.shareModel.timer)
    return;

self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
[self.shareModel.bgTask beginNewBackgroundTask];

//Restart the locationMaanger after 1 minute
self.shareModel.timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self
                                                      selector:@selector(restartLocationUpdates)
                                                       userInfo:nil
                                                        repeats:NO];

//Will only stop the locationManager after 10 seconds, so that we can get some accurate locations
//The location manager will only operate for 10 seconds to save battery
NSTimer * delay10Seconds;
delay10Seconds = [NSTimer scheduledTimerWithTimeInterval:10 target:self
                                                selector:@selector(stopLocationDelayBy10Seconds)
                                                userInfo:nil
                                                 repeats:NO];
 }

I was able to use your code in the github project referenced in there to listen to the lock and unlock events on a device running ios 9, using the latest XCode. Here are the logs:

2015-12-18 13:31:44.777 Location[16185:3796448] startLocationTracking
2015-12-18 13:31:44.780 Location[16185:3796448] authorizationStatus authorized
2015-12-18 13:31:44.788 Location[16185:3796448] Start listening to lock/unlock and screen-goes-black events.
2015-12-18 13:31:44.834 Location[16185:3796448] locationManager didUpdateLocations
2015-12-18 13:31:44.837 Location[16185:3796448] started master task 1
2015-12-18 13:31:45.197 Location[16185:3796448] locationManager didUpdateLocations
2015-12-18 13:31:48.079 Location[16185:3796448] Blanked screen event received!
2015-12-18 13:31:48.215 Location[16185:3796448] Lock event received!
Community
  • 1
  • 1
  • 1
    Can someone explain why this answer was downvoted? I tried adding a comment and it said i did not have enough karma, and could only add an answer – user3272750 Jan 27 '16 at 19:32