@stream-io/video-react-native-sdk 1.2.14 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/commonjs/hooks/push/useIosCallKeepEventsSetupEffect.js +43 -6
  3. package/dist/commonjs/hooks/push/useIosCallKeepEventsSetupEffect.js.map +1 -1
  4. package/dist/commonjs/hooks/push/useIosCallkeepWithCallingStateEffect.js +1 -1
  5. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +2 -2
  6. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js +2 -7
  7. package/dist/commonjs/hooks/push/useProcessPushCallEffect.js.map +1 -1
  8. package/dist/commonjs/hooks/push/useProcessPushNonRingingCallEffect.js +3 -3
  9. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js +1 -0
  10. package/dist/commonjs/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  11. package/dist/commonjs/providers/StreamCall.js +1 -1
  12. package/dist/commonjs/utils/StreamVideoRN/index.js +5 -6
  13. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  14. package/dist/commonjs/utils/index.js +12 -0
  15. package/dist/commonjs/utils/index.js.map +1 -1
  16. package/dist/commonjs/utils/push/android.js +23 -79
  17. package/dist/commonjs/utils/push/android.js.map +1 -1
  18. package/dist/commonjs/utils/push/index.js +39 -0
  19. package/dist/commonjs/utils/push/index.js.map +1 -0
  20. package/dist/commonjs/utils/push/internal/rxSubjects.js.map +1 -0
  21. package/dist/commonjs/utils/push/internal/utils.js +157 -0
  22. package/dist/commonjs/utils/push/internal/utils.js.map +1 -0
  23. package/dist/commonjs/utils/push/ios.js +43 -84
  24. package/dist/commonjs/utils/push/ios.js.map +1 -1
  25. package/dist/commonjs/utils/push/libs/expoNotifications.js.map +1 -1
  26. package/dist/commonjs/utils/push/libs/index.js +0 -11
  27. package/dist/commonjs/utils/push/libs/index.js.map +1 -1
  28. package/dist/commonjs/utils/push/libs/iosPushNotification.js.map +1 -1
  29. package/dist/commonjs/utils/push/utils.js +29 -150
  30. package/dist/commonjs/utils/push/utils.js.map +1 -1
  31. package/dist/commonjs/version.js +1 -1
  32. package/dist/commonjs/version.js.map +1 -1
  33. package/dist/module/hooks/push/useIosCallKeepEventsSetupEffect.js +41 -4
  34. package/dist/module/hooks/push/useIosCallKeepEventsSetupEffect.js.map +1 -1
  35. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js +1 -1
  36. package/dist/module/hooks/push/useIosCallkeepWithCallingStateEffect.js.map +1 -1
  37. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js +2 -2
  38. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  39. package/dist/module/hooks/push/useProcessPushCallEffect.js +2 -7
  40. package/dist/module/hooks/push/useProcessPushCallEffect.js.map +1 -1
  41. package/dist/module/hooks/push/useProcessPushNonRingingCallEffect.js +3 -3
  42. package/dist/module/hooks/push/useProcessPushNonRingingCallEffect.js.map +1 -1
  43. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js +1 -0
  44. package/dist/module/hooks/useAndroidKeepCallAliveEffect.js.map +1 -1
  45. package/dist/module/providers/StreamCall.js +1 -1
  46. package/dist/module/providers/StreamCall.js.map +1 -1
  47. package/dist/module/utils/StreamVideoRN/index.js +5 -6
  48. package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
  49. package/dist/module/utils/index.js +1 -0
  50. package/dist/module/utils/index.js.map +1 -1
  51. package/dist/module/utils/push/android.js +20 -79
  52. package/dist/module/utils/push/android.js.map +1 -1
  53. package/dist/module/utils/push/index.js +4 -0
  54. package/dist/module/utils/push/index.js.map +1 -0
  55. package/dist/module/utils/push/internal/rxSubjects.js.map +1 -0
  56. package/dist/module/utils/push/internal/utils.js +146 -0
  57. package/dist/module/utils/push/internal/utils.js.map +1 -0
  58. package/dist/module/utils/push/ios.js +40 -81
  59. package/dist/module/utils/push/ios.js.map +1 -1
  60. package/dist/module/utils/push/libs/expoNotifications.js.map +1 -1
  61. package/dist/module/utils/push/libs/index.js +0 -1
  62. package/dist/module/utils/push/libs/index.js.map +1 -1
  63. package/dist/module/utils/push/libs/iosPushNotification.js.map +1 -1
  64. package/dist/module/utils/push/utils.js +25 -144
  65. package/dist/module/utils/push/utils.js.map +1 -1
  66. package/dist/module/version.js +1 -1
  67. package/dist/module/version.js.map +1 -1
  68. package/dist/typescript/hooks/push/useIosCallKeepEventsSetupEffect.d.ts.map +1 -1
  69. package/dist/typescript/hooks/useAndroidKeepCallAliveEffect.d.ts.map +1 -1
  70. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  71. package/dist/typescript/utils/StreamVideoRN/types.d.ts +6 -4
  72. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  73. package/dist/typescript/utils/index.d.ts +1 -0
  74. package/dist/typescript/utils/index.d.ts.map +1 -1
  75. package/dist/typescript/utils/push/android.d.ts +12 -2
  76. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  77. package/dist/typescript/utils/push/index.d.ts +4 -0
  78. package/dist/typescript/utils/push/index.d.ts.map +1 -0
  79. package/dist/typescript/utils/push/{rxSubjects.d.ts → internal/rxSubjects.d.ts} +1 -1
  80. package/dist/typescript/utils/push/internal/rxSubjects.d.ts.map +1 -0
  81. package/dist/typescript/utils/push/internal/utils.d.ts +43 -0
  82. package/dist/typescript/utils/push/internal/utils.d.ts.map +1 -0
  83. package/dist/typescript/utils/push/ios.d.ts +8 -3
  84. package/dist/typescript/utils/push/ios.d.ts.map +1 -1
  85. package/dist/typescript/utils/push/libs/expoNotifications.d.ts +2 -0
  86. package/dist/typescript/utils/push/libs/expoNotifications.d.ts.map +1 -1
  87. package/dist/typescript/utils/push/libs/index.d.ts +0 -1
  88. package/dist/typescript/utils/push/libs/index.d.ts.map +1 -1
  89. package/dist/typescript/utils/push/libs/iosPushNotification.d.ts +2 -0
  90. package/dist/typescript/utils/push/libs/iosPushNotification.d.ts.map +1 -1
  91. package/dist/typescript/utils/push/utils.d.ts +14 -42
  92. package/dist/typescript/utils/push/utils.d.ts.map +1 -1
  93. package/dist/typescript/version.d.ts +1 -1
  94. package/dist/typescript/version.d.ts.map +1 -1
  95. package/package.json +6 -11
  96. package/src/hooks/push/useIosCallKeepEventsSetupEffect.ts +62 -6
  97. package/src/hooks/push/useIosCallkeepWithCallingStateEffect.ts +1 -1
  98. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +2 -2
  99. package/src/hooks/push/useProcessPushCallEffect.ts +2 -7
  100. package/src/hooks/push/useProcessPushNonRingingCallEffect.ts +3 -3
  101. package/src/hooks/useAndroidKeepCallAliveEffect.ts +1 -0
  102. package/src/providers/StreamCall.tsx +1 -1
  103. package/src/utils/StreamVideoRN/index.ts +11 -6
  104. package/src/utils/StreamVideoRN/types.ts +6 -4
  105. package/src/utils/index.ts +1 -0
  106. package/src/utils/push/android.ts +28 -99
  107. package/src/utils/push/index.ts +3 -0
  108. package/src/utils/push/{rxSubjects.ts → internal/rxSubjects.ts} +1 -1
  109. package/src/utils/push/internal/utils.ts +178 -0
  110. package/src/utils/push/ios.ts +49 -115
  111. package/src/utils/push/libs/expoNotifications.ts +4 -0
  112. package/src/utils/push/libs/index.ts +0 -1
  113. package/src/utils/push/libs/iosPushNotification.ts +4 -0
  114. package/src/utils/push/utils.ts +44 -175
  115. package/src/version.ts +1 -1
  116. package/dist/commonjs/utils/push/libs/expoTaskManager.js +0 -17
  117. package/dist/commonjs/utils/push/libs/expoTaskManager.js.map +0 -1
  118. package/dist/commonjs/utils/push/rxSubjects.js.map +0 -1
  119. package/dist/module/utils/push/libs/expoTaskManager.js +0 -11
  120. package/dist/module/utils/push/libs/expoTaskManager.js.map +0 -1
  121. package/dist/module/utils/push/rxSubjects.js.map +0 -1
  122. package/dist/typescript/utils/push/libs/expoTaskManager.d.ts +0 -3
  123. package/dist/typescript/utils/push/libs/expoTaskManager.d.ts.map +0 -1
  124. package/dist/typescript/utils/push/rxSubjects.d.ts.map +0 -1
  125. package/src/utils/push/libs/expoTaskManager.ts +0 -16
  126. /package/dist/commonjs/utils/push/{rxSubjects.js → internal/rxSubjects.js} +0 -0
  127. /package/dist/module/utils/push/{rxSubjects.js → internal/rxSubjects.js} +0 -0
@@ -1,4 +1,3 @@
1
- import { FirebaseMessagingTypes } from '@react-native-firebase/messaging';
2
1
  import {
3
2
  Call,
4
3
  RxUtils,
@@ -12,11 +11,10 @@ import type {
12
11
  } from '../StreamVideoRN/types';
13
12
  import {
14
13
  getFirebaseMessagingLib,
15
- getFirebaseMessagingLibNoThrow,
16
14
  getExpoNotificationsLib,
17
- getExpoTaskManagerLib,
18
15
  getNotifeeLibThrowIfNotInstalledForPush,
19
16
  NotifeeLib,
17
+ FirebaseMessagingTypes,
20
18
  } from './libs';
21
19
  import {
22
20
  pushAcceptedIncomingCallCId$,
@@ -25,15 +23,16 @@ import {
25
23
  pushNonRingingCallData$,
26
24
  pushUnsubscriptionCallbacks$,
27
25
  pushAndroidBackgroundDeliveredIncomingCallCId$,
28
- } from './rxSubjects';
26
+ } from './internal/rxSubjects';
29
27
  import {
30
28
  canAddPushWSSubscriptionsRef,
31
29
  clearPushWSEventSubscriptions,
32
30
  processCallFromPushInBackground,
33
31
  shouldCallBeEnded,
34
- } from './utils';
32
+ } from './internal/utils';
35
33
  import { setPushLogoutCallback } from '../internal/pushLogoutCallback';
36
34
  import { getAndroidDefaultRingtoneUrl } from '../getAndroidDefaultRingtoneUrl';
35
+ import { StreamVideoRN } from '../StreamVideoRN';
37
36
 
38
37
  const ACCEPT_CALL_ACTION_ID = 'accept';
39
38
  const DECLINE_CALL_ACTION_ID = 'decline';
@@ -48,89 +47,6 @@ type Event = Parameters<onBackgroundEventFunctionParams>[0];
48
47
 
49
48
  let lastFirebaseToken = { token: '', userId: '' };
50
49
 
51
- // EventType = NotifeeLib['EventType'];
52
-
53
- /** Setup Firebase push message handler **/
54
- export function setupFirebaseHandlerAndroid(pushConfig: PushConfig) {
55
- if (Platform.OS !== 'android') {
56
- return;
57
- }
58
- if (pushConfig.isExpo) {
59
- const messaging = getFirebaseMessagingLibNoThrow(true);
60
- if (messaging) {
61
- // handles on app killed state in expo, expo-notifications cannot handle that
62
- messaging().setBackgroundMessageHandler(
63
- async (msg) =>
64
- await firebaseMessagingOnMessageHandler(msg.data, pushConfig)
65
- );
66
- messaging().onMessage((msg) =>
67
- firebaseMessagingOnMessageHandler(msg.data, pushConfig)
68
- ); // this is to listen to foreground messages, which we dont need for now
69
- } else {
70
- const Notifications = getExpoNotificationsLib();
71
- const TaskManager = getExpoTaskManagerLib();
72
- const BACKGROUND_NOTIFICATION_TASK =
73
- 'STREAM-VIDEO-SDK-INTERNAL-BACKGROUND-NOTIFICATION-TASK';
74
-
75
- TaskManager.defineTask(
76
- BACKGROUND_NOTIFICATION_TASK,
77
- ({ data, error }) => {
78
- if (error) {
79
- return;
80
- }
81
- // @ts-ignore
82
- const dataToProcess = data.notification?.data;
83
- firebaseMessagingOnMessageHandler(dataToProcess, pushConfig);
84
- }
85
- );
86
- // background handler (does not handle on app killed state)
87
- Notifications.registerTaskAsync(BACKGROUND_NOTIFICATION_TASK);
88
- // foreground handler
89
- Notifications.setNotificationHandler({
90
- handleNotification: async (notification) => {
91
- // @ts-ignore
92
- const trigger = notification?.request?.trigger;
93
- if (trigger.type === 'push') {
94
- const data = trigger?.remoteMessage?.data;
95
- if (data?.sender === 'stream.video') {
96
- await firebaseMessagingOnMessageHandler(data, pushConfig);
97
- return {
98
- shouldShowAlert: false,
99
- shouldPlaySound: false,
100
- shouldSetBadge: false,
101
- };
102
- }
103
- }
104
- return {
105
- shouldShowAlert: true,
106
- shouldPlaySound: false,
107
- shouldSetBadge: false,
108
- };
109
- },
110
- });
111
- }
112
- } else {
113
- const messaging = getFirebaseMessagingLib();
114
- messaging().setBackgroundMessageHandler(
115
- async (msg) =>
116
- await firebaseMessagingOnMessageHandler(msg.data, pushConfig)
117
- );
118
- messaging().onMessage((msg) =>
119
- firebaseMessagingOnMessageHandler(msg.data, pushConfig)
120
- ); // this is to listen to foreground messages, which we dont need for now
121
- }
122
-
123
- // the notification tap handlers are always registered with notifee for both expo and non-expo in android
124
- const notifeeLib = getNotifeeLibThrowIfNotInstalledForPush();
125
- const notifee = notifeeLib.default;
126
- notifee.onBackgroundEvent(async (event) => {
127
- await onNotifeeEvent(event, pushConfig, true);
128
- });
129
- notifee.onForegroundEvent((event) => {
130
- onNotifeeEvent(event, pushConfig, false);
131
- });
132
- }
133
-
134
50
  /** Send token to stream, create notification channel, */
135
51
  export async function initAndroidPushToken(
136
52
  client: StreamVideoClient,
@@ -184,10 +100,14 @@ export async function initAndroidPushToken(
184
100
  }
185
101
  }
186
102
 
187
- const firebaseMessagingOnMessageHandler = async (
188
- data: FirebaseMessagingTypes.RemoteMessage['data'],
189
- pushConfig: PushConfig
103
+ /**
104
+ * Creates notification from the push message data.
105
+ * For Ringing and Non-Ringing calls.
106
+ */
107
+ export const firebaseDataHandler = async (
108
+ data: FirebaseMessagingTypes.RemoteMessage['data']
190
109
  ) => {
110
+ if (Platform.OS !== 'android') return;
191
111
  /* Example data from firebase
192
112
  "message": {
193
113
  "data": {
@@ -203,7 +123,8 @@ const firebaseMessagingOnMessageHandler = async (
203
123
  // other stuff
204
124
  }
205
125
  */
206
- if (!data || data.sender !== 'stream.video') {
126
+ const pushConfig = StreamVideoRN.getConfig().push;
127
+ if (!pushConfig || !data || data.sender !== 'stream.video') {
207
128
  return;
208
129
  }
209
130
 
@@ -377,16 +298,25 @@ const firebaseMessagingOnMessageHandler = async (
377
298
  }
378
299
  };
379
300
 
380
- const onNotifeeEvent = async (
381
- event: Event,
382
- pushConfig: PushConfig,
383
- isBackground: boolean
384
- ) => {
301
+ export const onAndroidNotifeeEvent = async ({
302
+ event,
303
+ isBackground,
304
+ }: {
305
+ event: Event;
306
+ isBackground: boolean;
307
+ }) => {
308
+ if (Platform.OS !== 'android') return;
385
309
  const { type, detail } = event;
386
310
  const { notification, pressAction } = detail;
387
311
  const notificationId = notification?.id;
388
312
  const data = notification?.data;
389
- if (!data || !notificationId || data.sender !== 'stream.video') {
313
+ const pushConfig = StreamVideoRN.getConfig().push;
314
+ if (
315
+ !pushConfig ||
316
+ !data ||
317
+ !notificationId ||
318
+ data.sender !== 'stream.video'
319
+ ) {
390
320
  return;
391
321
  }
392
322
 
@@ -443,7 +373,6 @@ const onNotifeeEvent = async (
443
373
  } else {
444
374
  const notifeeLib = getNotifeeLibThrowIfNotInstalledForPush();
445
375
  if (type === notifeeLib.EventType.PRESS) {
446
- pushTappedIncomingCallCId$.next(call_cid);
447
376
  pushConfig.onTapNonRingingCallNotification?.(
448
377
  call_cid,
449
378
  data.type as NonRingingPushEvent
@@ -0,0 +1,3 @@
1
+ export * from './android';
2
+ export * from './ios';
3
+ export * from './utils';
@@ -1,5 +1,5 @@
1
1
  import { BehaviorSubject } from 'rxjs';
2
- import { NonRingingPushEvent } from '../StreamVideoRN/types';
2
+ import { NonRingingPushEvent } from '../../StreamVideoRN/types';
3
3
 
4
4
  /**
5
5
  * This rxjs subject is used to store the call cid of the accepted incoming call from push notification
@@ -0,0 +1,178 @@
1
+ import {
2
+ Call,
3
+ RxUtils,
4
+ StreamVideoClient,
5
+ getLogger,
6
+ } from '@stream-io/video-client';
7
+ import type {
8
+ NonRingingPushEvent,
9
+ StreamVideoConfig,
10
+ } from '../../StreamVideoRN/types';
11
+ import { onNewCallNotification } from '../../internal/newNotificationCallbacks';
12
+ import { pushUnsubscriptionCallbacks$ } from './rxSubjects';
13
+
14
+ type PushConfig = NonNullable<StreamVideoConfig['push']>;
15
+
16
+ type CanAddPushWSSubscriptionsRef = { current: boolean };
17
+
18
+ /**
19
+ * This function is used to check if the call should be ended based on the push notification
20
+ * Useful for callkeep management to end the call if necessary (with reportEndCallWithUUID)
21
+ */
22
+ export const shouldCallBeEnded = (
23
+ callFromPush: Call,
24
+ created_by_id: string | undefined,
25
+ receiver_id: string | undefined
26
+ ) => {
27
+ /* callkeep reasons for ending a call
28
+ FAILED: 1,
29
+ REMOTE_ENDED: 2,
30
+ UNANSWERED: 3,
31
+ ANSWERED_ELSEWHERE: 4,
32
+ DECLINED_ELSEWHERE: 5,
33
+ MISSED: 6
34
+ */
35
+ const callSession = callFromPush.state.session;
36
+ const rejected_by = callSession?.rejected_by;
37
+ const accepted_by = callSession?.accepted_by;
38
+ let mustEndCall = false;
39
+ let callkeepReason = 0;
40
+ if (created_by_id && rejected_by) {
41
+ if (rejected_by[created_by_id]) {
42
+ // call was cancelled by the caller
43
+ mustEndCall = true;
44
+ callkeepReason = 2;
45
+ }
46
+ } else if (receiver_id && rejected_by) {
47
+ if (rejected_by[receiver_id]) {
48
+ // call was rejected by the receiver in some other device
49
+ mustEndCall = true;
50
+ callkeepReason = 5;
51
+ }
52
+ } else if (receiver_id && accepted_by) {
53
+ if (accepted_by[receiver_id]) {
54
+ // call was accepted by the receiver in some other device
55
+ mustEndCall = true;
56
+ callkeepReason = 4;
57
+ }
58
+ }
59
+ return { mustEndCall, callkeepReason };
60
+ };
61
+
62
+ /* An action for the notification or callkeep and app does not have JS context setup yet, so we need to do two steps:
63
+ 1. we need to create a new client and connect the user to decline the call
64
+ 2. this is because the app is in background state and we don't have a client to get the call and do an action
65
+ */
66
+ export const processCallFromPushInBackground = async (
67
+ pushConfig: PushConfig,
68
+ call_cid: string,
69
+ action: Parameters<typeof processCallFromPush>[2]
70
+ ) => {
71
+ let videoClient: StreamVideoClient | undefined;
72
+
73
+ try {
74
+ videoClient = await pushConfig.createStreamVideoClient();
75
+ if (!videoClient) {
76
+ return;
77
+ }
78
+ } catch (e) {
79
+ const logger = getLogger(['processCallFromPushInBackground']);
80
+ logger('error', 'failed to create video client', e);
81
+ return;
82
+ }
83
+ await processCallFromPush(videoClient, call_cid, action, pushConfig);
84
+ };
85
+
86
+ /**
87
+ * This function is used process the call from push notifications due to incoming call
88
+ * It does the following steps:
89
+ * 1. Get the call from the client if present or create a new call
90
+ * 2. Fetch the latest state of the call from the server if its not already in ringing state
91
+ * 3. Join or leave the call based on the user's action.
92
+ */
93
+ export const processCallFromPush = async (
94
+ client: StreamVideoClient,
95
+ call_cid: string,
96
+ action: 'accept' | 'decline' | 'pressed' | 'backgroundDelivered',
97
+ pushConfig: PushConfig
98
+ ) => {
99
+ let callFromPush: Call;
100
+ try {
101
+ callFromPush = await client.onRingingCall(call_cid);
102
+ } catch (e) {
103
+ const logger = getLogger(['processCallFromPush']);
104
+ logger('error', 'failed to fetch call from push notification', e);
105
+ return;
106
+ }
107
+ // note: when action was pressed or delivered, we dont need to do anything as the only thing is to do is to get the call which adds it to the client
108
+ try {
109
+ if (action === 'accept') {
110
+ if (pushConfig.publishOptions) {
111
+ callFromPush.updatePublishOptions(pushConfig.publishOptions);
112
+ }
113
+ await callFromPush.join();
114
+ } else if (action === 'decline') {
115
+ await callFromPush.leave({ reject: true });
116
+ }
117
+ } catch (e) {
118
+ const logger = getLogger(['processCallFromPush']);
119
+ logger(
120
+ 'error',
121
+ `failed to process ${action} call from push notification`,
122
+ e
123
+ );
124
+ }
125
+ };
126
+
127
+ /**
128
+ * This function is used process the call from push notifications due to non ringing calls
129
+ * It does the following steps:
130
+ * 1. Get the call from the client if present or create a new call
131
+ * 2. Fetch the latest state of the call from the server
132
+ * 3. Call all the callbacks to inform the app about the call
133
+ */
134
+ export const processNonIncomingCallFromPush = async (
135
+ client: StreamVideoClient,
136
+ call_cid: string,
137
+ nonRingingNotificationType: NonRingingPushEvent
138
+ ) => {
139
+ let callFromPush: Call;
140
+ try {
141
+ const _callFromPush = client.state.calls.find((c) => c.cid === call_cid);
142
+ if (_callFromPush) {
143
+ callFromPush = _callFromPush;
144
+ } else {
145
+ // if not it means that WS is not alive when receiving the push notifications and we need to fetch the call
146
+ const [callType, callId] = call_cid.split(':');
147
+ callFromPush = client.call(callType as string, callId as string);
148
+ await callFromPush.get();
149
+ }
150
+ } catch (e) {
151
+ const logger = getLogger(['processNonIncomingCallFromPush']);
152
+ logger('error', 'failed to fetch call from push notification', e);
153
+ return;
154
+ }
155
+ onNewCallNotification(callFromPush, nonRingingNotificationType);
156
+ };
157
+
158
+ /**
159
+ * This function is used to clear all the push related WS subscriptions
160
+ * note: events are subscribed in push for accept/decline through WS
161
+ */
162
+ export const clearPushWSEventSubscriptions = () => {
163
+ const unsubscriptionCallbacks = RxUtils.getCurrentValue(
164
+ pushUnsubscriptionCallbacks$
165
+ );
166
+ if (unsubscriptionCallbacks) {
167
+ unsubscriptionCallbacks.forEach((cb) => cb());
168
+ }
169
+ pushUnsubscriptionCallbacks$.next(undefined);
170
+ };
171
+
172
+ /**
173
+ * This ref is used to check if the push WS subscriptions can be added
174
+ * It is used to avoid adding the push WS subscriptions when the client is connected to WS in the foreground
175
+ */
176
+ export const canAddPushWSSubscriptionsRef: CanAddPushWSSubscriptionsRef = {
177
+ current: true,
178
+ };
@@ -1,41 +1,24 @@
1
1
  import { Platform } from 'react-native';
2
- import type {
3
- NonRingingPushEvent,
4
- StreamVideoConfig,
5
- } from '../StreamVideoRN/types';
6
- import {
7
- pushAcceptedIncomingCallCId$,
8
- voipPushNotificationCallCId$,
9
- voipCallkeepCallOnForegroundMap$,
10
- voipCallkeepAcceptedCallOnNativeDialerMap$,
11
- pushNonRingingCallData$,
12
- } from './rxSubjects';
13
- import {
14
- clearPushWSEventSubscriptions,
15
- processCallFromPushInBackground,
16
- } from './utils';
2
+ import type { StreamVideoConfig } from '../StreamVideoRN/types';
3
+ import { pushNonRingingCallData$ } from './internal/rxSubjects';
17
4
  import {
5
+ ExpoNotification,
18
6
  getExpoNotificationsLib,
19
- getNotifeeLibThrowIfNotInstalledForPush,
20
7
  getPushNotificationIosLib,
8
+ PushNotificationiOSType,
21
9
  } from './libs';
22
10
  import { StreamVideoClient, getLogger } from '@stream-io/video-client';
23
11
  import { setPushLogoutCallback } from '../internal/pushLogoutCallback';
12
+ import { EventType, Event } from '@notifee/react-native';
13
+ import { StreamVideoRN } from '../StreamVideoRN';
14
+ import { StreamPushPayload } from './utils';
24
15
 
25
16
  type PushConfig = NonNullable<StreamVideoConfig['push']>;
26
17
 
27
- type StreamPayload =
28
- | {
29
- call_cid: string;
30
- type: 'call.ring' | NonRingingPushEvent;
31
- sender: string;
32
- }
33
- | undefined;
34
-
35
18
  let lastApnToken = { token: '', userId: '' };
36
19
 
37
20
  function processNonRingingNotificationStreamPayload(
38
- streamPayload: StreamPayload
21
+ streamPayload: StreamPushPayload
39
22
  ) {
40
23
  if (
41
24
  streamPayload?.sender === 'stream.video' &&
@@ -48,87 +31,56 @@ function processNonRingingNotificationStreamPayload(
48
31
  }
49
32
  }
50
33
 
51
- export const iosCallkeepAcceptCall = (
52
- call_cid: string | undefined,
53
- callUUIDFromCallkeep: string
54
- ) => {
55
- if (!shouldProcessCallFromCallkeep(call_cid, callUUIDFromCallkeep)) {
56
- return;
57
- }
58
- clearPushWSEventSubscriptions();
59
- // to call end callkeep later if ended in app and not through callkeep
60
- voipCallkeepAcceptedCallOnNativeDialerMap$.next({
61
- uuid: callUUIDFromCallkeep,
62
- cid: call_cid,
63
- });
64
- // to process the call in the app
65
- pushAcceptedIncomingCallCId$.next(call_cid);
66
- // no need to keep these references anymore
67
- voipCallkeepCallOnForegroundMap$.next(undefined);
68
- };
69
-
70
- export const iosCallkeepRejectCall = async (
71
- call_cid: string | undefined,
72
- callUUIDFromCallkeep: string,
73
- pushConfig: PushConfig
74
- ) => {
75
- if (!shouldProcessCallFromCallkeep(call_cid, callUUIDFromCallkeep)) {
76
- return;
34
+ export const oniOSExpoNotificationEvent = (event: ExpoNotification) => {
35
+ const pushConfig = StreamVideoRN.getConfig().push;
36
+ if (pushConfig) {
37
+ if (event.request.trigger.type === 'push') {
38
+ const streamPayload = event.request.trigger.payload
39
+ ?.stream as StreamPushPayload;
40
+ processNonRingingNotificationStreamPayload(streamPayload);
41
+ }
77
42
  }
78
- clearPushWSEventSubscriptions();
79
- // no need to keep these references anymore
80
- voipCallkeepAcceptedCallOnNativeDialerMap$.next(undefined);
81
- voipCallkeepCallOnForegroundMap$.next(undefined);
82
- voipPushNotificationCallCId$.next(undefined);
83
- await processCallFromPushInBackground(pushConfig, call_cid, 'decline');
84
43
  };
85
44
 
86
- /**
87
- * Helper function to determine if the answer/end call event from callkeep must be processed
88
- * Just checks if we have a valid call_cid and acts as a type guard for call_cid
89
- */
90
- const shouldProcessCallFromCallkeep = (
91
- call_cid: string | undefined,
92
- callUUIDFromCallkeep: string
93
- ): call_cid is string => {
94
- if (!call_cid || !callUUIDFromCallkeep) {
95
- return false;
45
+ export const oniOSNotifeeEvent = ({
46
+ event,
47
+ }: {
48
+ event: Event;
49
+ isBackground: boolean;
50
+ }) => {
51
+ if (Platform.OS !== 'ios') return;
52
+ const pushConfig = StreamVideoRN.getConfig().push;
53
+ const { type, detail } = event;
54
+ if (pushConfig && type === EventType.PRESS) {
55
+ const streamPayload = detail.notification?.data?.stream as
56
+ | StreamPushPayload
57
+ | undefined;
58
+ const result = processNonRingingNotificationStreamPayload(streamPayload);
59
+ if (result) {
60
+ pushConfig.onTapNonRingingCallNotification?.(result.cid, result.type);
61
+ }
96
62
  }
97
- return true;
98
63
  };
99
64
 
100
- export const setupRemoteNotificationsHandleriOS = (pushConfig: PushConfig) => {
101
- if (Platform.OS !== 'ios') {
65
+ export function onPushNotificationiOSStreamVideoEvent(
66
+ notification: PushNotificationiOSType
67
+ ) {
68
+ const pushNotificationIosLib = getPushNotificationIosLib();
69
+ const data = notification.getData();
70
+ const streamPayload = data?.stream as StreamPushPayload;
71
+ const isClicked = data.userInteraction === 1;
72
+ const pushConfig = StreamVideoRN.getConfig().push;
73
+ if (!streamPayload || !isClicked || !pushConfig) {
74
+ notification.finish(pushNotificationIosLib.FetchResult.NoData);
102
75
  return;
103
76
  }
104
- const notifeeLib = getNotifeeLibThrowIfNotInstalledForPush();
105
-
106
- notifeeLib.default.onForegroundEvent(({ type, detail }) => {
107
- if (type === notifeeLib.EventType.PRESS) {
108
- const streamPayload = detail.notification?.data?.stream as
109
- | StreamPayload
110
- | undefined;
111
- const result = processNonRingingNotificationStreamPayload(streamPayload);
112
- if (result) {
113
- pushConfig.onTapNonRingingCallNotification?.(result.cid, result.type);
114
- }
115
- }
116
- });
117
- if (pushConfig.isExpo) {
118
- const Notifications = getExpoNotificationsLib();
119
-
120
- // foreground handler (just to show the notifications on foreground)
121
- Notifications.setNotificationHandler({
122
- handleNotification: async () => {
123
- return {
124
- shouldShowAlert: true,
125
- shouldPlaySound: true,
126
- shouldSetBadge: false,
127
- };
128
- },
129
- });
77
+ // listen to foreground notifications
78
+ const result = processNonRingingNotificationStreamPayload(streamPayload);
79
+ if (result) {
80
+ pushConfig.onTapNonRingingCallNotification?.(result.cid, result.type);
130
81
  }
131
- };
82
+ notification.finish(pushNotificationIosLib.FetchResult.NoData);
83
+ }
132
84
 
133
85
  /** Send token to stream */
134
86
  export async function initIosNonVoipToken(
@@ -171,34 +123,16 @@ export async function initIosNonVoipToken(
171
123
  setDeviceToken(devicePushToken.data);
172
124
  }
173
125
  );
174
- const subscriptionForReceive =
175
- expoNotificationsLib.addNotificationReceivedListener((event) => {
176
- // listen to foreground notifications
177
- if (event.request.trigger.type === 'push') {
178
- const streamPayload = event.request.trigger.payload
179
- ?.stream as StreamPayload;
180
- processNonRingingNotificationStreamPayload(streamPayload);
181
- }
182
- });
183
126
  setUnsubscribeListener(() => {
184
127
  subscription.remove();
185
- subscriptionForReceive.remove();
186
128
  });
187
129
  } else {
188
130
  const pushNotificationIosLib = getPushNotificationIosLib();
189
131
  pushNotificationIosLib.addEventListener('register', (token) => {
190
132
  setDeviceToken(token);
191
133
  });
192
- pushNotificationIosLib.addEventListener('notification', (notification) => {
193
- const data = notification.getData();
194
- const streamPayload = data?.stream as StreamPayload;
195
- // listen to foreground notifications
196
- processNonRingingNotificationStreamPayload(streamPayload);
197
- notification.finish(pushNotificationIosLib.FetchResult.NoData);
198
- });
199
134
  setUnsubscribeListener(() => {
200
135
  pushNotificationIosLib.removeEventListener('register');
201
- pushNotificationIosLib.removeEventListener('notification');
202
136
  });
203
137
  }
204
138
  }
@@ -1,5 +1,9 @@
1
1
  export type ExpoNotificationsLib = typeof import('expo-notifications');
2
2
 
3
+ import type { Notification } from 'expo-notifications';
4
+
5
+ export type ExpoNotification = Notification;
6
+
3
7
  let expoNotificationsLib: ExpoNotificationsLib | undefined;
4
8
 
5
9
  try {
@@ -1,5 +1,4 @@
1
1
  export * from './expoNotifications';
2
- export * from './expoTaskManager';
3
2
  export * from './firebaseMessaging';
4
3
  export * from './iosPushNotification';
5
4
  export * from './voipPushNotification';
@@ -3,6 +3,10 @@ export type PushNotificationIosLib =
3
3
 
4
4
  let pushNotificationIosLib: PushNotificationIosLib | undefined;
5
5
 
6
+ import type { PushNotification } from '@react-native-community/push-notification-ios';
7
+
8
+ export type PushNotificationiOSType = PushNotification;
9
+
6
10
  try {
7
11
  pushNotificationIosLib =
8
12
  require('@react-native-community/push-notification-ios').default;