4

I want a event/callback for my iOS app when the network activity goes from none to up (and the other way around). Similar to how Android does with onDataActivity(). I'm not talking about Reachability but when data actually starts or stops transmitting.

The app is not for App Store and not for jailbreak. I have got a similar functionality of detecting when the screen goes on/off working by using

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

along with other events such as

com.apple.springboard.hasBlankedScreen
com.apple.springboard.lockstate

Now I wonder if there is a event for when data is started or stopped to transmit? Or if someone could point me the direction of a complete list of all events that can be monitored in the way above.

Victor Ronin
  • 22,758
  • 18
  • 92
  • 184
Sunkas
  • 9,542
  • 6
  • 62
  • 102

2 Answers2

5

I monitored both the standard Darwin notifications and the Core Telphony notifications on a jailbroken iOS 5 iPhone.

I did not see any notifications that really do what you want.

There are a few Core Telephony notifications that come out, but not on every transmit start and end. It looks like when the data service connects, there might be some notifications, but again, they really aren't exactly what you asked for:

kCTIndicatorRadioTransmitNotification
kCTRegistrationDataStatusChangedNotification

If you want to try monitoring all the Core Telephony notifications for yourself, you can use the Core Telephony framework, and the CT notification center:

-(void) registerCallback {
   id ct = CTTelephonyCenterGetDefault();
   CTTelephonyCenterAddObserver(ct,   // center
                                NULL, // observer
                                telephonyEventCallback,  // callback
                                NULL,                    // event name (or all)
                                NULL,                    // object
                                CFNotificationSuspensionBehaviorDeliverImmediately);
}    

static void telephonyEventCallback(CFNotificationCenterRef center, void* observer, CFStringRef name, const void* object, CFDictionaryRef userInfo)
{
    //NSLog(@"telephonyEventCallback()");

    NSString* notifyName = (__bridge NSString*)name;
    if ([notifyName isEqualToString:@"kCTMessageReceivedNotification"]) {  // received SMS

    } /* look for other notification names here */
}

In the above call, I pass NULL to the CTTelephonyCenterAddObserver() call, which registers for all notifications. You can of course pass the name of one particular notification if you know what you're looking for, like the example you posted for com.apple.iokit.hid.displayStatus.

Regarding john.k.doe's option, you might try using Key Value Observing on that property, to get notified when it changes:

UIApplication* app = [UIApplication sharedApplication];
[app addObserver: self forKeyPath: @"networkActivityIndicatorVisible" options: NSKeyValueObservingOptionNew context: nil];

where your observer callback is:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"networkActivityIndicatorVisible"]) {
        // process here
        NSLog(@"network activity indicator change!");
        BOOL active = [UIApplication sharedApplication].networkActivityIndicatorVisible;
    }
}

I'm not sure if KVO will still work in the background, and it might depend on how your app manages being backgrounded.

But, of course, that requires apps to actually use that property when they access the network, which not all of them do. It's unfortunate that Apple even made that indicator something that 3rd-party developers need to control. On Android and BlackBerry, the OS is smart enough to know when it's transmitting/receiving.

So, this is still only partly what you need :(

Community
  • 1
  • 1
Nate
  • 31,017
  • 13
  • 83
  • 207
  • I've tried the first part of your code/suggestion so far. I got a complie error stating that RTLD_LAZY is not declared. Also some warnings on the two rows below for "Implicit declaration of function 'dlsym' is invalid in C99." Does this really work on a non-jailbreaked device? Find similar code on http://cutnpaste.org/blog/ios-listen-incoming-sms/ but it states you need jailbreak for it to work. – Sunkas Jan 28 '13 at 10:37
  • I edited my answer to add the `#include` you would need to compile with `RTLD_LAZY` and the rest of the dynamic library functions. As I said in the answer, the code I posted is dynamically loading the Core Telephony framework, and dynamically looking up the function `CTTelephonyCenterAddObserver()`. You don't really **have** to do it that way ... I just had some code that did want dynamic loading. You can include the Core Telephony framework in your project in the normal way, and just call the `CTTelephonyCenterAddObserver()` function directly. – Nate Jan 28 '13 at 11:08
  • @Sunkas, This does work on non-jailbroken devices. I just tried it on my jailed iOS 6 iPhone 5 and got CT notifications. The example that you link to is intended for doing more than just listening to notifications. If you want to read incoming SMS, you need to listen to that notification, and then open up the sms.db file with sqlite to get the SMS content. That second part requires a jailbroken phone. But, for your problem, I was just suggesting that you subscribe for the notifications. – Nate Jan 28 '13 at 11:26
  • I also just changed the answer to *not* use dynamic loading, and simply use the Core Telephony APIs normally. You will still need to add the CoreTelephony.framework to your project, and you'll get compile warnings because those are Private APIs. But, it will work. – Nate Jan 28 '13 at 11:30
  • Thanks. Got it working now. However, neither kCTIndicatorRadioTransmitNotification nor kCTRegistrationDataStatusChangedNotification seems to be called when I need them to. And the userInfo dictionary does not provide any useful information either. Unfortunately, but perhaps expected. – Sunkas Jan 28 '13 at 12:27
  • Even if you solution did not work, I'll give you the 50 in bounty as you we're the closes to a desired solution. This will probably not work on iOS at all. – Sunkas Jan 31 '13 at 15:41
  • 1
    Sometimes, it's not possible to do what you want to do :( But, now you know how to list all the CT notifications. It's possible that there's a private API for this, although I wouldn't be surprised if there wasn't. If there was a callback for network activity off/on, then the status bar indicator would probably be wired up to that. The fact that it's not suggests that there is no such private API. It's possible that Apple doesn't want this, because it reveals when iOS is making small network calls in the background, which users might not like seeing, if it didn't come from them. – Nate Feb 01 '13 at 02:25
3

there's really not a system Notification for this.

if you are talking about monitoring activity to/from your own app, you obviously have control of that, and should be able to bracket any calls you know to access the network …

if you are talking about monitoring activity to/from all other apps, and you are willing to presume that they are in strict compliance with Apple guidelines and turn on/off the network activity status indicator in the status bar, you can call:

[[UIApplication sharedApplication] isNetworkActivityIndicatorVisible];

but this obviously requires that you do so in a polling fashion, probably best done on a background thread / GCD queue. then you can post your own notification, to be seen elsewhere within your app.

john.k.doe
  • 7,533
  • 2
  • 37
  • 64
  • Thanks for your reply! First, I can't get the method to work, it always returns false, even if the little spinner top right is spinning. Perhaps because may application is running in the background. Secondly, the Network Activity Indicator this method checks, it's up to the developer to call it, right? So if the network is being used but the app developer never starts the spinner, I still wont get any notification (using Nate's observer)? – Sunkas Jan 28 '13 at 10:54
  • @Sunkas, that's right. Unfortunately, both john and my solutions require the other developers to use this optional API. Apple's software itself is pretty good about using it, but with other 3rd-party developers, it's not going to indicate network activity 100% of the time. – Nate Jan 28 '13 at 11:16
  • @john.k.doe thanks for your answer , i was trying to monitor all network activity, i should only monitor mine... – Juan Boero Oct 28 '15 at 20:04
  • doesn't work. trying to catch when AVPlayer starts streaming – iWheelBuy Jan 03 '16 at 12:19