Format APNS-style JSON message in Python for use with Amazon SNS

bryanjclark picture bryanjclark · Nov 21, 2013 · Viewed 10.7k times · Source

I'm creating an iOS app, and for our push notifications, we're using Amazon's Simple Notification Service (SNS).

SNS is wonderful, but the documentation is pretty sparse. I'm using boto, Amazon's Python library, and I've figured out how to send plain-text push notifications:

device_arn = 'MY ENDPOINT ARN GOES HERE'
plain_text_message = 'a plaintext message'
sns.publish(message=plain_text_message,target_arn=device_arn)

However, what's not clear from the documentation is how to create an an Apple Push Notification Service (APNS) message. I need to send a sound and a badge along with the push notification, but can't figure out how to format the JSON for the message.

Here's my best guess so far:

message = {'default':'default message', 'message':{'APNS_SANDBOX':{'aps':{'alert':'inner message','sound':'mySound.caf'}}}}
messageJSON = json.dumps(message,ensure_ascii=False)
sns.publish(message=messageJSON,target_arn=device_arn,message_structure='json')

When I run this code, though, all I see on the notification is "default message" - which means that Amazon SNS rejected my message's format, and displayed the default instead.

How do I format this JSON correctly?

Answer

bryanjclark picture bryanjclark · Nov 22, 2013

I figured it out! Turns out, the APNS payload has to be encoded as a string within the larger payload - and it totally works.

Here's the final, working code:

apns_dict = {'aps':{'alert':'inner message','sound':'mySound.caf'}}
apns_string = json.dumps(apns_dict,ensure_ascii=False)
message = {'default':'default message','APNS_SANDBOX':apns_string}
messageJSON = json.dumps(message,ensure_ascii=False)
sns.publish(message=messageJSON,target_arn=device_arn,message_structure='json')

Here's a walkthrough of what's going on in this code:

First, create the python dictionary for APNS:

apns_dict = {'aps':{'alert':'inner message','sound':'mySound.caf'}}

Second, take that dictionary, and turn it into a JSON-formatted string:

apns_string = json.dumps(apns_dict,ensure_ascii=False)

Third, put that string into the larger payload:

message = {'default':'default message','APNS_SANDBOX':apns_string}

Next, we encode that in its own JSON-formatted string:

messageJSON = json.dumps(message,ensure_ascii=False)

The resulting string can then be published using boto:

sns.publish(message=messageJSON,target_arn=device_arn,message_structure='json')