Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect screen on/off from iOS service

I am developing a network monitor app that runs in background as a service. Is it possible to get a notification/call when the screen is turned on or off?

It exists in Android by using the following code:

private void registerScreenOnOffReceiver()
{
   IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
   filter.addAction(Intent.ACTION_SCREEN_OFF);
   registerReceiver(screenOnOffReceiver, filter);
}

screenOnOffReceiver is then called when screen is turned on/off. Is there a similar solution for iOS?

Edit: The best I've found so far is UIApplicationProtectedDataWillBecomeUnavailable ( Detect if iPhone screen is on/off ) but it require the user to enable Data Protection (password protection) on the device.

like image 699
Sunkas Avatar asked Jan 07 '13 08:01

Sunkas


2 Answers

You can use Darwin notifications, to listen for the events. I'm not 100% sure, but it looks to me, from running on a jailbroken iOS 5.0.1 iPhone 4, that one of these events might be what you need:

com.apple.iokit.hid.displayStatus
com.apple.springboard.hasBlankedScreen
com.apple.springboard.lockstate

Update: also, the following notification is posted when the phone locks (but not when it unlocks):

com.apple.springboard.lockcomplete

To use this, register for the event like this (this registers for just one event, but if that doesn't work for you, try the others):

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                NULL, // observer
                                displayStatusChanged, // callback
                                CFSTR("com.apple.iokit.hid.displayStatus"), // event name
                                NULL, // object
                                CFNotificationSuspensionBehaviorDeliverImmediately);

where displayStatusChanged is your event callback:

static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
    NSLog(@"event received!");
    // you might try inspecting the `userInfo` dictionary, to see 
    //  if it contains any useful info
    if (userInfo != nil) {
        CFShow(userInfo);
    }
}

If you really want this code to run in the background as a service, and you're jailbroken, I would recommend looking into iOS Launch Daemons. As opposed to an app that you simply let run in the background, a launch daemon can start automatically after a reboot, and you don't have to worry about iOS rules for apps running tasks in the background.

Let us know how this works!

like image 55
Nate Avatar answered Sep 19 '22 12:09

Nate


Using the lower-level notify API you can query the lockstate when a notification is received:

#import <notify.h>

int notify_token;
notify_register_dispatch("com.apple.springboard.lockstate", &notify_token, dispatch_get_main_queue(), ^(int token) {
    uint64_t state = UINT64_MAX;
    notify_get_state(token, &state);
    NSLog(@"com.apple.springboard.lockstate = %llu", state);
});

Of course your app will have to start a UIBackgroundTask in order to get the notifications, which limits the usefulness of this technique due to the limited runtime allowed by iOS.

like image 44
Nick Dowell Avatar answered Sep 19 '22 12:09

Nick Dowell