-
Notifications
You must be signed in to change notification settings - Fork 48
Apple Push Notifications
Karambir Singh Nain edited this page Jan 13, 2016
·
2 revisions
To send push notifications to apple devices, we have to send our requests to Apple push notification service(APNs). We are using django-push-notifications package for this. It implements Device models that can send messages through APNS and GCM. It also implements an admin panel and DRF api views. A simple setup will need following:
- Install
django-push-notifications
with pip and addpush_notifications
to INSTALLED_APPS in settings. - APns provides a set to certificates for authentication that we have to provide to django-push-notifications. We will have an environment variable that will control which APN certificate and gateway to use(sandbox or prod).
- Create a directory
certs
underROOT_DIR
. Put both certificates, sandbox and prod in it and name themapns_sandbox.pem
andapns_prod.pem
. - Add following code your settings:
CERTS_DIR = ROOT_DIR.path('certs')
# Determines whether to use APNS SANDBOX OR PROD settings
# Should be True for dev and False for qa and prod environment
PUSH_NOTIFICATIONS_DEBUG = env('PUSH_NOTIFICATIONS_DEBUG', default='sandbox')
CERTS_CHOICES = {
'sandbox': {
'cert': 'dev.pem',
'apns_host': 'gateway.sandbox.push.apple.com',
'apns_feedback': 'feedback.sandbox.push.apple.com'
},
'prod': {
'cert': 'prod.pem',
'apns_host': 'gateway.push.apple.com',
'apns_feedback': 'feedback.push.apple.com'
},
}
PUSH_NOTIFICATIONS_SETTINGS = {
'APNS_CERTIFICATE': str(CERTS_DIR.path(CERTS_CHOICES[PUSH_NOTIFICATIONS_DEBUG]['cert'])),
'APNS_HOST': CERTS_CHOICES[PUSH_NOTIFICATIONS_DEBUG]['apns_host'],
'APNS_FEEDBACK_HOST': CERTS_CHOICES[PUSH_NOTIFICATIONS_DEBUG]['apns_feedback'],
}
Points to Remember
- We have to give pathname to these certificate files, as underlying python socket library expect a valid filename.
- These file should not be password protected.
To check if the certs are setup correctly, try sending push notifications via admin to test feedback service, try this management command:
python manage.py prune_devices
You are all set after this. It is advised to use your own view logic as the default api views are somewhat glitch-y. You can use following:
from rest_framework import status
from rest_framework.response import Response
from push_notifications.api.rest_framework import APNSDeviceAuthorizedViewSet as PNAPNSDeviceAuthorizedViewSet
from push_notifications.models import APNSDevice
class APNSDeviceAuthorizedViewSet(PNAPNSDeviceAuthorizedViewSet):
"""
Register an iOS device for push notifications
"""
def create(self, request, *args, **kwargs):
"""
Get or create a device for a user. If the device with the
`registration_id` exists already and another user registers, assign
the device to the new user.
"""
# Default status code to expect
status_code = status.HTTP_201_CREATED
existing_device = APNSDevice.objects.filter(
registration_id=request.data.get('registration_id')
).first()
if existing_device:
if existing_device.user == request.user:
status_code = status.HTTP_200_OK
return Response(
self.serializer_class(existing_device).data,
status=status_code
)
existing_device.delete()
# Device doesn't exist, create a new one for the user
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status_code, headers=headers)
Api View features:
- ios app to only send the apns token (
registration_id
), and backend to add a new entry if the apns device token doesn't already exist - ios app makes a
post
request with both apns device token. Backend to update/add entry based on the apns token (registration_id
) -
device_id
is being ignored for now. - If another user enters the same apns token (
registration_id
), delete the existing device, and create a new device assigning it to the new user. -
POST
toapi/devices/apns
when the device withe theregistration_id
already exists for that user will return the existing device instead of a400
per iOS request