4

I am developing an app that logs down the screen on/off events. It's a kind of smartphone usage analysis app. All the app does is to write down a log like this:

2015 July 25 at 03:54:12 PM - Screen on
2015 July 25 at 03:59:38 PM - Screen off
2015 July 25 at 04:20:52 PM - Screen on
2015 July 25 at 04:22:32 PM - Screen off
...
2015 July 26 at 10:20:32 AM - Screen on
2015 July 26 at 10:22:11 AM - Screen off
2015 July 26 at 11:30:38 AM - Screen on
2015 July 26 at 10:31:02 AM - Screen off
...
  • "Screen on": user press home button (or power button) and enter passcode/unlock password if there is any.
  • "Screen off": user press power button to turn off the screen.

I was able to find some way to do this this on Android using the broadcast receiver to capture the events sent by the system. But in iOS there seems to be a problem since iOS only allows background services to run several minutes, I am not even sure if I can detect the "screen on/off" event on iOS.

I did some researches on this and found some articles, but those weren't help much:

My question is "Is it possible to make an app like this in iOS (latest version - 8.4) ?"

Thanks.

Community
  • 1
  • 1
Tony Dinh
  • 6,668
  • 5
  • 39
  • 58

2 Answers2

2

It may not be possible to meet all your requirements within the published, non jail broken iOS device using the background service. I can see the notifications come across, I'm just not sure about the backgrounding.

Since others have been saying it's not possible, I'm digging a little deeper here to see just how much can be done.

Because iOS is currently restricted to a small number of background modes (situations where events are delivered in the background), or a mode where your app is granted a few minutes of time after the user navigates away from your app, the primary issue is going to be tricking the system into allowing your app to get time in the background when needed.

There are several background modes, described in the Programming Guide to Background Execution. If you can, for example, send push notifications periodically to awaken the app to "download content", you may be able to get some time periodically as the system sees fit to do so.

The background Daemon is a possible solution, but only for your own use, but not via the App Store. The official take on this is in the App Store Review Guidelines -- the relevant section is 2.8 (presumably you'd get your daemon on by having the app install it "behind the scenes"):

2.8 Apps that install or launch other executable code will be rejected

There may be some system logs that iOS keeps for itself; if you can gain access to those, you'd have your data. I doubt, however, that this is available programmatically from a non jail broken phone.

I was able to test out some Swift (2.0) code that uses the Darwin Notifications mentioned in one of the Stack Overflow discussions that your original question led to: Lock / Unlock Events for iPhone. I didn't actually run in the background, but I did verify that the events are eventually delivered, even if the app isn't running when the actual lock event takes place. When my app is switched in, the notification gets called. So, if you were able to get time from the system, you'd get the (delayed) notification when Apple's algorithms decide to give you time.

The code snippet (I stuffed it into some random app) that allows the listening is as follows:

import UIKit
import CoreFoundation

class MainViewController: UIViewController, UIWebViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // CoreFoundation compatible types
        var cfstr: CFString = "com.apple.iokit.hid.displayStatus" as NSString
        var notificationCenter = CFNotificationCenterGetDarwinNotifyCenter()

        CFNotificationCenterAddObserver(notificationCenter, nil,
            { (noti: CFNotificationCenter!, aPtr: UnsafeMutablePointer<Void>, aStr: CFString!, bPtr: UnsafePointer<Void>, aDict: CFDictionary!) -> () in
                print("got notification") }, cfstr, nil, CFNotificationSuspensionBehavior.DeliverImmediately)

    }
    // [... more stuff ...]
}
Community
  • 1
  • 1
rholmes
  • 4,064
  • 3
  • 25
  • 34
  • Aw.. too bad. iOS things are so restricted. Anyway thanks for the information. Could you point out the reasons why this app is not possible and the link to Apple's policy about the restrictions? Thanks a lot. – Tony Dinh Jul 26 '15 at 15:36
  • Just updated some info that might be useful, at least for playing around with. Upvoted the question so perhaps someone with more specific advice will see it ;-) – rholmes Jul 27 '15 at 00:58
  • Thanks, that's a lot of useful information. I am really interested in "The background Daemon" and having some researches for it right now. I don't really need to publishing the app so according to what you said, this "daemon" thing might be the solution for me. – Tony Dinh Jul 28 '15 at 02:58
  • Yeah I'm thinking the background daemon would work -- not sure if jailbreaking is absolutely required for that. Perhaps the app could install it and you can provision it to a test device. – rholmes Jul 28 '15 at 03:00
0

If you can use the C or objective C code i guess this code might help you.

   notify_register_dispatch("com.apple.iokit.hid.displayStatus", &notify_token, dispatch_get_main_queue(), ^(int token) {
    uint64_t state = UINT64_MAX;
    notify_get_state(token, &state);
    //notify_cancel(token);
    debug("com.apple.iokit.hid.displayStatus = %llu", state);
});

Provided that you are able to run your app in background modes. State will provide the screen on off status

Dinesh
  • 929
  • 7
  • 25