@stream-io/video-react-native-sdk 0.1.2 → 0.1.4

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 (111) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/commonjs/components/Call/CallControls/HangupCallButton.js +4 -6
  3. package/dist/commonjs/components/Call/CallControls/HangupCallButton.js.map +1 -1
  4. package/dist/commonjs/hooks/push/index.js +4 -0
  5. package/dist/commonjs/hooks/push/index.js.map +1 -1
  6. package/dist/commonjs/hooks/push/useInitAndroidTokenAndRest.js +8 -2
  7. package/dist/commonjs/hooks/push/useInitAndroidTokenAndRest.js.map +1 -1
  8. package/dist/commonjs/hooks/push/useIosInitRemoteNotifications.js +34 -0
  9. package/dist/commonjs/hooks/push/useIosInitRemoteNotifications.js.map +1 -0
  10. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js +50 -4
  11. package/dist/commonjs/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  12. package/dist/commonjs/hooks/push/useProcessPushNonRingingCallEffect.js +50 -0
  13. package/dist/commonjs/hooks/push/useProcessPushNonRingingCallEffect.js.map +1 -0
  14. package/dist/commonjs/utils/StreamVideoRN/index.js +33 -0
  15. package/dist/commonjs/utils/StreamVideoRN/index.js.map +1 -1
  16. package/dist/commonjs/utils/internal/newNotificationCallbacks.js +18 -0
  17. package/dist/commonjs/utils/internal/newNotificationCallbacks.js.map +1 -0
  18. package/dist/commonjs/utils/internal/pushLogoutCallback.js +18 -0
  19. package/dist/commonjs/utils/internal/pushLogoutCallback.js.map +1 -0
  20. package/dist/commonjs/utils/push/android.js +182 -68
  21. package/dist/commonjs/utils/push/android.js.map +1 -1
  22. package/dist/commonjs/utils/push/ios.js +107 -1
  23. package/dist/commonjs/utils/push/ios.js.map +1 -1
  24. package/dist/commonjs/utils/push/libs.js +34 -1
  25. package/dist/commonjs/utils/push/libs.js.map +1 -1
  26. package/dist/commonjs/utils/push/rxSubjects.js +8 -1
  27. package/dist/commonjs/utils/push/rxSubjects.js.map +1 -1
  28. package/dist/commonjs/utils/push/utils.js +29 -1
  29. package/dist/commonjs/utils/push/utils.js.map +1 -1
  30. package/dist/commonjs/version.js +1 -1
  31. package/dist/module/components/Call/CallControls/HangupCallButton.js +3 -4
  32. package/dist/module/components/Call/CallControls/HangupCallButton.js.map +1 -1
  33. package/dist/module/hooks/push/index.js +4 -0
  34. package/dist/module/hooks/push/index.js.map +1 -1
  35. package/dist/module/hooks/push/useInitAndroidTokenAndRest.js +8 -2
  36. package/dist/module/hooks/push/useInitAndroidTokenAndRest.js.map +1 -1
  37. package/dist/module/hooks/push/useIosInitRemoteNotifications.js +28 -0
  38. package/dist/module/hooks/push/useIosInitRemoteNotifications.js.map +1 -0
  39. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js +49 -4
  40. package/dist/module/hooks/push/useIosVoipPushEventsSetupEffect.js.map +1 -1
  41. package/dist/module/hooks/push/useProcessPushNonRingingCallEffect.js +44 -0
  42. package/dist/module/hooks/push/useProcessPushNonRingingCallEffect.js.map +1 -0
  43. package/dist/module/utils/StreamVideoRN/index.js +32 -0
  44. package/dist/module/utils/StreamVideoRN/index.js.map +1 -1
  45. package/dist/module/utils/internal/newNotificationCallbacks.js +10 -0
  46. package/dist/module/utils/internal/newNotificationCallbacks.js.map +1 -0
  47. package/dist/module/utils/internal/pushLogoutCallback.js +10 -0
  48. package/dist/module/utils/internal/pushLogoutCallback.js.map +1 -0
  49. package/dist/module/utils/push/android.js +184 -70
  50. package/dist/module/utils/push/android.js.map +1 -1
  51. package/dist/module/utils/push/ios.js +103 -1
  52. package/dist/module/utils/push/ios.js.map +1 -1
  53. package/dist/module/utils/push/libs.js +31 -1
  54. package/dist/module/utils/push/libs.js.map +1 -1
  55. package/dist/module/utils/push/rxSubjects.js +5 -0
  56. package/dist/module/utils/push/rxSubjects.js.map +1 -1
  57. package/dist/module/utils/push/utils.js +27 -0
  58. package/dist/module/utils/push/utils.js.map +1 -1
  59. package/dist/module/version.js +1 -1
  60. package/dist/typescript/hooks/push/index.d.ts.map +1 -1
  61. package/dist/typescript/hooks/push/useInitAndroidTokenAndRest.d.ts +1 -1
  62. package/dist/typescript/hooks/push/useInitAndroidTokenAndRest.d.ts.map +1 -1
  63. package/dist/typescript/hooks/push/useIosInitRemoteNotifications.d.ts +5 -0
  64. package/dist/typescript/hooks/push/useIosInitRemoteNotifications.d.ts.map +1 -0
  65. package/dist/typescript/hooks/push/useIosVoipPushEventsSetupEffect.d.ts.map +1 -1
  66. package/dist/typescript/hooks/push/useProcessPushNonRingingCallEffect.d.ts +7 -0
  67. package/dist/typescript/hooks/push/useProcessPushNonRingingCallEffect.d.ts.map +1 -0
  68. package/dist/typescript/utils/StreamVideoRN/index.d.ts +12 -0
  69. package/dist/typescript/utils/StreamVideoRN/index.d.ts.map +1 -1
  70. package/dist/typescript/utils/StreamVideoRN/types.d.ts +40 -6
  71. package/dist/typescript/utils/StreamVideoRN/types.d.ts.map +1 -1
  72. package/dist/typescript/utils/internal/newNotificationCallbacks.d.ts +10 -0
  73. package/dist/typescript/utils/internal/newNotificationCallbacks.d.ts.map +1 -0
  74. package/dist/typescript/utils/internal/pushLogoutCallback.d.ts +8 -0
  75. package/dist/typescript/utils/internal/pushLogoutCallback.d.ts.map +1 -0
  76. package/dist/typescript/utils/push/android.d.ts +1 -1
  77. package/dist/typescript/utils/push/android.d.ts.map +1 -1
  78. package/dist/typescript/utils/push/ios.d.ts +4 -0
  79. package/dist/typescript/utils/push/ios.d.ts.map +1 -1
  80. package/dist/typescript/utils/push/libs.d.ts +6 -0
  81. package/dist/typescript/utils/push/libs.d.ts.map +1 -1
  82. package/dist/typescript/utils/push/rxSubjects.d.ts +9 -0
  83. package/dist/typescript/utils/push/rxSubjects.d.ts.map +1 -1
  84. package/dist/typescript/utils/push/utils.d.ts +9 -1
  85. package/dist/typescript/utils/push/utils.d.ts.map +1 -1
  86. package/dist/typescript/version.d.ts +1 -1
  87. package/expo-config-plugin/dist/index.d.ts +3 -2
  88. package/expo-config-plugin/dist/index.js +9 -5
  89. package/expo-config-plugin/dist/withPushAppDelegate.d.ts +4 -0
  90. package/expo-config-plugin/dist/withPushAppDelegate.js +119 -0
  91. package/expo-config-plugin/dist/withiOSInfoPlist.d.ts +2 -1
  92. package/expo-config-plugin/dist/withiOSInfoPlist.js +6 -1
  93. package/package.json +19 -3
  94. package/src/components/Call/CallControls/HangupCallButton.tsx +4 -4
  95. package/src/hooks/push/index.ts +4 -0
  96. package/src/hooks/push/useInitAndroidTokenAndRest.ts +8 -2
  97. package/src/hooks/push/useIosInitRemoteNotifications.ts +29 -0
  98. package/src/hooks/push/useIosVoipPushEventsSetupEffect.ts +50 -3
  99. package/src/hooks/push/useProcessPushNonRingingCallEffect.ts +44 -0
  100. package/src/utils/StreamVideoRN/index.ts +36 -0
  101. package/src/utils/StreamVideoRN/types.ts +47 -6
  102. package/src/utils/internal/newNotificationCallbacks.ts +29 -0
  103. package/src/utils/internal/pushLogoutCallback.ts +17 -0
  104. package/src/utils/push/android.ts +203 -74
  105. package/src/utils/push/ios.ts +120 -1
  106. package/src/utils/push/libs.ts +48 -2
  107. package/src/utils/push/rxSubjects.ts +9 -0
  108. package/src/utils/push/utils.ts +35 -1
  109. package/src/version.ts +1 -1
  110. /package/expo-config-plugin/dist/{withAppDelegate.d.ts → withStreamVideoReactNativeSDKAppDelegate.d.ts} +0 -0
  111. /package/expo-config-plugin/dist/{withAppDelegate.js → withStreamVideoReactNativeSDKAppDelegate.js} +0 -0
@@ -7,7 +7,7 @@ import { StreamVideoRN } from '../../utils';
7
7
  import { initAndroidPushToken } from '../../utils/push/android';
8
8
 
9
9
  /**
10
- * This hook is used to initialize the push token for Android and ask notification permissions.
10
+ * This hook is used to initialize the push token for Android.
11
11
  */
12
12
  export const useInitAndroidTokenAndRest = () => {
13
13
  const client = useStreamVideoClient();
@@ -18,6 +18,12 @@ export const useInitAndroidTokenAndRest = () => {
18
18
  if (!client || !connectedUserId || !pushConfig) {
19
19
  return;
20
20
  }
21
- initAndroidPushToken(client, pushConfig);
21
+ let unsubscribe = () => {};
22
+ initAndroidPushToken(client, pushConfig, (unsubscribeListener) => {
23
+ unsubscribe = unsubscribeListener;
24
+ });
25
+ return () => {
26
+ unsubscribe();
27
+ };
22
28
  }, [client, connectedUserId]);
23
29
  };
@@ -0,0 +1,29 @@
1
+ import {
2
+ useConnectedUser,
3
+ useStreamVideoClient,
4
+ } from '@stream-io/video-react-bindings';
5
+ import { useEffect } from 'react';
6
+ import { StreamVideoRN } from '../../utils';
7
+ import { initIosNonVoipToken } from '../../utils/push/ios';
8
+
9
+ /**
10
+ * This hook is used to initialize the push token for iOS.
11
+ */
12
+ export const useIosInitRemoteNotifications = () => {
13
+ const client = useStreamVideoClient();
14
+ const connectedUserId = useConnectedUser()?.id;
15
+ useEffect(() => {
16
+ const pushConfig = StreamVideoRN.getConfig().push;
17
+ // NOTE: we need to wait for user to be connected before we can send the push token
18
+ if (!client || !connectedUserId || !pushConfig) {
19
+ return;
20
+ }
21
+ let unsubscribe = () => {};
22
+ initIosNonVoipToken(client, pushConfig, (unsubscribeListener) => {
23
+ unsubscribe = unsubscribeListener;
24
+ });
25
+ return () => {
26
+ unsubscribe();
27
+ };
28
+ }, [client, connectedUserId]);
29
+ };
@@ -5,6 +5,9 @@ import { Platform } from 'react-native';
5
5
  import { StreamVideoRN } from '../../utils';
6
6
  import { useStreamVideoClient } from '@stream-io/video-react-bindings';
7
7
  import { voipPushNotificationCallCId$ } from '../../utils/push/rxSubjects';
8
+ import { setPushLogoutCallback } from '../../utils/internal/pushLogoutCallback';
9
+
10
+ let lastVoipToken: string | undefined = '';
8
11
 
9
12
  /**
10
13
  * This hook is used to do the initial setup of listeners
@@ -17,14 +20,35 @@ export const useIosVoipPushEventsSetupEffect = () => {
17
20
  if (Platform.OS !== 'ios' || !pushConfig || !client) {
18
21
  return;
19
22
  }
23
+ if (lastVoipToken) {
24
+ // send token to stream (userId might have switched on the same device)
25
+ const push_provider_name = pushConfig.ios.pushProviderName;
26
+ if (!push_provider_name) {
27
+ return;
28
+ }
29
+ client
30
+ .addVoipDevice(lastVoipToken, 'apn', push_provider_name)
31
+ .catch((err) => {
32
+ console.warn('Failed to send voip token to stream', err);
33
+ });
34
+ }
20
35
  const voipPushNotification = getVoipPushNotificationLib();
21
-
22
36
  const onTokenReceived = (token: string) => {
23
37
  // send token to stream
38
+ lastVoipToken = token;
24
39
  const push_provider_name = pushConfig.ios.pushProviderName;
40
+ if (!push_provider_name) {
41
+ return;
42
+ }
25
43
  client.addVoipDevice(token, 'apn', push_provider_name).catch((err) => {
26
44
  console.warn('Failed to send voip token to stream', err);
27
45
  });
46
+ // set the logout callback
47
+ setPushLogoutCallback(() => {
48
+ client.removeDevice(token).catch((err) => {
49
+ console.warn('Failed to remove voip token from stream', err);
50
+ });
51
+ });
28
52
  };
29
53
  // fired when PushKit give us the latest token
30
54
  voipPushNotification.addEventListener('register', (token) => {
@@ -68,9 +92,32 @@ export const useIosVoipPushEventsSetupEffect = () => {
68
92
  };
69
93
 
70
94
  const onNotificationReceived = (notification: any) => {
95
+ /* --- Example payload ---
96
+ {
97
+ "aps": {
98
+ "alert": {
99
+ "body": "",
100
+ "title": "Vishal Narkhede is calling you"
101
+ },
102
+ "badge": 0,
103
+ "category": "stream.video",
104
+ "mutable-content": 1
105
+ },
106
+ "stream": {
107
+ "call_cid": "default:ixbm7y0k74pbjnq",
108
+ "call_display_name": "",
109
+ "created_by_display_name": "Vishal Narkhede",
110
+ "created_by_id": "vishalexpo",
111
+ "receiver_id": "santhoshexpo",
112
+ "sender": "stream.video",
113
+ "type": "call.ring",
114
+ "version": "v2"
115
+ }
116
+ } */
71
117
  const sender = notification?.stream?.sender;
72
- // do not process any other notifications other than stream.video
73
- if (sender !== 'stream.video') {
118
+ const type = notification?.stream?.type;
119
+ // do not process any other notifications other than stream.video or ringing
120
+ if (sender !== 'stream.video' && type !== 'call.ring') {
74
121
  return;
75
122
  }
76
123
  const call_cid = notification?.stream?.call_cid;
@@ -0,0 +1,44 @@
1
+ import { pushNonRingingCallData$ } from '../../utils/push/rxSubjects';
2
+ import { useEffect } from 'react';
3
+ import { StreamVideoRN } from '../../utils';
4
+ import {
5
+ useConnectedUser,
6
+ useStreamVideoClient,
7
+ } from '@stream-io/video-react-bindings';
8
+ import { filter } from 'rxjs/operators';
9
+ import { processNonIncomingCallFromPush } from '../../utils/push/utils';
10
+
11
+ /**
12
+ * This hook is used to process the non ringing call data via push notifications using the relevant rxjs subject
13
+ * Note: this effect cannot work when push notifications are received when the app is in quit state or in other words when the client is not connected with a websocket.
14
+ * So we essentially run this effect only when the client is connected with a websocket.
15
+ */
16
+ export const useProcessPushNonRingingCallEffect = () => {
17
+ const client = useStreamVideoClient();
18
+ const connectedUserId = useConnectedUser()?.id;
19
+ // The Effect to join/reject call automatically when incoming call was received and processed from push notification
20
+ useEffect(() => {
21
+ const pushConfig = StreamVideoRN.getConfig().push;
22
+ if (!pushConfig || !client || !connectedUserId) {
23
+ return;
24
+ }
25
+
26
+ const subscription = pushNonRingingCallData$
27
+ .pipe(filter(NotUndefined))
28
+ .subscribe(async ({ cid, type }) => {
29
+ await processNonIncomingCallFromPush(client, cid, type);
30
+ pushNonRingingCallData$.next(undefined); // remove the current data to avoid processing again
31
+ });
32
+
33
+ return () => {
34
+ subscription.unsubscribe();
35
+ };
36
+ }, [client, connectedUserId]);
37
+ };
38
+
39
+ /**
40
+ * A type guard to check if the data is not undefined
41
+ */
42
+ function NotUndefined<T>(data: T | undefined): data is T {
43
+ return data !== undefined;
44
+ }
@@ -1,6 +1,11 @@
1
1
  import { AndroidImportance } from '@notifee/react-native';
2
2
  import { setupFirebaseHandlerAndroid } from '../push/android';
3
3
  import { StreamVideoConfig } from './types';
4
+ import pushLogoutCallbacks from '../internal/pushLogoutCallback';
5
+ import { setupRemoteNotificationsHandleriOS } from '../push/ios';
6
+ import newNotificationCallbacks, {
7
+ NewCallNotificationCallback,
8
+ } from '../internal/newNotificationCallbacks';
4
9
 
5
10
  const DEFAULT_STREAM_VIDEO_CONFIG: StreamVideoConfig = {
6
11
  foregroundService: {
@@ -58,9 +63,40 @@ export class StreamVideoRN {
58
63
  this.config.push = pushConfig;
59
64
  // After getting the config we should setup callkeep events, firebase handler asap to handle incoming calls from a dead state
60
65
  setupFirebaseHandlerAndroid(pushConfig);
66
+ // setup ios handler for non-voip push notifications asap
67
+ setupRemoteNotificationsHandleriOS(pushConfig);
61
68
  }
62
69
 
63
70
  static getConfig() {
64
71
  return this.config;
65
72
  }
73
+
74
+ /**
75
+ * This is the function to be called when the push token must be removed.
76
+ * Typically used on user logout.
77
+ */
78
+ static onPushLogout() {
79
+ if (pushLogoutCallbacks.current) {
80
+ pushLogoutCallbacks.current.forEach((callback) => callback());
81
+ }
82
+ }
83
+
84
+ /**
85
+ * This function is used to add a callback to be called when a new call notification is received.
86
+ * @param callback
87
+ * @returns Unsubscribe function
88
+ */
89
+ static addOnNewCallNotificationListener(
90
+ callback: NewCallNotificationCallback,
91
+ ) {
92
+ if (!newNotificationCallbacks.current) {
93
+ newNotificationCallbacks.current = [callback];
94
+ } else {
95
+ newNotificationCallbacks.current.push(callback);
96
+ }
97
+ return () => {
98
+ newNotificationCallbacks.current =
99
+ newNotificationCallbacks.current?.filter((cb) => cb !== callback);
100
+ };
101
+ }
66
102
  }
@@ -1,6 +1,8 @@
1
1
  import { StreamVideoClient } from '@stream-io/video-client';
2
2
  import { AndroidChannel } from '@notifee/react-native';
3
3
 
4
+ export type NonRingingPushEvent = 'call.live_started' | 'call.notification';
5
+
4
6
  export type StreamVideoConfig = {
5
7
  /**
6
8
  * The configuration to be used for push notifications.
@@ -8,14 +10,32 @@ export type StreamVideoConfig = {
8
10
  * @default undefined
9
11
  */
10
12
  push?: {
13
+ isExpo?: boolean;
11
14
  ios: {
12
15
  /**
13
16
  * The name for the alias of push provider used for iOS
17
+ * Pass undefined if you will not be using stream's push notifications but still want to use the functionality of the SDK
14
18
  * @example "production-apn-video" or "staging-apn-video" based on the environment
15
19
  */
16
- pushProviderName: string;
20
+ pushProviderName?: string;
17
21
  };
18
22
  android: {
23
+ /**
24
+ * The name for the alias of push provider used for Android
25
+ * Pass undefined if you will not be using stream's push notifications but still want to use the functionality of the SDK
26
+ * @example "production-fcm-video" or "staging-fcm-video" based on the environment
27
+ */
28
+ pushProviderName?: string;
29
+ /**
30
+ * The notification channel to be used for non ringing calls for Android.
31
+ * @example
32
+ * {
33
+ * id: 'stream_call_notifications',
34
+ * name: 'Call notifications',
35
+ * importance: AndroidImportance.HIGH
36
+ * }
37
+ */
38
+ callChannel?: AndroidChannel;
19
39
  /**
20
40
  * The notification channel to be used for incoming calls for Android.
21
41
  * @example
@@ -25,7 +45,7 @@ export type StreamVideoConfig = {
25
45
  * importance: AndroidImportance.HIGH
26
46
  * }
27
47
  */
28
- incomingCallChannel: AndroidChannel;
48
+ incomingCallChannel?: AndroidChannel;
29
49
  /**
30
50
  * Functions to create the texts shown in the notification for incoming calls in Android.
31
51
  * @example
@@ -34,15 +54,31 @@ export type StreamVideoConfig = {
34
54
  * body: (createdUserName: string) => `Tap to answer the call`
35
55
  * }
36
56
  */
37
- incomingCallNotificationTextGetters: {
57
+ incomingCallNotificationTextGetters?: {
38
58
  getTitle: (createdUserName: string) => string;
39
59
  getBody: (createdUserName: string) => string;
40
60
  };
41
61
  /**
42
- * The name for the alias of push provider used for Android
43
- * @example "production-fcm-video" or "staging-fcm-video" based on the environment
62
+ * Functions to create the texts shown in the notification for non ringing calls in Android.
63
+ * @example
64
+ * getTitle(type, createdUserName) {
65
+ if (type === 'call.live_started') {
66
+ return `Call went live, it was started by ${createdUserName}`;
67
+ } else {
68
+ return `${createdUserName} is notifying you about a call`;
69
+ }
70
+ },
71
+ getBody(_type, createdUserName) {
72
+ return 'Tap to open the call';
73
+ },
44
74
  */
45
- pushProviderName: string;
75
+ callNotificationTextGetters?: {
76
+ getTitle: (
77
+ type: NonRingingPushEvent,
78
+ createdUserName: string,
79
+ ) => string;
80
+ getBody: (type: NonRingingPushEvent, createdUserName: string) => string;
81
+ };
46
82
  };
47
83
  /**
48
84
  * This function is used to create a custom video client.
@@ -66,6 +102,11 @@ export type StreamVideoConfig = {
66
102
  navigateAcceptCall: () => void;
67
103
  /** The callback that is called when a push notification is tapped but user did not press accept or decline, used for navigation */
68
104
  navigateToIncomingCall: () => void;
105
+ /** Callback that is called when a non ringing push notification was tapped */
106
+ onTapNonRingingCallNotification?: (
107
+ call_cid: string,
108
+ type: NonRingingPushEvent,
109
+ ) => void;
69
110
  };
70
111
  foregroundService: {
71
112
  android: {
@@ -0,0 +1,29 @@
1
+ import { Call } from '@stream-io/video-client';
2
+ import { NonRingingPushEvent } from '../StreamVideoRN/types';
3
+
4
+ export type NewCallNotificationCallback = (
5
+ call: Call,
6
+ notificationType: NonRingingPushEvent,
7
+ ) => void;
8
+
9
+ type NewNotificationCallbacks = {
10
+ current?: NewCallNotificationCallback[];
11
+ };
12
+
13
+ let lastCid = '';
14
+
15
+ const newNotificationCallbacks: NewNotificationCallbacks = {};
16
+
17
+ export const onNewCallNotification: NewCallNotificationCallback = (
18
+ call,
19
+ notificationType,
20
+ ) => {
21
+ if (newNotificationCallbacks.current && lastCid !== call.cid) {
22
+ newNotificationCallbacks.current.forEach((callback) =>
23
+ callback(call, notificationType),
24
+ );
25
+ lastCid = call.cid;
26
+ }
27
+ };
28
+
29
+ export default newNotificationCallbacks;
@@ -0,0 +1,17 @@
1
+ type Callback = () => void;
2
+
3
+ type PushLogoutCallbacks = {
4
+ current?: Callback[];
5
+ };
6
+
7
+ let pushLogoutCallbacks: PushLogoutCallbacks = {};
8
+
9
+ export const setPushLogoutCallback = (callback: () => void) => {
10
+ if (!pushLogoutCallbacks.current) {
11
+ pushLogoutCallbacks.current = [callback];
12
+ } else {
13
+ pushLogoutCallbacks.current.push(callback);
14
+ }
15
+ };
16
+
17
+ export default pushLogoutCallbacks;