@talkjs/expo
Version:
Official TalkJS SDK for React Native (Expo)
256 lines (254 loc) • 9.61 kB
JavaScript
;
import Notifee, { EventType } from '@notifee/react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { AndroidImportance, AndroidVisibility } from './Notification';
import { TokenHandler } from './Notification';
import { ExpoNotificationsContext, FirebaseMessagingContext } from './Imports';
var AndroidStyle = /*#__PURE__*/function (AndroidStyle) {
AndroidStyle[AndroidStyle["BIGPICTURE"] = 0] = "BIGPICTURE";
AndroidStyle[AndroidStyle["BIGTEXT"] = 1] = "BIGTEXT";
AndroidStyle[AndroidStyle["INBOX"] = 2] = "INBOX";
AndroidStyle[AndroidStyle["MESSAGING"] = 3] = "MESSAGING";
return AndroidStyle;
}(AndroidStyle || {});
export class AndroidNotificationHandler extends TokenHandler {
#channelIdStorageKey = 'TalkJS_channel_id';
#activeNotifications = {};
#wasStopped = true;
constructor() {
super('fcm');
}
#onBackgroundMessage = async data => {
const channelId = await AsyncStorage.getItem(this.#channelIdStorageKey);
if (!channelId) {
return;
}
if (typeof data?.talkjs === 'string') {
let notification;
const androidSettings = {
channelId,
importance: AndroidImportance.HIGH,
sound: 'default',
showTimestamp: true,
pressAction: {
id: 'default'
}
};
const talkjsData = JSON.parse(data.talkjs);
if (talkjsData.sender.photoUrl) {
androidSettings['largeIcon'] = talkjsData.sender.photoUrl;
}
const notificationId = talkjsData.conversation.id;
const commonData = {
id: notificationId,
data: {
talkjs: data.talkjs
},
android: {
timestamp: talkjsData.timestamp,
...androidSettings
}
};
let sender = {
id: talkjsData.sender.id,
name: talkjsData.sender.name
};
if (talkjsData.sender.photoUrl) {
sender['icon'] = talkjsData.sender.photoUrl;
}
let activeNotifications = this.#activeNotifications[notificationId];
if (!activeNotifications) {
const attachment = talkjsData.message.attachment;
if (attachment) {
commonData.android.style = {
type: AndroidStyle.BIGPICTURE,
picture: attachment.url
};
} else {
const participants = talkjsData.conversation.participants;
commonData.android.style = {
type: AndroidStyle.MESSAGING,
person: {
name: 'me'
},
group: Object.keys(participants).length > 2,
messages: [{
person: sender,
text: talkjsData.message.text,
timestamp: talkjsData.timestamp
}]
};
}
notification = {
title: data.title,
body: data.message,
...commonData
};
this.#activeNotifications[notificationId] = [{
sender: talkjsData.sender,
message: talkjsData.message
}];
} else {
const messages = [];
for (let {
sender,
message
} of activeNotifications) {
let person = {
id: sender.id,
name: sender.name
};
if (sender.photoUrl) {
person['icon'] = sender.photoUrl;
}
messages.push({
person,
text: message.text,
timestamp: message.createdAt
});
}
messages.push({
person: sender,
text: talkjsData.message.text,
timestamp: talkjsData.timestamp
});
const participants = talkjsData.conversation.participants;
commonData.android.style = {
type: AndroidStyle.MESSAGING,
person: {
name: 'me'
},
group: Object.keys(participants).length > 2,
messages
};
notification = {
...commonData
};
activeNotifications.push({
sender: talkjsData.sender,
message: talkjsData.message
});
}
Notifee.displayNotification(notification);
}
};
removeActiveNotification = talkjsString => {
if (talkjsString) {
const talkjsData = JSON.parse(talkjsString);
delete this.#activeNotifications[talkjsData.conversation.id];
}
};
#setupExpoHandlers = async () => {
try {
const ExpoNotifications = ExpoNotificationsContext('./index.js');
if (ExpoNotifications) {
if (!this.pushTokenListenerSubscription) {
this.pushTokenListenerSubscription = ExpoNotifications.addPushTokenListener(token => this.setPushRegistrationId(token.data));
}
const token = await ExpoNotifications.getDevicePushTokenAsync();
this.setPushRegistrationId(token.data);
// Setup background task to handle background notifications
const expoTaskManagerContext = require.context('../../../../expo-task-manager/build', false, /\.js$/);
const ExpoTaskManager = expoTaskManagerContext('./TaskManager.js');
if (ExpoTaskManager) {
const BACKGROUND_TASK = 'BACKGROUND-NOTIFICATION-TASK';
ExpoTaskManager.defineTask(BACKGROUND_TASK, ({
data
}) => this.#onBackgroundMessage(data.notification?.data));
ExpoNotifications.registerTaskAsync(BACKGROUND_TASK);
} else {
console.error('Module: expo-task-manager could not be imported. Background notification Listener could not be setup');
}
} else {
console.error('Module: expo-notifications could not be imported');
}
} catch (e) {
console.error('Could not setup Expo Notifications. Ensure expo-notifications and expo-task-manager are properly installed', e);
}
};
#setupFirebaseHandlers = async () => {
const errorMessage = 'Could not setup Firebase Messaging. Ensure @react-native-firebase/messaging is properly installed: ';
try {
const FirebaseMessaging = FirebaseMessagingContext('./index.js');
if (FirebaseMessaging) {
const messaging = FirebaseMessaging.getMessaging();
FirebaseMessaging.onTokenRefresh(messaging, token => this.setPushRegistrationId(token));
FirebaseMessaging.setBackgroundMessageHandler(messaging, message => this.#onBackgroundMessage(message.data));
this.setPushRegistrationId(await FirebaseMessaging.getToken(messaging));
} else {
console.error(errorMessage);
}
} catch (e) {
console.error(errorMessage, e);
}
};
async setup(androidSettings, _) {
Notifee.onBackgroundEvent(async event => {
const talkjsString = event.detail.notification?.data?.talkjs;
if (event.type === EventType.PRESS) {
this.removeActiveNotification(talkjsString);
this.notificationPressed(event, false);
} else if (event.type === EventType.DISMISSED) {
this.removeActiveNotification(talkjsString);
}
});
Notifee.onForegroundEvent(async event => {
const talkjsString = event.detail.notification?.data?.talkjs;
if (event.type === EventType.PRESS) {
this.removeActiveNotification(talkjsString);
this.notificationPressed(event, true);
} else if (event.type === EventType.DISMISSED) {
this.removeActiveNotification(talkjsString);
}
});
if (FirebaseMessagingContext.keys().length === 1) {
await this.#setupFirebaseHandlers();
} else if (ExpoNotificationsContext.keys().length === 1) {
await this.#setupExpoHandlers();
} else {
console.error('Neither expo-notifications nor @react-native-firebase/messaging are installed. Push notifications will not work.');
}
const channelId = await AsyncStorage.getItem(this.#channelIdStorageKey);
if (androidSettings && androidSettings.channelId !== channelId) {
await Notifee.createChannel({
id: androidSettings.channelId,
name: androidSettings.channelName,
badge: androidSettings.badge ?? true,
description: androidSettings.channelDescription ?? '',
lights: androidSettings.lights ?? true,
lightColor: androidSettings.lightColor ?? 'white',
bypassDnd: androidSettings.bypassDnd ?? false,
sound: androidSettings.playSound ?? 'default',
importance: androidSettings.importance ?? AndroidImportance.HIGH,
visibility: androidSettings.visibility ?? AndroidVisibility.PRIVATE,
vibration: androidSettings.vibrate ?? true,
vibrationPattern: androidSettings.vibrationPattern
});
await AsyncStorage.setItem(this.#channelIdStorageKey, androidSettings.channelId);
}
if (this.#wasStopped) {
const notifications = await Notifee.getDisplayedNotifications();
for (let displayedNotification of notifications) {
const notification = displayedNotification.notification;
if (JSON.stringify(notification.data) !== '{}') {
let activeNotifications = this.#activeNotifications[notification.id];
if (!activeNotifications) {
activeNotifications = [];
this.#activeNotifications[notification.id] = activeNotifications;
}
const data = notification.data;
if (data.talkjs) {
const talkjs = JSON.parse(data.talkjs);
activeNotifications.push({
sender: talkjs.sender,
message: talkjs.message
});
}
}
}
this.#wasStopped = false;
}
return this;
}
}
//# sourceMappingURL=AndroidNotification.js.map