Skip to content

Commit eb4ab03

Browse files
committed
Implement push notifications
Note this also stores the device token in the backend. This ports #1.
1 parent 9a6e021 commit eb4ab03

File tree

4 files changed

+1097
-22
lines changed

4 files changed

+1097
-22
lines changed

App.js

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
import React, { useState, useEffect, useRef } from 'react';
2+
import * as Notifications from "expo-notifications";
23
import { StatusBar } from 'expo-status-bar';
34
import { WebView } from 'react-native-webview';
5+
import registerForPushNotificationsAsync from './lib/pushNotifications';
46
import { StyleSheet, Text, View, BackHandler } from 'react-native';
57
import * as Updates from 'expo-updates';
68

9+
Notifications.setNotificationHandler({
10+
handleNotification: async () => ({
11+
shouldShowAlert: true,
12+
shouldPlaySound: false,
13+
shouldSetBadge: false,
14+
}),
15+
});
16+
717
const baseUrl = () => {
818
const { releaseChannel } = Updates;
919
console.log('releaseChannel =', releaseChannel);
@@ -15,6 +25,8 @@ const baseUrl = () => {
1525

1626
export default function App() {
1727
const [currentUrl, setCurrentUrl] = useState(baseUrl());
28+
const [expoPushToken, setExpoPushToken] = useState("");
29+
const responseListener = useRef();
1830

1931
const webViewRef = useRef(null);
2032

@@ -36,14 +48,50 @@ export default function App() {
3648
return () => backHandler.remove();
3749
}, []);
3850

51+
useEffect(() => {
52+
registerForPushNotificationsAsync().then((token) =>
53+
setExpoPushToken(token)
54+
);
55+
56+
responseListener.current =
57+
Notifications.addNotificationResponseReceivedListener((response) => {
58+
console.log('content =', response.notification.request.content);
59+
const { url } = response.notification.request.content.data;
60+
setCurrentUrl(`${baseUrl()}${url}`);
61+
});
62+
63+
return () => {
64+
Notifications.removeNotificationSubscription(responseListener.current);
65+
};
66+
}, []);
67+
68+
const handleLoggedInPage = (webview, token) => {
69+
webview?.injectJavaScript(
70+
`window.TimeOverflowRegisterExpoDeviceToken(\'${token}\');`
71+
);
72+
};
73+
74+
const injectCustomJavaScript = (url) => {
75+
if (/members/.test(url)) {
76+
handleLoggedInPage(webViewRef.current, expoPushToken);
77+
}
78+
};
79+
80+
const handleStateChange = (navState) => {
81+
console.log('state change =', navState);
82+
const { url } = navState;
83+
setCurrentUrl(url);
84+
injectCustomJavaScript(url);
85+
};
86+
3987
return (
4088
<>
4189
<WebView
4290
ref={(ref) => (webViewRef.current = ref)}
4391
style={styles.container}
4492
source={{ uri: currentUrl }}
4593
scalesPageToFit={false}
46-
// onNavigationStateChange={handleStateChange}
94+
onNavigationStateChange={handleStateChange}
4795
/>
4896
</>
4997
);

lib/pushNotifications.js

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,38 @@
1-
import { Permissions, Notifications } from 'expo';
1+
import * as Device from 'expo-device';
2+
import * as Notifications from 'expo-notifications';
23

3-
export async function registerForPushNotificationsAsync() {
4-
const { status: existingStatus } = await Permissions.getAsync(Permissions.NOTIFICATIONS);
4+
export default async function registerForPushNotificationsAsync() {
5+
let token;
56

6-
let finalStatus = existingStatus;
7+
if (Device.isDevice) {
8+
const { status: existingStatus } = await Notifications.getPermissionsAsync();
79

8-
// only ask if permissions have not already been determined, because
9-
// iOS won't necessarily prompt the user a second time.
10-
if (existingStatus !== 'granted') {
11-
// Android remote notification permissions are granted during the app
12-
// install, so this will only ask on iOS
13-
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
14-
finalStatus = status;
10+
let finalStatus = existingStatus;
11+
12+
if (existingStatus !== 'granted') {
13+
const { status } = await Notifications.requestPermissionsAsync();
14+
finalStatus = status;
15+
}
16+
17+
if (finalStatus !== 'granted') {
18+
alert('Failed to get push token for push notification!');
19+
return;
20+
}
21+
22+
token = (await Notifications.getExpoPushTokenAsync()).data;
23+
console.log('token =', token);
24+
} else {
25+
console.log('Must use physical device for Push Notifications');
1526
}
1627

17-
// Stop here if the user did not grant permissions
18-
if (finalStatus !== 'granted') return;
28+
if (Platform.OS === 'android') {
29+
Notifications.setNotificationChannelAsync('default', {
30+
name: 'default',
31+
importance: Notifications.AndroidImportance.MAX,
32+
vibrationPattern: [0, 250, 250, 250],
33+
lightColor: '#FF231F7C',
34+
});
35+
}
1936

20-
// Get the token that uniquely identifies this device
21-
return await Notifications.getExpoPushTokenAsync();
37+
return token;
2238
}

0 commit comments

Comments
 (0)