-
-
Save hankkuu/73bb449fc231cda8b6b788b09cb304ed to your computer and use it in GitHub Desktop.
Firebase Cloud Messaging via AWS Lambda
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
shared util on React-Native src | |
*/ | |
import { | |
PushNotificationIOS, | |
Platform | |
} from 'react-native'; | |
import firebase from 'react-native-firebase'; | |
import appStore from '../stores/appStore'; // mobX | |
import { useFetch, useAjax, requests, handleConnectivityChange } from './Networking'; | |
import { encryptUserkey, decryptUserkey } from './Secure'; | |
import { getSingleData, storeSingleData, storeMultiData, storageKeys } from './ControlAsyncStorage'; | |
let notiChannelId = 0; | |
/** | |
* @name onRegister | |
* @param token | |
* @description get FCM token and send to AWS RDS server | |
*/ | |
const onRegister = (token) => { | |
console.log('[NotifService]TOKEN:', token); | |
/* Store to LocalStorage */ | |
storeSingleData(storageKeys.fcm_token, token); | |
/* Networking */ | |
useFetch(requests.setDeviceInfo, 'POST', { | |
user_key: encryptUserkey(appStore.userPhone), | |
token: token, | |
crud: 'U', | |
mode: 'token', | |
}).then((response) => { | |
console.log('[NotifService]response:', response); | |
// if (response.status === 200) { | |
// let result = response.body; | |
// } else { | |
// } | |
}).catch((error) => { | |
console.log('network catch:', error); | |
}); | |
} | |
/** | |
* @name onNotification | |
* @param {*} notification | |
*/ | |
const onNotification = (notification) => { | |
console.log('[NotifService:onNotification]notification:', notification); | |
console.log('[NotifService:onNotification]appStore.projInfo:', appStore.projInfo); | |
if (notification.data && notification.data.PROJ_ID === appStore.projInfo.PROJ_ID) { | |
if (appStore.notiEnabled === 'true') { | |
/* Display Notification */ | |
displayNotif(notification); | |
/* load TodoStatus */ | |
useFetch(requests.getTodoStatus, 'POST', { | |
user_key: encryptUserkey(appStore.userPhone), | |
}).then((response) => { | |
console.log('[Notif] checkTodo response:', response); | |
if (response.status === 200) { | |
let result = response.body; | |
/* Modify MobX */ | |
appStore.todoStatusCompleted = result.completed; | |
appStore.todoStatusIng = result.ing; | |
appStore.todoStatusDelay = result.delay; | |
} else { | |
/* */ | |
} | |
}).catch((error) => { | |
console.log('[Notif] checkTodo catch:', error); | |
}); | |
} | |
/* Assemble noti list */ | |
let noti_item = { | |
...notification.data, | |
CONTEXT: notification.body, | |
read: false, | |
} | |
/* Read AsyncStorage */ | |
getSingleData(storageKeys.noti_list).then((data) => { | |
console.log('[NotifService] get asyncstorage data', data); | |
/* Data of Async Storage */ | |
let noti_list; | |
if (!data) { | |
noti_list = []; | |
} else if (data && typeof data === 'string' && data.length > 0) { | |
noti_list = JSON.parse(data); | |
} else if (data && typeof data === 'object') { | |
noti_list = data; | |
} else { | |
noti_list = []; | |
} | |
noti_list.splice(0, 0, noti_item); | |
/* Modify MobX */ | |
appStore.notiList = noti_list; | |
return storeSingleData(storageKeys.noti_list, JSON.stringify(noti_list)) | |
}).then((isSaved) => { | |
console.log('[NotifService] after save asyncstorage', isSaved); | |
console.log('[NotifService] after save asyncstorage/appStore', appStore.getNotiList()); | |
}); | |
} else { | |
console.log('[NotifService]notification.proj_id != appStore.projInfo.PROJ_ID'); | |
} | |
} | |
const displayNotif = (notification) => { | |
notiChannelId++; | |
const { | |
body, | |
data, | |
notificationId, | |
sound, | |
subtitle, | |
title | |
} = notification; | |
console.log('[NotifService]displayNotif: ', title, body, JSON.stringify(data)); | |
/* Displaying Notification */ | |
const pushnotification = new firebase.notifications.Notification() | |
.setNotificationId(notificationId) | |
.setTitle(title) | |
.setBody(body) | |
.setData({ | |
worker: data.worker_id, | |
project: data.proj_id, | |
}); | |
if (Platform.OS === 'ios') { | |
pushnotification.ios.setBadge(2); | |
} else { | |
pushnotification | |
.android.setChannelId('reportAlarm') | |
.android.setSmallIcon('ic_stat_ic_notification') | |
.android.setVibrate([300]); | |
} | |
console.log("[NotifService]pushnotification:", pushnotification); | |
firebase.notifications().displayNotification(pushnotification); | |
}; | |
const initFirebaseMessaging = () => { | |
if (Platform.OS === 'android') { | |
/* Create Notif Channel */ | |
// Build a channel | |
const channel = new firebase.notifications.Android.Channel( | |
'reportAlarm', | |
'reportAlarm', | |
firebase.notifications.Android.Importance.Max | |
).setDescription('ProjectHUBCL'); | |
// Create the channel | |
firebase.notifications().android.createChannel(channel); | |
} | |
/* Init Cloud Message */ | |
return firebase.messaging().hasPermission().then(enabled => { | |
console.log('[NotifService] permission', enabled); | |
if (enabled) { | |
firebase.messaging().getToken().then((token) => { | |
console.log("[NotifService] getToken: ", token); | |
onRegister(token); | |
}); | |
// user has permissions | |
} else { | |
/* disabled */ | |
firebase.messaging().requestPermission() | |
.then(() => { | |
// alert("푸쉬알람을 받는 것을 허용하시겠습니까?"); | |
}) | |
.catch(error => { | |
// alert("Error", error) | |
// User has rejected permissions | |
}); | |
} | |
}); | |
} | |
const tokenRefreshListener = () => { | |
return firebase.messaging().onTokenRefresh(fcmToken => { | |
// Process your token as required | |
console.log("[NotifService] onTokenRefresh: ", fcmToken); | |
onRegister(fcmToken); | |
}); | |
} | |
const notificationListener = () => { | |
return firebase.notifications().onNotification((notification: Notification) => { | |
console.log("[NotifService:notificationListener]notification: ", notification); | |
/* notification constructure | |
{ | |
_android: { | |
_notification: [Circular], | |
_actions: [], | |
_people: [], | |
_smallIcon: { icon: 'ic_launcher' } | |
}, | |
_ios: { | |
_notification: [Circular], | |
_alertAction: undefined, | |
_attachments: [], | |
_badge: undefined, | |
_category: '', | |
_hasAction: undefined, | |
_launchImage: '', | |
_threadIdentifier: '' | |
}, | |
_body: 'myname', | |
_data: { | |
'google.c.a.ts': '1536079080', | |
'google.c.a.c_id': '8018338889909034580', | |
worker_id: 'worker', | |
'google.c.a.udt': '0', | |
'google.c.a.c_l': 'lbl', | |
'gcm.n.e': '1', | |
'google.c.a.e': '1', | |
proj_id: 'proj-48' | |
}, | |
_notificationId: '83687E73-5408-46FC-B3B1-BBEA5C924AC7', | |
_sound: undefined, | |
_subtitle: undefined, | |
_title: 'parameter 나갑니다잉' | |
} | |
*/ | |
onNotification(notification); | |
}); | |
} | |
const initFirebaseNotiOpenedListener = () => { | |
/* App in Foreground and background */ | |
this.notificationOpenedListener = firebase.notifications().onNotificationOpened((notificationOpen: NotificationOpen) => { | |
// Get the action triggered by the notification being opened | |
const action = notificationOpen.action; | |
// Get information about the notification that was opened | |
const notification: Notification = notificationOpen.notification; | |
console.log("[NotifService/onNotificationOpened] action:", action); | |
console.log("[NotifService/onNotificationOpened] notification:", notification); | |
}); | |
} | |
const getInitialNoti = () => { | |
firebase.notifications().getInitialNotification() | |
.then((notificationOpen: NotificationOpen) => { | |
console.log("[NotifService/getInitialNotification] notificationOpen:", notificationOpen); | |
if (notificationOpen) { | |
// App was opened by a notification | |
// Get the action triggered by the notification being opened | |
const action = notificationOpen.action; | |
// Get information about the notification that was opened | |
const notification: Notification = notificationOpen.notification; | |
} | |
}); | |
} | |
const toggleNoti = (bool) => { | |
const boolStr = (bool) ? 'true' : 'false'; | |
/* Store to MobX */ | |
appStore.notiEnabled = boolStr; | |
/* Store to LocalStorage */ | |
storeSingleData(storageKeys.notiEnabled, boolStr); | |
} | |
export { | |
initFirebaseMessaging, | |
tokenRefreshListener, | |
initFirebaseNotiOpenedListener, | |
notificationListener, | |
getInitialNoti, | |
toggleNoti, | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Firebase Push Noti를 구현한 실직적인 화면 in React-Native src | |
*/ | |
// @flow | |
import React, { Component } from 'react'; | |
import { | |
Platform, | |
StatusBar, | |
StyleSheet, | |
TouchableHighlight, | |
TouchableOpacity, | |
Image, | |
ScrollView, | |
Text, | |
View, | |
FlatList, | |
NetInfo, | |
Clipboard, | |
PushNotificationIOS, | |
AppState, | |
} from 'react-native'; | |
import { observer, inject } from 'mobx-react/native'; | |
import { SafeAreaView, NavigationScreenProp, NavigationStateRoute } from 'react-navigation'; | |
import { | |
retrieveAllData, getSingleData, storeSingleData, storeMultiData, multiRemoveData, storageKeys, setDidMountTodo, getDidMountTodo | |
} from '../../utils/ControlAsyncStorage'; | |
import { initFirebaseMessaging, initFirebaseNotiOpenedListener, notificationListener, tokenRefreshListener } from '../../utils/NotifService'; | |
type Props = { | |
store: any, | |
navigation: NavigationScreenProp<NavigationStateRoute>, | |
}; | |
type State = { | |
modalContext: string; | |
modalVisible: any; | |
title: string; | |
} | |
@inject('store') @observer | |
class Page extends Component<Props, State> { | |
static navigationOptions = { | |
header: null, | |
}; | |
// notiService; | |
notificationListener; | |
initFirebaseNotiOpenedListener; | |
onTokenRefreshListener; | |
constructor(props) { | |
super(props); | |
/* Firebase Noti */ | |
initFirebaseMessaging(); | |
this.onTokenRefreshListener = tokenRefreshListener(); | |
this.notificationListener = notificationListener(); | |
/* Load Noti Setting is Enabled | Disabled */ | |
getSingleData(storageKeys.notiEnabled).then((bool) => { | |
if (bool === null || bool === undefined) { | |
/* Store to MobX */ | |
this.props.store.notiEnabled = 'true'; | |
} else { | |
/* Store to MobX */ | |
this.props.store.notiEnabled = bool; | |
} | |
}); | |
} | |
/* ... */ | |
componentWillUnmount() { | |
/* Spinner 숨기기 */ | |
this.props.store.setLoginSpinnerVisible(false); | |
/* 메시지 창 숨기기 */ | |
this.props.store.setLoginAlertVisible(false); | |
/* Firebase Noti */ | |
this.onTokenRefreshListener(); | |
this.notificationListener(); | |
} | |
/* ... */ | |
render() { | |
{ /* ... */ } | |
} | |
} | |
export default Page; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Firebase Admin SDK implementation of Cloud Messaging in AWS Lambda | |
reference: https://firebase.google.com/docs/cloud-messaging/admin/send-messages?hl=ko | |
*/ | |
const admin = require('firebase-admin'); | |
const serviceAccount = require('./firebase/xxxx-firebase-adminsdk-xxxx.json'); | |
exports.handler = (event, context, callback) => { | |
const done = (err, res) => callback(null, { | |
statusCode: err ? '400' : '200', | |
body: err ? err.message : JSON.stringify(res), | |
headers: { | |
'Access-Control-Allow-Origin': '*', | |
'Content-Type': 'application/json', | |
}, | |
}); | |
/** | |
* @name request_parameters | |
* @param devices registrationToken | |
* @param projInfo notification and data | |
*/ | |
const postBody = (typeof event.body === 'string') ? JSON.parse(event.body) : event.body; | |
console.log('[sendNoti:postBody]', postBody); | |
if (!postBody) { | |
return done({message: 'warming'}, null); | |
} | |
if (!admin.apps.length) { | |
admin.initializeApp({ | |
credential: admin.credential.cert(serviceAccount), | |
}); | |
} | |
if (postBody.devices.length === 0) { | |
return done({message: 'nothing to send to device'}, null); | |
} | |
const registrationToken = postBody.devices; | |
const projInfo = postBody.projInfo; | |
const payload = { | |
notification: { | |
title: /* title */, | |
body: projInfo.msg, // PROJHUB_MGMT_PUSH_LOG.CONTEXT | |
sound: 'default', | |
}, | |
data: { | |
/* datas you want to send */ | |
} | |
}; | |
const options = { | |
priority: 'high', | |
timeToLive: 60 * 60 | |
}; | |
// Send a message to the device corresponding to the provided | |
// registration token. | |
admin.messaging().sendToDevice(registrationToken, payload, options).then((response) => { | |
// Response is a message ID string. | |
console.log('Successfully sent message:', response); | |
console.log('results:', response.results); | |
// Lambda같은 serverless function에선 MySQL의 인스턴스 닫듯이 firebase app객체도 즉각 없애야 됨 | |
admin.app('[DEFAULT]').delete(); | |
return done(null, {result: 1}); | |
}) | |
.catch((error) => { | |
console.log('Error sending message:', error); | |
// Lambda같은 serverless function에선 MySQL의 인스턴스 닫듯이 firebase app객체도 즉각 없애야 됨 | |
admin.app('[DEFAULT]').delete(); | |
return done(error, null); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment