import { Subscription } from '@unimodules/core'; import * as Notifications from 'expo-notifications'; import React from 'react'; import { Alert, Platform, ScrollView } from 'react-native'; import registerForPushNotificationsAsync from '../api/registerForPushNotificationsAsync'; import HeadingText from '../components/HeadingText'; import ListButton from '../components/ListButton'; import MonoText from '../components/MonoText'; export default class NotificationScreen extends React.Component< // See: https://github.com/expo/expo/pull/10229#discussion_r490961694 // eslint-disable-next-line @typescript-eslint/ban-types {}, { lastNotifications?: Notifications.Notification; } > { static navigationOptions = { title: 'Notifications', }; private _onReceivedListener: Subscription | undefined; private _onResponseReceivedListener: Subscription | undefined; // See: https://github.com/expo/expo/pull/10229#discussion_r490961694 // eslint-disable-next-line @typescript-eslint/ban-types constructor(props: {}) { super(props); this.state = {}; } componentDidMount() { if (Platform.OS !== 'web') { this._onReceivedListener = Notifications.addNotificationReceivedListener( this._handelReceivedNotification ); this._onResponseReceivedListener = Notifications.addNotificationResponseReceivedListener( this._handelNotificationResponseReceived ); // Using the same category as in `registerForPushNotificationsAsync` Notifications.setNotificationCategoryAsync('welcome', [ { buttonTitle: `Don't open app`, identifier: 'first-button', options: { opensAppToForeground: false, }, }, { buttonTitle: 'Respond with text', identifier: 'second-button-with-text', textInput: { submitButtonTitle: 'Submit button', placeholder: 'Placeholder text', }, }, { buttonTitle: 'Open app', identifier: 'third-button', options: { opensAppToForeground: true, }, }, ]) .then(category => console.log('Notification category set', category)) .catch(error => console.warn('Could not have set notification category', error)); } } componentWillUnmount() { this._onReceivedListener?.remove(); this._onResponseReceivedListener?.remove(); } render() { return ( Local Notifications Push Notifications Badge Number Dismissing notifications {this.state.lastNotifications && ( {JSON.stringify(this.state.lastNotifications, null, 2)} )} Notification Permissions Notification triggers debugging Notifications.getNextTriggerDateAsync({ seconds: 10 }).then(timestamp => alert(new Date(timestamp!)) ) } title="Get next date for time interval + 10 seconds" /> Notifications.getNextTriggerDateAsync({ hour: 9, minute: 0, repeats: true, }).then(timestamp => alert(new Date(timestamp!))) } title="Get next date for 9 AM" /> Notifications.getNextTriggerDateAsync({ hour: 9, minute: 0, weekday: 1, repeats: true, }).then(timestamp => alert(new Date(timestamp!))) } title="Get next date for Sunday, 9 AM" /> ); } _handelReceivedNotification = (notification: Notifications.Notification) => { this.setState({ lastNotifications: notification, }); }; _handelNotificationResponseReceived = ( notificationResponse: Notifications.NotificationResponse ) => { console.log({ notificationResponse }); // Calling alert(message) immediately fails to show the alert on Android // if after backgrounding the app and then clicking on a notification // to foreground the app setTimeout(() => Alert.alert('You clicked on the notification 🥇'), 1000); }; private getPermissionsAsync = async () => { const permission = await Notifications.getPermissionsAsync(); console.log('Get permission: ', permission); alert(`Status: ${permission.status}`); }; private requestPermissionsAsync = async () => { const permission = await Notifications.requestPermissionsAsync(); alert(`Status: ${permission.status}`); }; _obtainUserFacingNotifPermissionsAsync = async () => { let permission = await Notifications.getPermissionsAsync(); if (permission.status !== 'granted') { permission = await Notifications.requestPermissionsAsync(); if (permission.status !== 'granted') { Alert.alert(`We don't have permission to present notifications.`); } } return permission; }; // This is the same thing as user-facing notifications in expo-notifications _obtainRemoteNotifPermissionsAsync = async () => { let permission = await Notifications.getPermissionsAsync(); if (permission.status !== 'granted') { permission = await Notifications.requestPermissionsAsync(); if (permission.status !== 'granted') { Alert.alert(`We don't have permission to receive remote notifications.`); } } return permission; }; _presentLocalNotificationAsync = async () => { await this._obtainUserFacingNotifPermissionsAsync(); await Notifications.scheduleNotificationAsync({ content: { title: 'Here is a scheduled notification!', body: 'This is the body', data: { hello: 'there', future: 'self', }, sound: true, }, trigger: null, }); }; _LEGACY_presentLocalNotificationAsync = async () => { await this._obtainUserFacingNotifPermissionsAsync(); await Notifications.presentNotificationAsync({ title: 'Here is a local notification!', body: 'This is the body', data: { hello: 'there', }, sound: true, }); }; _scheduleLocalNotificationAsync = async () => { await this._obtainUserFacingNotifPermissionsAsync(); await Notifications.scheduleNotificationAsync({ content: { title: 'Here is a local notification!', body: 'This is the body', data: { hello: 'there', future: 'self', }, sound: true, }, trigger: { seconds: 10, }, }); }; _scheduleLocalNotificationAndCancelAsync = async () => { await this._obtainUserFacingNotifPermissionsAsync(); const notificationId = await Notifications.scheduleNotificationAsync({ content: { title: 'This notification should not appear', body: 'It should have been cancelled. :(', sound: true, }, trigger: { seconds: 10, }, }); await Notifications.cancelScheduledNotificationAsync(notificationId); }; _incrementIconBadgeNumberAsync = async () => { const currentNumber = await Notifications.getBadgeCountAsync(); await Notifications.setBadgeCountAsync(currentNumber + 1); const actualNumber = await Notifications.getBadgeCountAsync(); Alert.alert(`Set the badge number to ${actualNumber}`); }; _clearIconBadgeAsync = async () => { await Notifications.setBadgeCountAsync(0); Alert.alert(`Cleared the badge`); }; _sendNotificationAsync = async () => { const permission = await this._obtainRemoteNotifPermissionsAsync(); if (permission.status === 'granted') { registerForPushNotificationsAsync(); } }; _countPresentedNotifications = async () => { const presentedNotifications = await Notifications.getPresentedNotificationsAsync(); Alert.alert(`You currently have ${presentedNotifications.length} notifications presented`); }; _dismissAll = async () => { await Notifications.dismissAllNotificationsAsync(); Alert.alert(`Notifications dismissed`); }; _dismissSingle = async () => { const presentedNotifications = await Notifications.getPresentedNotificationsAsync(); if (!presentedNotifications.length) { Alert.alert(`No notifications to be dismissed`); return; } const identifier = presentedNotifications[0].request.identifier; await Notifications.dismissNotificationAsync(identifier); Alert.alert(`Notification dismissed`); }; }