Setting Up Uniqush With APNS
This walks you through running Uniqush in the cloud (under Docker) and setting up an iOS app to receive messages via APNS (Apple Push Notification Service).
Run Uniqush under Docker
Install Docker components
Config
mkdir -p volumes/uniqushwget https://git.io/vgSYM -O volumes/uniqush/uniqush-push.conf
Security note: the above config has Uniqush listening on all interfaces, but depending on your setup you probably want to change that to localhost or something more restrictive.
Docker compose file
Copy and paste this content into docker-compose.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
version: '2'
services:
uniqush:
container_name: uniqush
ports:
- "9898:9898"
image: tleyden5iwx/uniqush
entrypoint: uniqush-push
links:
- redis
volumes:
- ~/docker/volumes/uniqush/uniqush-push.conf:/etc/uniqush/uniqush-push.conf
redis:
container_name: redis
image: redis
Start docker containers
1
$ docker compose up -dVerify Uniqush is running
Run this curl command outside of the docker container to verify that Uniqush is responding to HTTP requests:
1 2
$ curl localhost:9898/version
uniqush-push 1.5.2Create APNS certificate
In my case, I already had an app id for my app (com.couchbase.todolite), but push notifications are not enabled, so I needed to enable them:
screenshot
Create a new push cert:
screenshot
Choose the correct app id:
screenshot
Generate CSR according to instructions in keychain:
screenshot
This will save a CSR on your file system, and the next wizard step will ask you to upload this CSSR and generate the certificate. Now you can download it:
screenshot
Double click the downloaded cert and it will be added to your keychain.
This is where I got a bit confused, since I had to also download the cert from the app id section — go to the app id and hit “Edit”, then download the cert and double click it to add to your keychain. (I’m confused because I thought these were the same certs and this second step felt redundant)
screenshot
Create and use provisioning profile
Go to the Provisioning Profiles / Development section and hit the “+” button:
screenshot
Choose all certs and all devices, and then give your provisioning profile an easy to remember name.
screenshot
Download this provisioning profile and double click it to install it.
In xcode under Build Settings, choose this provisioning profile:
screenshot
Register for push notifications in your app
Add the following code to your didFinishLaunchingWithOptions::
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Register for push notifications
if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
{
// iOS 8 Notifications
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[application registerForRemoteNotifications];
}
else
{
// iOS < 8 Notifications
[application registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
}
// rest of your code goes here ...
}And the following callback methods which will be called if remote notification is successful:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *deviceTokenStr = [NSString stringWithFormat:@"%@",deviceToken];
NSLog(@"didRegisterForRemoteNotificationsWithDeviceToken, Device token: %@", deviceTokenStr);
NSString* deviceTokenCleaned = [[[[deviceToken description]
stringByReplacingOccurrencesOfString: @"<" withString: @""]
stringByReplacingOccurrencesOfString: @">" withString: @""]
stringByReplacingOccurrencesOfString: @" " withString: @""];
NSLog(@"didRegisterForRemoteNotificationsWithDeviceToken, Cleaned device token token: %@", deviceTokenCleaned);
}and this callback which will be called if it’s not unsuccessful:
1 2 3 4 5
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err
{
NSString *str = [NSString stringWithFormat: @"Error: %@", err];
NSLog(@"Error registering device token. Push notifications will not work%@", str);
}
If you now run this app on a simulator, you can expect an error like Error registering device token. Push notifications will not workError.
Run the app on a device you should see a popup dialog in the app asking if it’s OK to receive push notifications, and the following log messages in the xcode console:
1 2
didRegisterForRemoteNotificationsWithDeviceToken, Device token: <281c8710 1b029fdb 16c8e134 39436336 116001ce bf6519e6 8edefab5 23dab4e9>
didRegisterForRemoteNotificationsWithDeviceToken, Cleaned device token token: 281c87101b029fdb16c8e13439436336116001cebf6519e68edefab523dab4e9Export APNS keys to .PEM format
Open keychain, select the login keychain and the My Certificates category:
screenshot
- Right click on the certificate (not the private key) "Apple Development Push Services: (your app id)"
- Choose Export "Apple Development Push Services: (your app id)′′.
- Save this as
apns-prod-cert.p12file somewhere you can access it. - When it prompts you for a password, leave it blank (or add one if you want, but this tutorial will assume it was left blank)
- Repeat with the private key (in this case, TodoLite Push Notification Cert) and save it as
apns-prod-key.p12.
Now they need to be converted from .p12 to .pem format.
1 2 3
$ openssl pkcs12 -clcerts -nokeys -out apns-prod-cert.pem -in apns-prod-cert.p12
Enter Import Password: <return>
MAC verified OK1 2 3 4
$ openssl pkcs12 -nocerts -out apns-prod-key.pem -in apns-prod-key.p12
Enter Import Password:
MAC verified OK
Enter PEM pass phrase: hello <return>Remove the PEM passphrase:
1 2 3
$ openssl rsa -in apns-prod-key.pem -out apns-prod-key-noenc.pem
Enter pass phrase for apns-prod-key.pem: hello
writing RSA keyAdd PEM files to Uniqush docker container
When you call the Uniqush REST API to add a Push Service Provider, it expects to find the PEM files on it’s local file system. Use the following commands to get these files into the running container in the /tmp directory:
1 2 3
$ `container=$(docker ps | grep -i uniqush-push | awk '{print 1ドル}')`
$ docker cp /tmp/apns-prod-cert.pem $container:/tmp/apns-prod-cert.pem
$ docker cp /tmp/apns-prod-key-noenc.pem $container:/tmp/apns-prod-key-noenc.pemCreate APNS provider in Uniqush via REST API
1 2 3 4 5
$ curl -v http://localhost:9898/addpsp -d service=myservice \
-d pushservicetype=apns \
-d cert=/tmp/apns-prod-cert.pem \
-d key=/tmp/apns-prod-key-noenc.pem \
-d sandbox=true(Note: I’m using a development cert, but if this was a distribution cert you’d want to use sandbox=false)
You should get a 200 OK response with:
1
[AddPushServiceProvider][Info] 2016年02月03日 20:35:29 From=24.23.246.59:59447 Service=myservice PushServiceProvider=apns:9f49c9c618c97bebe21bea159d3c7a8577934bdf00 Success!Add Uniqush subscriber
Using the cleaned up device token from the previous step 281c87101b029fdb16c8e13439436336116001cebf6519e68edefab523dab1e9, create a subscriber with the name mytestsubscriber via:
1 2 3 4
$ curl -v http://localhost:9898/subscribe -d service=myservice \
-d subscriber=mytestsubscriber \
-d pushservicetype=apns \
-d devtoken=281c87101b029fdb16c8e13439436336116001cebf6519e68edefab523dab1e9 You should receive a 200 OK response with:
1
[Subscribe][Info] 2016年02月03日 20:43:21 From=24.23.246.59:60299 Service=myservice Subscriber=mytestsubscriber PushServiceProvider=apns:9f49c9c618c97bebe21bea159d3c7a8577934bdf00 DeliveryPoint=apns:2cbecd0798cc6731d96d5b0fb01d813c7c9a83af00 Success!Push a test message
The moment of truth!
First, you need to either background your app by pressing the home button, or add some code like this so that an alert will be shown if the app is foregrounded.
1 2 3
$ curl -v http://localhost:9898/push -d service=myservice \
-d subscriber=mytestsubscriber \
-d msg=HelloWorldYou should get a 200 OK response with:
1 2
[Push][Info] 2016年02月03日 20:46:08 RequestId=56b26710-INbW8UWMUONtH8Ttddd2Qg== From=24.23.246.59:60634 Service=myservice NrSubscribers=1 Subscribers="[mytestsubscriber]"
[Push][Info] 2016年02月03日 20:46:09 RequestID=56b26710-INbW8UWMUONtH8Ttddd2Qg== Service=myservice Subscriber=mytestsubscriber PushServiceProvider=apns:9f49c9c618c97bebe21bea159d3c7a8577934bdf00 DeliveryPoint=apns:2cbecd0798cc6731d96d5b0fb01d813c7c9a83af MsgId=apns:apns:9f49c9c618c97bebe21bea159d3c7a8577934bdf-1 Success!And a push notification on the device!
screenshot