Skip to content

Instantly share code, notes, and snippets.

@ArchieR7
Created April 26, 2017 06:27
Show Gist options
  • Save ArchieR7/500a3831f14ef4c88987659854ae99f3 to your computer and use it in GitHub Desktop.
Save ArchieR7/500a3831f14ef4c88987659854ae99f3 to your computer and use it in GitHub Desktop.
python apple push notification server by auth key
# -*- coding: utf8 -*-
import jwt
import time
import json
import os
from hyper import HTTPConnection
class ApnsPusher:
def __init__(self, apns_key_id = '', apns_key_name = '.p8', team_id = '', bundle_id = ''):
self.ALGORITHM = 'ES256'
self.APNS_KEY_ID = apns_key_id
self.APNS_AUTH_KEY = os.path.dirname(os.path.realpath(__file__)) + '/' + apns_key_name
self.TEAM_ID = team_id
self.BUNDLE_ID = bundle_id
def push(self, title, body, device_token, isProduction):
file = open(self.APNS_AUTH_KEY)
secret = file.read()
token = jwt.encode({
'iss': self.TEAM_ID,
'iat': time.time()
},
secret,
algorithm = self.ALGORITHM,
headers = {
'alg': self.ALGORITHM,
'kid': self.APNS_KEY_ID,
}
)
path = '/3/device/{0}'.format(device_token)
request_headers = {
'apns-expiration': '0',
'apns-priority': '10',
'apns-topic': self.BUNDLE_ID,
'authorization': 'bearer {0}'.format(token.decode('ascii'))
}
if isProduction:
conn = HTTPConnection('api.push.apple.com:443')
else :
conn = HTTPConnection('api.development.push.apple.com:443')
payload_data = {
'aps': {
'alert': {
'title': title,
'body': body
},
'badeg': 1,
'sound': 'default'
}
}
payload = json.dumps(payload_data).encode('utf-8')
conn.request(
'POST',
path,
payload,
headers=request_headers
)
resp = conn.get_response()
print(resp.status)
print(resp.read())
@gunnartorfis
Copy link

gunnartorfis commented May 5, 2017

Hi Archie.

I'm trying to send push notifications with Python and this gist is by far the best looking I've seen so far, there are limited resources for the new .p8 files.

However, I keep getting an exception. I'd appreciate it a lot if you can help me out here.

Traceback (most recent call last): File "/usr/local/lib/python2.7/dist-packages/bottle.py", line 862, in _handle return route.call(**args) File "/usr/local/lib/python2.7/dist-packages/bottle.py", line 1740, in wrapper rv = callback(*a, **ka) File "web_server.py", line 19, in open send_ring_push() File "web_server.py", line 57, in send_ring_push pusher.push('Hallo', 'Bodybody', deviceToken, False) File "/home/pi/Projects/raspberry-hringbraut/apns.py", line 60, in push resp = conn.get_response() File "/usr/local/lib/python2.7/dist-packages/hyper/common/connection.py", line 129, in get_response return self._conn.get_response(*args, **kwargs) File "/usr/local/lib/python2.7/dist-packages/hyper/http11/connection.py", line 203, in get_response self._sock.fill() File "/usr/local/lib/python2.7/dist-packages/hyper/common/bufsocket.py", line 169, in fill raise ConnectionResetError() ConnectionResetError

@ArchieR7
Copy link
Author

@gunnartorfis

I use python 3.6 and not getting an exception like yours, maybe you can try that version?

@pmaddi
Copy link

pmaddi commented Nov 4, 2018

@gunnartorfis I have the same issue, have you found a fix?

@DataGreed
Copy link

Have you succeed in finding a fix?

@harr1424
Copy link

harr1424 commented Nov 2, 2022

This is a fantastic example. I've run into a problem though. Calling .decode('ascii') on the generated token when packaging as request header throws AttributeError: 'str' object has no attribute 'decode'

Omitting the call to .decode() results in TypeError: Object of type bytes is not JSON serializable.

Has anyone else encountered this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment