django-push-notifications-(复制于github)
A minimal Django app that implements Device models that can send messages through APNS, FCM/GCM and WNS.
- The app implements three models:
GCMDevice,APNSDeviceandWNSDevice. Those models share the same attributes: -
name(optional): A name for the device.active(default True): A boolean that determines whether the device will be sent notifications.user(optional): A foreign key to auth.User, if you wish to link the device to a specific user.device_id(optional): A UUID for the device obtained from Android/iOS/Windows APIs, if you wish to uniquely identify it.registration_id(required): The FCM/GCM registration id or the APNS token for the device.
The app also implements an admin panel, through which you can test single and bulk notifications. Select one or more FCM/GCM, APNS or WNS devices and in the action dropdown, select "Send test message" or "Send test message in bulk", accordingly. Note that sending a non-bulk test message to more than one device will just iterate over the devices and send multiple single messages. UPDATE_ON_DUPLICATE_REG_ID: Transform create of an existing Device (based on registration id) into a update. See below Update of device with duplicate registration ID for more details.
Dependencies
- Python 2.7 or 3.4+
- Django 1.11+
- For the API module, Django REST Framework 3.7+ is required.
- For WebPush (WP), pywebpush 1.3.0+ is required. py-vapid 1.3.0+ is required for generating the WebPush private key; however this step does not need to occur on the application server.
Setup
You can install the library directly from pypi using pip:
$ pip install django-push-notifications
Edit your settings.py file:
INSTALLED_APPS = (
...
"push_notifications"
)
PUSH_NOTIFICATIONS_SETTINGS = {
"FCM_API_KEY": "[your api key]",
"GCM_API_KEY": "[your api key]",
"APNS_CERTIFICATE": "/path/to/your/certificate.pem",
"APNS_TOPIC": "com.example.push_test",
"WNS_PACKAGE_SECURITY_ID": "[your package security id, e.g: 'ms-app://e-3-4-6234...']",
"WNS_SECRET_KEY": "[your app secret key, e.g.: 'KDiejnLKDUWodsjmewuSZkk']",
"WP_PRIVATE_KEY": "/path/to/your/private.pem",
"WP_CLAIMS": {'sub': "mailto: development@example.com"}
}
Note
If you are planning on running your project with APNS_USE_SANDBOX=True, then make sure you have set the developmentcertificate as your APNS_CERTIFICATE. Otherwise the app will not be able to connect to the correct host. See settings for details.
You can learn more about APNS certificates here.
Native Django migrations are in use. manage.py migrate will install and migrate all models.
Settings list
All settings are contained in a PUSH_NOTIFICATIONS_SETTINGS dict.
In order to use FCM/GCM, you are required to include FCM_API_KEY or GCM_API_KEY. For APNS, you are required to include APNS_CERTIFICATE. For WNS, you need both the WNS_PACKAGE_SECURITY_KEY and the WNS_SECRET_KEY.
General settings
USER_MODEL: Your user model of choice. Eg.myapp.User. Defaults tosettings.AUTH_USER_MODEL.UPDATE_ON_DUPLICATE_REG_ID: Transform create of an existing Device (based on registration id) into a update. See below Update of device with duplicate registration ID for more details.
APNS settings
APNS_CERTIFICATE: Absolute path to your APNS certificate file. Certificates with passphrases are not supported.APNS_TOPIC: The topic of the remote notification, which is typically the bundle ID for your app. If you omit this header and your APNs certificate does not specify multiple topics, the APNs server uses the certificate’s Subject as the default topic.APNS_USE_ALTERNATIVE_PORT: Use port 2197 for APNS, instead of default port 443.APNS_USE_SANDBOX: Use 'api.development.push.apple.com', instead of default host 'api.push.apple.com'.
FCM/GCM settings
FCM_API_KEY: Your API key for Firebase Cloud Messaging.FCM_POST_URL: The full url that FCM notifications will be POSTed to. Defaults to https://fcm.googleapis.com/fcm/send.FCM_MAX_RECIPIENTS: The maximum amount of recipients that can be contained per bulk message. If theregistration_idslist is larger than that number, multiple bulk messages will be sent. Defaults to 1000 (the maximum amount supported by FCM).FCM_ERROR_TIMEOUT: The timeout on FCM POSTs.GCM_API_KEY,GCM_POST_URL,GCM_MAX_RECIPIENTS,GCM_ERROR_TIMEOUT: Same parameters for GCM
WNS settings
WNS_PACKAGE_SECURITY_KEY: TODOWNS_SECRET_KEY: TODO
WP settings
- Install:
pip install pywebpush
pip install py-vapid (Only for generating key)
-
Getting keys:
- Create file (claim.json) like this:
{
"sub": "mailto: development@example.com",
"aud": "https://android.googleapis.com"
}
- Generate public and private keys:
vapid --sign claim.json
No private_key.pem file found.
Do you want me to create one for you? (Y/n)Y
Do you want me to create one for you? (Y/n)Y
Generating private_key.pem
Generating public_key.pem
Include the following headers in your request:
Crypto-Key: p256ecdsa=BEFuGfKKEFp-kEBMxAIw7ng8HeH_QwnH5_h55ijKD4FRvgdJU1GVlDo8K5U5ak4cMZdQTUJlkA34llWF0xHya70
Authorization: WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL2FuZHJvaWQuZ29vZ2xlYXBpcy5jb20iLCJleHAiOiIxNTA4NDkwODM2Iiwic3ViIjoibWFpbHRvOiBkZXZlbG9wbWVudEBleGFtcGxlLmNvbSJ9.r5CYMs86X3JZ4AEs76pXY5PxsnEhIFJ-0ckbibmFHZuyzfIpf1ZGIJbSI7knA4ufu7Hm8RFfEg5wWN1Yf-dR2A
- Generate client public key (applicationServerKey)
vapid --applicationServerKey
Application Server Key = BEFuGfKKEFp-kEBMxAIw7ng8HeH_QwnH5_h55ijKD4FRvgdJU1GVlDo8K5U5ak4cMZdQTUJlkA34llWF0xHya70
- Configure settings:
WP_PRIVATE_KEY: Absolute path to your private certificate file: os.path.join(BASE_DIR, "private_key.pem")WP_CLAIMS: Dictionary with the same sub info like claims file: {'sub': "mailto: development@example.com"}WP_ERROR_TIMEOUT: The timeout on WebPush POSTs. (Optional)WP_POST_URL: A dictionary (key per browser supported) with the full url that webpush notifications will be POSTed to. (Optional)- Configure client (javascript):
// Utils functions:
function urlBase64ToUint8Array (base64String) {
var padding = '='.repeat((4 - base64String.length % 4) % 4)
var base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/')
var rawData = window.atob(base64)
var outputArray = new Uint8Array(rawData.length)
for (var i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i)
}
return outputArray;
}
function loadVersionBrowser (userAgent) {
var ua = userAgent, tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if (/trident/i.test(M[1])) {
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return {name: 'IE', version: (tem[1] || '')};
}
if (M[1] === 'Chrome') {
tem = ua.match(/\bOPR\/(\d+)/);
if (tem != null) {
return {name: 'Opera', version: tem[1]};
}
}
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
if ((tem = ua.match(/version\/(\d+)/i)) != null) {
M.splice(1, 1, tem[1]);
}
return {
name: M[0],
version: M[1]
};
};
var applicationServerKey = "BEFuGfKKEFp-kEBMxAIw7ng8HeH_QwnH5_h55ijKD4FRvgdJU1GVlDo8K5U5ak4cMZdQTUJlkA34llWF0xHya70";
....
// In your ready listener
if ('serviceWorker' in navigator) {
// The service worker has to store in the root of the app
// http://stackoverflow.com/questions/29874068/navigator-serviceworker-is-never-ready
var browser = loadVersionBrowser();
navigator.serviceWorker.register('navigatorPush.service.js?version=1.0.0').then(function (reg) {
reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(applicationServerKey)
}).then(function (sub) {
var endpointParts = sub.endpoint.split('/');
var registration_id = endpointParts[endpointParts.length - 1];
var data = {
'browser': browser.name.toUpperCase(),
