React Native - Push Notifications ====================================== I'm going to use Batch to make things easier. Install ----------- .. code-block:: bash npm install --save react-native-push-notification react-native link pip install python-gcm apns Client Side ----------------- Get the ID: **Android** https://developers.google.com/mobile/add **iOS** http://facebook.github.io/react-native/docs/integration-with-existing-apps.html#app-transport-security .. code-block:: bash sudo gem install fastlane fastlane pem Add the following to the client: .. code-block:: javascript var PushNotification = require('react-native-push-notification'); // THIS PART GOES OUTSIDE ALL CLASSES !!!!!!!!!! export function postForm(path, form) { const str = []; for (let p in form) { str.push(encodeURIComponent(p) + "=" + encodeURIComponent(form[p])); } const body = str.join("&"); const req = { method: 'post', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body }; return fetch(path, req); } // THIS PART GOES IN constructor(props) !!!!!!!!!!! PushNotification.configure({ // (optional) Called when Token is generated (iOS and Android) onRegister: function(t) { console.log(t) postForm('http://192.168.0.120:5020/', {token: t.token}) }, // (required) Called when a remote or local notification is opened or received onNotification: function(notification) { console.log( 'NOTIFICATION:', notification ); }, // ANDROID ONLY: GCM Sender ID (optional - not required for local notifications, but is need to receive remote push notifications) senderID: "", // IOS ONLY (optional): default: all - Permissions to register. permissions: { alert: true, badge: true, sound: true }, // Should the initial notification be popped automatically // default: true popInitialNotification: true, /** * (optional) default: true * - Specified if permissions (ios) and token (android and ios) will requested or not, * - if not, you must call PushNotificationsHandler.requestPermissions() later */ requestPermissions: true, }); **On Android, add the following to AndroidManifest.xml** .. code-block:: xml And then in the application brackets: .. code-block:: xml Server Side -------------- That's it for the client side. Now for the server side: .. code-block:: python from gcm import * from time import sleep #from apns import APNs, Frame, Payload from izzati import Backend gcm = GCM("AIzaSyBUXAxT9Nynnx6ZbQfjnZL9-Ep3d37wBxY") #apns = APNs(use_sandbox=True, cert_file='cert.pem') tokens = [] def callback(data, files): global gcm, tokens print(data) token = data['token'] tokens.append(token) tokens = list(set(tokens)) data = {'title': 'Test Notifications', 'message': 'Hello!'} #payload = Payload(alert="Hello World!", sound="default", badge=1, mutable_content=True) #apns.gateway_server.send_notification(token, payload) gcm.plaintext_request(registration_id=token, data=data) sleep(10) gcm.plaintext_request(registration_id=token, data=data) b = Backend(callback) b.run() For more info on the data input: https://developers.google.com/cloud-messaging/http-server-ref#notification-payload-support That's it! Expo - Push Notifications =========================== Install -------------- Install Expo as you usually would. **This will only work on a non-ejected Expo project!!!** Install the Python server side. .. code-block:: bash sudo pip install exponent_server_sdk izzati https://docs.expo.io/versions/v18.0.0/guides/push-notifications.html Client Side ---------------- .. code-block:: javascript import Expo from 'expo'; import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { Permissions, Notifications } from 'expo'; const PUSH_ENDPOINT = 'http://192.168.0.120:5020/'; export function postForm(path, form) { const str = []; for (let p in form) { str.push(encodeURIComponent(p) + "=" + encodeURIComponent(form[p])); } const body = str.join("&"); const req = { method: 'post', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body }; return fetch(path, req); } async function registerForPushNotificationsAsync() { const { existingStatus } = await Permissions.getAsync(Permissions.REMOTE_NOTIFICATIONS); let finalStatus = existingStatus; // only ask if permissions have not already been determined, because // iOS won't necessarily prompt the user a second time. if (existingStatus !== 'granted') { // Android remote notification permissions are granted during the app // install, so this will only ask on iOS const { status } = await Permissions.askAsync(Permissions.REMOTE_NOTIFICATIONS); finalStatus = status; } // Stop here if the user did not grant permissions if (finalStatus !== 'granted') { return; } // Get the token that uniquely identifies this device let t = await Notifications.getExponentPushTokenAsync(); // POST the token to our backend so we can use it to send pushes from there return postForm(PUSH_ENDPOINT, {token: t}) } class App extends React.Component { state = { notification: {}, }; componentWillMount() { registerForPushNotificationsAsync(); // Handle notifications that are received or selected while the app // is open. If the app was closed and then opened by tapping the // notification (rather than just tapping the app icon to open it), // this function will fire on the next tick after the app starts // with the notification data. this._notificationSubscription = Notifications.addListener(this._handleNotification); } _handleNotification = (notification) => { this.setState({notification: notification}); }; render() { return ( Origin: {this.state.notification.origin} Data: {JSON.stringify(this.state.notification.data)} ); } } The Server ----------------- .. code-block:: python from exponent_server_sdk import DeviceNotRegisteredError from exponent_server_sdk import PushClient from exponent_server_sdk import PushMessage from exponent_server_sdk import PushResponseError from exponent_server_sdk import PushServerError from requests.exceptions import ConnectionError from requests.exceptions import HTTPError from izzati import Backend from time import sleep # Basic arguments. You should extend this function with the push features you # want to use, or simply pass in a `PushMessage` object. # https://docs.expo.io/versions/v18.0.0/guides/push-notifications.html#http-2-api tokens = [] def send_push_message(token, message, extra=None): try: response = PushClient().publish( PushMessage(to=token, body=message, data=extra)) except PushServerError as exc: # Encountered some likely formatting/validation error. raise except (ConnectionError, HTTPError) as exc: # Encountered some Connection or HTTP error - retry a few times in # case it is transient. raise self.retry(exc=exc) try: # We got a response back, but we don't know whether it's an error yet. # This call raises errors so we can handle them with normal exception # flows. response.validate_response() except DeviceNotRegisteredError: # Mark the push token as inactive from notifications.models import PushToken PushToken.objects.filter(token=token).update(active=False) except PushResponseError as exc: raise self.retry(exc=exc) def register_token(data, files): global tokens print(data) tokens.append(data['token']) sleep(10) send_push_message(data['token'], "hello") b = Backend(register_token) b.run()