UNPKG

4.78 kBJavaScriptView Raw
1import { CodedError } from '@unimodules/core';
2import Constants from 'expo-constants';
3import { Platform } from 'react-native';
4export function guardPermission() {
5 if (!('Notification' in window)) {
6 throw new Error('The Notification API is not available on this device.');
7 }
8 if (!navigator.serviceWorker) {
9 throw new Error('Notifications cannot be used because the service worker API is not supported on this device. This might also happen because your web page does not support HTTPS.');
10 }
11 if (Notification.permission !== 'granted') {
12 throw new Error('Cannot use Notifications without permissions. Please request permissions with `expo-permissions`');
13 }
14}
15export async function getExponentPushTokenAsync() {
16 if (!Constants.manifest.owner || !Constants.manifest.slug) {
17 throw new CodedError('E_NOTIFICATIONS_PUSH_WEB_MISSING_CONFIG', 'You must provide `owner` and `slug` in `app.json` to use push notifications on web. Learn more: https://docs.expo.io/versions/latest/guides/using-vapid/.');
18 }
19 const data = await _subscribeUserToPushAsync();
20 const experienceId = `@${Constants.manifest.owner}/${Constants.manifest.slug}`;
21 const tokenArguments = {
22 deviceId: Constants.installationId,
23 experienceId,
24 // Also uses `experienceId` for `appId` because there's no `appId` for web.
25 appId: experienceId,
26 deviceToken: JSON.stringify(data),
27 type: 'web',
28 };
29 const response = await fetch('https://exp.host/--/api/v2/push/getExpoPushToken', {
30 method: 'POST',
31 body: JSON.stringify(tokenArguments),
32 })
33 .then(response => {
34 if (!response.ok) {
35 throw new Error(response.statusText);
36 }
37 return response;
38 })
39 .then(response => response.json())
40 .catch(error => {
41 throw new CodedError('E_NOTIFICATIONS_TOKEN_REGISTRATION_FAILED', 'The device was unable to register for remote notifications with Expo. (' + error + ')');
42 });
43 return response.data.expoPushToken;
44}
45export async function getDevicePushTokenAsync() {
46 const data = await _subscribeUserToPushAsync();
47 return { type: Platform.OS, data };
48}
49async function _subscribeUserToPushAsync() {
50 if (!Constants.manifest.notification || !Constants.manifest.notification.vapidPublicKey) {
51 throw new CodedError('E_NOTIFICATIONS_PUSH_WEB_MISSING_CONFIG', 'You must provide `notification.vapidPublicKey` in `app.json` to use push notifications on web. Learn more: https://docs.expo.io/versions/latest/guides/using-vapid/.');
52 }
53 guardPermission();
54 const registration = await navigator.serviceWorker.register('/expo-service-worker.js');
55 await navigator.serviceWorker.ready;
56 if (!registration.active) {
57 throw new Error('Notifications might not be working because the service worker API is not active.');
58 }
59 const subscribeOptions = {
60 userVisibleOnly: true,
61 applicationServerKey: _urlBase64ToUint8Array(Constants.manifest.notification.vapidPublicKey),
62 };
63 const pushSubscription = await registration.pushManager
64 .subscribe(subscribeOptions)
65 .catch(error => {
66 throw new CodedError('E_NOTIFICATIONS_PUSH_WEB_TOKEN_REGISTRATION_FAILED', 'The device was unable to register for remote notifications with the browser endpoint. (' +
67 error +
68 ')');
69 });
70 const pushSubscriptionJson = pushSubscription.toJSON();
71 const subscriptionObject = {
72 endpoint: pushSubscriptionJson.endpoint,
73 keys: {
74 p256dh: pushSubscriptionJson.keys.p256dh,
75 auth: pushSubscriptionJson.keys.auth,
76 },
77 };
78 // Store notification icon string in service worker.
79 // This message is received by `/expo-service-worker.js`.
80 // We wrap it with `fromExpoWebClient` to make sure other message
81 // will not override content such as `notificationIcon`.
82 // https://stackoverflow.com/a/35729334/2603230
83 const notificationIcon = (Constants.manifest.notification || {}).icon;
84 await registration.active.postMessage(JSON.stringify({ fromExpoWebClient: { notificationIcon } }));
85 return subscriptionObject;
86}
87// https://github.com/web-push-libs/web-push#using-vapid-key-for-applicationserverkey
88function _urlBase64ToUint8Array(base64String) {
89 const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
90 const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
91 const rawData = window.atob(base64);
92 const outputArray = new Uint8Array(rawData.length);
93 for (let i = 0; i < rawData.length; ++i) {
94 outputArray[i] = rawData.charCodeAt(i);
95 }
96 return outputArray;
97}
98//# sourceMappingURL=ExponentNotificationsHelper.web.js.map
\No newline at end of file