iPhone and BlueTooth Enabled Device Communication Using NodeJS and iOS7’s ANCS

With iOS7 Apple have allowed access to the Apple Notification Center Service (ANCS) and it has opened up a lot of fun opportunities to develop for connected devices. Essentially the ANCS allows Bluetooth Low Energy (BTLE) devices to listen and respond to your iPhone’s local notifications. With the current proliferation of BTLE enabled devices (Pebble, FuelBand, Estimote etc) and DIY kits such as Arduino and Raspberry Pi making it easy to connect BTLE dongles, there are immense opportunities in developing ways to communicate between devices outside of the mobile world.

The ANCS has quite a lot to it but in keeping with the spirit of my blog I’m going to make this as simple as possible. It’s a fun technology to play around with and easy to get going. It’s also very easy to get bogged down in the technicalities, feel free to do that later on in your own time. I definitely recommend you read the Apple docs to get an idea of all the possibilities and limitations of the ANCS.

In this post we’re going to be responding to notifications sent from an iPhone (Notification Provider) to your Mac (Notification Consumer) running NodeJS to access the ANCS. You can replace “your Mac” with any BLE connected device running NodeJS, eg Raspberry Pi etc. I’m going to be using this really useful NodeJS lib to get the the Mac set up as the Notification Consumer and the iPhone app will instantiate a CBPeripheralManager object and it’s required delegate method to start advertising to the NodeJS app handling the ANCS. Your Mac will need to support BTLE (Bluetooth 4.0) or have a BLE dongle.

You can download the finished iOS project here. Download the NodeJS stuff here, unzip it (or check it out), navigate to the folder using the Terminal and run the test.js file in the Terminal as you would any Node app. If you don’t have NodeJS installed or you don’t know anything about NodeJS, check out this link on setting it up. NodeJS is a great JavaScript framework for creating applications and is really easy to get your head around and get going. When it starts up you should see something like this:

$ node test.js
discovered
connected
services and characteristics discovered

Now for the iOS development. Make sure you’ve added the CoreBluetooth framework to the project’s build phases, set your viewController to conform to the CBPeripheralManagerDelegate and make an instance of the CBPeripheralManager in the .h file.

#import <CoreBluetooth/CoreBluetooth.h>

@interface ViewController : UIViewController <CBPeripheralManagerDelegate>

@property (strong, nonatomic) CBPeripheralManager *peripheralManager;

@end

In the .m file I have a method fireNotification that responds to a UIButton tap with a local notification being fired. CBPeripheralManagerDelegate has one required delegate method, peripheralManagerDidUpdateState, where we use the peripheralManager to start and stop advertising our iPhone device, it takes a dictionary of advertising data types for the consumers of the notification.

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
	
    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
}

// Fire a local notification for the Notification Consumer, in this case NodeJS app running on Mac OSX to respond to
- (IBAction)fireNotification:(id)sender
{
    UIApplication *app                = [UIApplication sharedApplication];
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    
    if (notification == nil)return;
    
    notification.alertBody = @"This is the notification alertBody";
    notification.alertAction = @"notification alertAction";
    notification.soundName = UILocalNotificationDefaultSoundName;
    notification.applicationIconBadgeNumber = 1;
    
    [app presentLocalNotificationNow:notification];
    
}

// Required delegate method
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
    if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
        NSLog(@"STARTED ADVERTISING");
        [self.peripheralManager startAdvertising:@{ CBAdvertisementDataLocalNameKey: [[UIDevice currentDevice] name] }];
                                                   
                                                   
    } else {
        NSLog(@"STOP ADVERTISING");
        [self.peripheralManager stopAdvertising];
    }
}

@end

When you run the iPhone app within range of your Mac running the NodeJS ANCS lib and fire a notification (after being prompted to pair with the Mac) you’ll see something like this in Terminal:


notification: {"event":"added","flags":["silent","important"],"category":"missedCall","categoryCount":1,"uid":0}
notification: {"event":"added","flags":[],"category":"other","categoryCount":1,"uid":1}
notification: {"event":"added","flags":[],"category":"other","categoryCount":2,"uid":2}
	appIdentifier = com.ANCSExample
	title = ANCSExample
	subtitle = 
	date = Fri Feb 14 2014 10:29:50 GMT-0500 (EST)
	appIdentifier = com.ANCSExample
	title = ANCSExample
	subtitle = 
	date = Sat Feb 15 2014 21:53:28 GMT-0500 (EST)
	message = This is a notification
	message = This is a notification
{ appIdentifier: 'com.ANCSExample',
  title: 'ANCSExample',
  subtitle: '',
  message: 'This is a notification',
  date: Fri Feb 14 2014 10:29:50 GMT-0500 (EST) }

One comment

  1. Thanks for this post. Sometimes just a short basic example is exactly what I need but so hard to find. This post was perfect!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *