99 lines
4.7 KiB
JavaScript
99 lines
4.7 KiB
JavaScript
import { CodedError } from '@unimodules/core';
|
|
import Constants from 'expo-constants';
|
|
import { Platform } from 'react-native';
|
|
import getInstallationIdAsync from '../environment/getInstallationIdAsync';
|
|
export function guardPermission() {
|
|
if (!('Notification' in window)) {
|
|
throw new Error('The Notification API is not available on this device.');
|
|
}
|
|
if (!navigator.serviceWorker) {
|
|
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.');
|
|
}
|
|
if (Notification.permission !== 'granted') {
|
|
throw new Error('Cannot use Notifications without permissions. Please request permissions with `expo-permissions`');
|
|
}
|
|
}
|
|
export async function getExponentPushTokenAsync() {
|
|
if (!Constants.manifest.owner || !Constants.manifest.slug) {
|
|
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/.');
|
|
}
|
|
const data = await _subscribeUserToPushAsync();
|
|
const experienceId = `@${Constants.manifest.owner}/${Constants.manifest.slug}`;
|
|
const tokenArguments = {
|
|
deviceId: await getInstallationIdAsync(),
|
|
experienceId,
|
|
// Also uses `experienceId` for `appId` because there's no `appId` for web.
|
|
appId: experienceId,
|
|
deviceToken: JSON.stringify(data),
|
|
type: 'web',
|
|
};
|
|
const response = await fetch('https://exp.host/--/api/v2/push/getExpoPushToken', {
|
|
method: 'POST',
|
|
body: JSON.stringify(tokenArguments),
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error(response.statusText);
|
|
}
|
|
return response;
|
|
})
|
|
.then(response => response.json())
|
|
.catch(error => {
|
|
throw new CodedError('E_NOTIFICATIONS_TOKEN_REGISTRATION_FAILED', 'The device was unable to register for remote notifications with Expo. (' + error + ')');
|
|
});
|
|
return response.data.expoPushToken;
|
|
}
|
|
export async function getDevicePushTokenAsync() {
|
|
const data = await _subscribeUserToPushAsync();
|
|
return { type: Platform.OS, data };
|
|
}
|
|
async function _subscribeUserToPushAsync() {
|
|
if (!Constants.manifest.notification || !Constants.manifest.notification.vapidPublicKey) {
|
|
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/.');
|
|
}
|
|
guardPermission();
|
|
const registration = await navigator.serviceWorker.register('/expo-service-worker.js');
|
|
await navigator.serviceWorker.ready;
|
|
if (!registration.active) {
|
|
throw new Error('Notifications might not be working because the service worker API is not active.');
|
|
}
|
|
const subscribeOptions = {
|
|
userVisibleOnly: true,
|
|
applicationServerKey: _urlBase64ToUint8Array(Constants.manifest.notification.vapidPublicKey),
|
|
};
|
|
const pushSubscription = await registration.pushManager
|
|
.subscribe(subscribeOptions)
|
|
.catch(error => {
|
|
throw new CodedError('E_NOTIFICATIONS_PUSH_WEB_TOKEN_REGISTRATION_FAILED', 'The device was unable to register for remote notifications with the browser endpoint. (' +
|
|
error +
|
|
')');
|
|
});
|
|
const pushSubscriptionJson = pushSubscription.toJSON();
|
|
const subscriptionObject = {
|
|
endpoint: pushSubscriptionJson.endpoint,
|
|
keys: {
|
|
p256dh: pushSubscriptionJson.keys.p256dh,
|
|
auth: pushSubscriptionJson.keys.auth,
|
|
},
|
|
};
|
|
// Store notification icon string in service worker.
|
|
// This message is received by `/expo-service-worker.js`.
|
|
// We wrap it with `fromExpoWebClient` to make sure other message
|
|
// will not override content such as `notificationIcon`.
|
|
// https://stackoverflow.com/a/35729334/2603230
|
|
const notificationIcon = (Constants.manifest.notification || {}).icon;
|
|
await registration.active.postMessage(JSON.stringify({ fromExpoWebClient: { notificationIcon } }));
|
|
return subscriptionObject;
|
|
}
|
|
// https://github.com/web-push-libs/web-push#using-vapid-key-for-applicationserverkey
|
|
function _urlBase64ToUint8Array(base64String) {
|
|
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
|
|
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
|
|
const rawData = window.atob(base64);
|
|
const outputArray = new Uint8Array(rawData.length);
|
|
for (let i = 0; i < rawData.length; ++i) {
|
|
outputArray[i] = rawData.charCodeAt(i);
|
|
}
|
|
return outputArray;
|
|
}
|
|
//# sourceMappingURL=ExponentNotificationsHelper.web.js.map
|