4

I'm trying to send push notifications using the APNS from Python (I know there are lots of libraries that do just that, but this has pedagogic intentions).

I started using this script (source):

def send_push(token, payload):
 # Your certificate file
 cert = 'ck.pem'
 # APNS development server
 apns_address = ('gateway.sandbox.push.apple.com', 2195)
 # Use a socket to connect to APNS over SSL
 s = socket.socket()
 sock = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3, certfile=cert)
 sock.connect(apns_address)
 # Generate a notification packet
 token = binascii.unhexlify(token)
 fmt = '!cH32sH{0:d}s'.format(len(payload))
 cmd = '\x00'
 message = struct.pack(fmt, cmd, len(token), token, len(payload), payload)
 sock.write(message)
 sock.close()

Which works, but Python 2.x only supports TSL until version 1. So I tried to run it using Python 3, and I get this error:

Traceback (most recent call last):
 File "push_notificator.py", line 52, in <module>
 send_notification(TOKEN, json.dumps(TEST_PAYLOAD))
 File "push_notificator.py", line 46, in send_push
 payload
struct.error: char format requires a bytes object of length 1

So it seems I must convert the payload to binary, but I'm really lost. This is the first time that I work with binary data on Python.

asked Jul 22, 2015 at 0:31

2 Answers 2

3

@cdonts's answer ultimately helped me out, but i thought it might be cleaner in a separate answer, instead of a comment...

@cdonts's answer: https://stackoverflow.com/a/31551978/2298002

I had to encode both cmd as well as payload, before packing. here is my code that solved it...

cmd = bytes(cmd, "utf-8")
payload = bytes(payload, "utf-8")

here is a longer code snippet to demonstrate in context...

token = "<string apns token from iOS client side>"
try:
 token = binascii.unhexlify(token)
 payload = json.dumps(payload)
 fmt = "!cH32sH{0:d}s".format(len(payload))
 cmd = '\x00'
 #python3 requirement
 cmd = bytes(cmd, "utf-8")
 payload = bytes(payload, "utf-8")
 msg = struct.pack(fmt, cmd, len(token), token, len(payload), payload)
except Exception as e: # ref:
 print(e) 

@cdonts THANK YOU!! (https://stackoverflow.com/a/31551978/2298002)

answered May 24, 2020 at 21:58
Sign up to request clarification or add additional context in comments.

Comments

2

In Python 3.x use:

bytes(payload, "utf-8")

Replace utf-8 with the necessary encoding.

Hope it helps.

answered Jul 22, 2015 at 0:39

5 Comments

Thanks for your answer @cdonts. Unfortunately it doesn't work, I get the same error: struct.error: char format requires a bytes object of length 1.
@Tae Maybe the object length is greater than 1 or the problem is with token instead of payload.
If that were the case then the error would occur running the code under Python 2 too. Finally I tried another format: !BH32sH%ds, but I'm still puzzled about why the other one works with Python 2 but not with Python 3. As far as I know the syntax is the same.
what is the fully executable code? Could you paste that out? Thanks!
@cdonts's answer helped solved my problem (with an additional step), and without having to change formats, thank you! i posted a new answer that provides more detail: stackoverflow.com/a/61992926/2298002

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.