user3113881
user3113881

Reputation: 51

Apple Notification Center Service through OS X

I know you can use this service to have devices like smart watches intercept notifications from iOS devices. But can you receive these iOS notifications on a Mac through OS X?

I want to be able to have my OS X program detect a specific notification type that is received in iOS. I tried browsing for the ANCS device on my Mac, but it didn't show up. I know you can't do this between iOS devices, so I was wondering if maybe the same was true between iOS and OS X or not? Thanks!

Upvotes: 5

Views: 1496

Answers (1)

Yazid
Yazid

Reputation: 968

It's definitely possible!

Here's what you need:

  1. An app on your iOS device which imports CoreBluetooth and uses CBPeripheralManager to advertise a dummy service with some custom UUID (not the ANCS UUID, it won't work). This dummy service is required for your Mac to "see" the ANCS service.*
  2. An app on your Mac which imports IOBluetooth, initiates a CBCentralManager object, and starts a scan. You can do this as so:

    [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:YOUR_CUSTOM_SERVICE_UUID]] options:@{CBCentralManagerScanOptionSolicitedServiceUUIDsKey:@[[CBUUID UUIDWithString:ANCS_SERVICE_UUID]]];
    

    Make sure you set yourself up as a delegate to CBCentralManager to receive the delegate callbacks.

  3. When your Mac discovers your device in didDiscoverPeripheral, connect to it: [self.centralManager connectPeripheral:peripheral options:nil];

    1 very important thing to note here is you need to retain your peripheral to a property if you wish to connect to it, otherwise it will be dealloc'ed. See this answer for a more detailed discussion.

  4. In didConnectPeripheral, you need to set yourself up as a delegate to the CBPeripheral you're connected to then start discovering services:

    [peripheral discoverServices:nil];

    (All the callbacks from this point onward are for CBPeripheral)

  5. In didDiscoverServices, you should get a list of available services. Loop through them as so and discover each service's characteristics:

    for (CBService *service in peripheral.services) {
        if ([service.UUID isEqual:[CBUUID UUIDWithString:YOUR_CUSTOM_SERVICE_UUID]]) {
            NSLog(@"Found your Custom Service");
        }
        if ([service.UUID isEqual:[CBUUID UUIDWithString:ANCS_UUID]]) {
            NSLog(@"Found ANCS Service");
        }
    
        [peripheral discoverCharacteristics:nil forService:service];
    }
    
  6. In didDiscoverCharacteristicsForService, you want to look for 3 characteristics:

    • ANCS Notification Source: UUID 9FBF120D-6301-42D9-8C58-25E699A21DBD (notifiable)
    • ANCS Control Point: UUID 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 (writeable with response)
    • ANCS Data Source: UUID 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB (notifiable)

    For those notifiable characteristics, subscribe to them for updates:

     if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:ANCS_CHARACTERISTIC_UUID]]) {
         [peripheral setNotifyValue:YES forCharacteristic:characteristic];
     }
    
  7. If you want to check if those characteristics are have started notifying, do a if(characteristic.isNotifying) in didUpdateNotificationStateForCharacteristic.

  8. You will get the actual NSData updates in didUpdateValueForCharacteristic with characteristic.value. The important thing to note here is that you will get informed of notification events by the Notification Source characteristic, but these will not contain that much information. If you want your Mac to play a sound or flash some Hue lights or something like that for every iOS notification, this will suffice. However, for the actual notification details, it will need to come from the Data Source characteristic, but you need to request for them by making very specific calls to the Control Point characteristic. This is where it gets really complicated, and you'll be able to get more information in the official ANCS Specification document.

  9. If you want a shortcut or a look at how others have done it, check out these Github repos:

    Just be careful as you may find bugs in some of these implementations, mainly in the processing of data sent by the ANCS Data Source (I had to get creative with my own error handling).

*** Some may argue that you can use "Service Solicitation" to expose ANCS without having an app running on the iOS device and/or without advertising a dummy Service (see options parameter in Step 2), but I haven't had that much success with it so perhaps there's something I'm missing.

Upvotes: 9

Related Questions