Format APNS-style JSON message in Python for use w

2019-03-11 02:08发布

问题:

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?

回答1:

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')


回答2:

When I use the SNS publish tool it autogenerates JSON that looks like this:

{ 
    "default": "<enter your message here>", 
    "email": "<enter your message here>", 
    "sqs": "<enter your message here>", 
    "http": "<enter your message here>", 
    "https": "<enter your message here>", 
    "sms": "<enter your message here>", 
    "APNS": "{\"aps\":{\"alert\": \"<message>\",\"sound\":\"default\"} }", 
    "GCM": "{ \"data\": { \"message\": \"<message>\" } }", 
    "ADM": "{ \"data\": { \"message\": \"<message>\" } }" 
 }

This looks closer to the spec talked about by apple in their "Notification Payload" section. Where they state that the message should be

a JSON dictionary object (as defined by RFC 4627). 
This dictionary must contain another dictionary identified by the key aps.
The aps dictionary contains one or more properties

Have you tried providing a message closer to that specification? Something like this for instance:

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

Or following the example from the publish SNS publish tool:

{
    'default':'default message',
    'APNS': {
        'aps':{
            'alert':'inner message',
            'sound':'mySound.caf'
         }\
     }
 }

Maybe also using their backslash escaping.