Skip to content

Commit 48a8ede

Browse files
committed
feat: add delivery receipt support inside push notification
1 parent b752e16 commit 48a8ede

File tree

4 files changed

+174
-128
lines changed

4 files changed

+174
-128
lines changed

examples/SampleApp/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ const App = () => {
163163
messageListImplementationStoredValue?.id as MessageListImplementationConfigItem['id'],
164164
);
165165
setMessageListMode(messageListModeStoredValue?.mode as MessageListModeConfigItem['mode']);
166-
setMessageListPruning(messageListPruningStoredValue?.value as MessageListPruningConfigItem['value']);
166+
setMessageListPruning(
167+
messageListPruningStoredValue?.value as MessageListPruningConfigItem['value'],
168+
);
167169
};
168170
getMessageListConfig();
169171
return () => {
Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,55 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>en</string>
7+
<key>CFBundleExecutable</key>
8+
<string>$(EXECUTABLE_NAME)</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>$(PRODUCT_NAME)</string>
15+
<key>CFBundlePackageType</key>
16+
<string>APPL</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>0.0.22</string>
19+
<key>CFBundleSignature</key>
20+
<string>????</string>
21+
<key>CFBundleVersion</key>
22+
<string>28</string>
23+
<key>LSRequiresIPhoneOS</key>
24+
<true/>
25+
<key>NSAppTransportSecurity</key>
426
<dict>
5-
<key>CFBundleDevelopmentRegion</key>
6-
<string>en</string>
7-
<key>CFBundleExecutable</key>
8-
<string>$(EXECUTABLE_NAME)</string>
9-
<key>CFBundleIdentifier</key>
10-
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11-
<key>CFBundleInfoDictionaryVersion</key>
12-
<string>6.0</string>
13-
<key>CFBundleName</key>
14-
<string>$(PRODUCT_NAME)</string>
15-
<key>CFBundlePackageType</key>
16-
<string>APPL</string>
17-
<key>CFBundleShortVersionString</key>
18-
<string>0.0.22</string>
19-
<key>CFBundleSignature</key>
20-
<string>????</string>
21-
<key>CFBundleVersion</key>
22-
<string>28</string>
23-
<key>LSRequiresIPhoneOS</key>
24-
<true />
25-
<key>NSAppTransportSecurity</key>
27+
<key>NSExceptionDomains</key>
2628
<dict>
27-
<key>NSExceptionDomains</key>
29+
<key>localhost</key>
2830
<dict>
29-
<key>localhost</key>
30-
<dict>
31-
<key>NSExceptionAllowsInsecureHTTPLoads</key>
32-
<true />
33-
</dict>
31+
<key>NSExceptionAllowsInsecureHTTPLoads</key>
32+
<true/>
3433
</dict>
3534
</dict>
36-
<key>NSLocationWhenInUseUsageDescription</key>
37-
<string></string>
38-
<key>UILaunchStoryboardName</key>
39-
<string>LaunchScreen</string>
40-
<key>UIRequiredDeviceCapabilities</key>
41-
<array>
42-
<string>armv7</string>
43-
</array>
44-
<key>UISupportedInterfaceOrientations</key>
45-
<array>
46-
<string>UIInterfaceOrientationPortrait</string>
47-
<string>UIInterfaceOrientationLandscapeLeft</string>
48-
<string>UIInterfaceOrientationLandscapeRight</string>
49-
</array>
50-
<key>UIViewControllerBasedStatusBarAppearance</key>
51-
<false />
5235
</dict>
53-
</plist>
36+
<key>NSLocationWhenInUseUsageDescription</key>
37+
<string></string>
38+
<key>RCTNewArchEnabled</key>
39+
<true/>
40+
<key>UILaunchStoryboardName</key>
41+
<string>LaunchScreen</string>
42+
<key>UIRequiredDeviceCapabilities</key>
43+
<array>
44+
<string>armv7</string>
45+
</array>
46+
<key>UISupportedInterfaceOrientations</key>
47+
<array>
48+
<string>UIInterfaceOrientationPortrait</string>
49+
<string>UIInterfaceOrientationLandscapeLeft</string>
50+
<string>UIInterfaceOrientationLandscapeRight</string>
51+
</array>
52+
<key>UIViewControllerBasedStatusBarAppearance</key>
53+
<false/>
54+
</dict>
55+
</plist>
Lines changed: 59 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,64 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>en</string>
7+
<key>CFBundleDisplayName</key>
8+
<string>ChatSample</string>
9+
<key>CFBundleExecutable</key>
10+
<string>$(EXECUTABLE_NAME)</string>
11+
<key>CFBundleIdentifier</key>
12+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13+
<key>CFBundleInfoDictionaryVersion</key>
14+
<string>6.0</string>
15+
<key>CFBundleName</key>
16+
<string>$(PRODUCT_NAME)</string>
17+
<key>CFBundlePackageType</key>
18+
<string>APPL</string>
19+
<key>CFBundleShortVersionString</key>
20+
<string>1.11.0</string>
21+
<key>CFBundleSignature</key>
22+
<string>????</string>
23+
<key>CFBundleVersion</key>
24+
<string>154</string>
25+
<key>FirebaseAppDelegateProxyEnabled</key>
26+
<true/>
27+
<key>ITSAppUsesNonExemptEncryption</key>
28+
<false/>
29+
<key>LSRequiresIPhoneOS</key>
30+
<true/>
31+
<key>NSAppTransportSecurity</key>
432
<dict>
5-
<key>CFBundleDevelopmentRegion</key>
6-
<string>en</string>
7-
<key>CFBundleDisplayName</key>
8-
<string>ChatSample</string>
9-
<key>CFBundleExecutable</key>
10-
<string>$(EXECUTABLE_NAME)</string>
11-
<key>CFBundleIdentifier</key>
12-
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13-
<key>CFBundleInfoDictionaryVersion</key>
14-
<string>6.0</string>
15-
<key>CFBundleName</key>
16-
<string>$(PRODUCT_NAME)</string>
17-
<key>CFBundlePackageType</key>
18-
<string>APPL</string>
19-
<key>CFBundleShortVersionString</key>
20-
<string>1.11.0</string>
21-
<key>CFBundleSignature</key>
22-
<string>????</string>
23-
<key>CFBundleVersion</key>
24-
<string>154</string>
25-
<key>FirebaseAppDelegateProxyEnabled</key>
26-
<true />
27-
<key>ITSAppUsesNonExemptEncryption</key>
28-
<false />
29-
<key>LSRequiresIPhoneOS</key>
30-
<true />
31-
<key>NSAppTransportSecurity</key>
32-
<dict>
33-
<key>NSAllowsArbitraryLoads</key>
34-
<false />
35-
<key>NSAllowsLocalNetworking</key>
36-
<true />
37-
</dict>
38-
<key>NSCameraUsageDescription</key>
39-
<string>$(PRODUCT_NAME) would like to use your camera to share image in a message.</string>
40-
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
41-
<string>$(PRODUCT_NAME) would like share live location always in a message.</string>
42-
<key>NSLocationWhenInUseUsageDescription</key>
43-
<string>$(PRODUCT_NAME) would like share live location when in use in a message.</string>
44-
<key>NSMicrophoneUsageDescription</key>
45-
<string>$(PRODUCT_NAME) would like to use your microphone for voice recording.</string>
46-
<key>NSPhotoLibraryUsageDescription</key>
47-
<string>$(PRODUCT_NAME) would like access to your photo gallery to share image in a message.</string>
48-
<key>UILaunchStoryboardName</key>
49-
<string>LaunchScreen</string>
50-
<key>UIRequiredDeviceCapabilities</key>
51-
<array>
52-
<string>arm64</string>
53-
</array>
54-
<key>UISupportedInterfaceOrientations</key>
55-
<array>
56-
<string>UIInterfaceOrientationPortrait</string>
57-
<string>UIInterfaceOrientationPortraitUpsideDown</string>
58-
</array>
59-
<key>UIViewControllerBasedStatusBarAppearance</key>
60-
<false />
33+
<key>NSAllowsArbitraryLoads</key>
34+
<false/>
35+
<key>NSAllowsLocalNetworking</key>
36+
<true/>
6137
</dict>
62-
</plist>
38+
<key>NSCameraUsageDescription</key>
39+
<string>$(PRODUCT_NAME) would like to use your camera to share image in a message.</string>
40+
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
41+
<string>$(PRODUCT_NAME) would like share live location always in a message.</string>
42+
<key>NSLocationWhenInUseUsageDescription</key>
43+
<string>$(PRODUCT_NAME) would like share live location when in use in a message.</string>
44+
<key>NSMicrophoneUsageDescription</key>
45+
<string>$(PRODUCT_NAME) would like to use your microphone for voice recording.</string>
46+
<key>NSPhotoLibraryUsageDescription</key>
47+
<string>$(PRODUCT_NAME) would like access to your photo gallery to share image in a message.</string>
48+
<key>RCTNewArchEnabled</key>
49+
<true/>
50+
<key>UILaunchStoryboardName</key>
51+
<string>LaunchScreen</string>
52+
<key>UIRequiredDeviceCapabilities</key>
53+
<array>
54+
<string>arm64</string>
55+
</array>
56+
<key>UISupportedInterfaceOrientations</key>
57+
<array>
58+
<string>UIInterfaceOrientationPortrait</string>
59+
<string>UIInterfaceOrientationPortraitUpsideDown</string>
60+
</array>
61+
<key>UIViewControllerBasedStatusBarAppearance</key>
62+
<false/>
63+
</dict>
64+
</plist>

examples/SampleApp/src/hooks/useChatClient.ts

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,78 @@
11
import { useEffect, useRef, useState } from 'react';
2-
import { StreamChat, PushProvider } from 'stream-chat';
3-
import { getMessaging, AuthorizationStatus } from '@react-native-firebase/messaging';
2+
import { StreamChat, PushProvider, DeliveredMessageConfirmation } from 'stream-chat';
3+
import {
4+
getMessaging,
5+
AuthorizationStatus,
6+
setBackgroundMessageHandler,
7+
FirebaseMessagingTypes,
8+
} from '@react-native-firebase/messaging';
49
import notifee from '@notifee/react-native';
510
import { SqliteClient } from 'stream-chat-react-native';
611
import { USER_TOKENS, USERS } from '../ChatUsers';
712
import AsyncStore from '../utils/AsyncStore';
813

914
import type { LoginConfig } from '../types';
1015
import { PermissionsAndroid, Platform } from 'react-native';
16+
import AsyncStorage from '@react-native-async-storage/async-storage';
1117

1218
const messaging = getMessaging();
1319

20+
const displayNotification = async (
21+
remoteMessage: FirebaseMessagingTypes.RemoteMessage,
22+
channelId: string,
23+
) => {
24+
const { stream, ...rest } = remoteMessage.data ?? {};
25+
const data = {
26+
...rest,
27+
...((stream as unknown as Record<string, string> | undefined) ?? {}), // extract and merge stream object if present
28+
};
29+
if (data.body && data.title) {
30+
await notifee.displayNotification({
31+
android: {
32+
channelId,
33+
pressAction: {
34+
id: 'default',
35+
},
36+
},
37+
body: data.body as string,
38+
title: data.title as string,
39+
data,
40+
});
41+
}
42+
};
43+
44+
setBackgroundMessageHandler(messaging, async (remoteMessage) => {
45+
try {
46+
const loginConfigStringified = await AsyncStorage.getItem('@stream-rn-sampleapp-login-config');
47+
const loginConfig = JSON.parse(loginConfigStringified ?? '');
48+
const chatClient = StreamChat.getInstance(loginConfig.apiKey);
49+
chatClient._setToken({ id: loginConfig.userId }, loginConfig.userToken);
50+
51+
const notification = remoteMessage.data;
52+
53+
const deliverMessageConfirmation = [
54+
{
55+
cid: notification?.cid,
56+
id: notification?.id,
57+
},
58+
];
59+
60+
await chatClient?.markChannelsDelivered({
61+
latest_delivered_messages: deliverMessageConfirmation as DeliveredMessageConfirmation[],
62+
});
63+
64+
// create the android channel to send the notification to
65+
const channelId = await notifee.createChannel({
66+
id: 'chat-messages',
67+
name: 'Chat Messages',
68+
});
69+
// display the notification
70+
await displayNotification(remoteMessage, channelId);
71+
} catch (error) {
72+
console.error(error);
73+
}
74+
});
75+
1476
// Request Push Notification permission from device.
1577
const requestNotificationPermission = async () => {
1678
const authStatus = await messaging.requestPermission();
@@ -94,34 +156,12 @@ export const useChatClient = () => {
94156
});
95157
// show notifications when on foreground
96158
const unsubscribeForegroundMessageReceive = messaging.onMessage(async (remoteMessage) => {
97-
const { stream, ...rest } = remoteMessage.data ?? {};
98-
const data = {
99-
...rest,
100-
...((stream as unknown as Record<string, string> | undefined) ?? {}), // extract and merge stream object if present
101-
};
102159
const channelId = await notifee.createChannel({
103160
id: 'foreground',
104161
name: 'Foreground Messages',
105162
});
106-
// create the android channel to send the notification to
107-
// display the notification on foreground
108-
const notification = remoteMessage.notification ?? {};
109-
const body = (data.body ?? notification.body) as string;
110-
const title = (data.title ?? notification.title) as string;
111-
112-
if (body && title) {
113-
await notifee.displayNotification({
114-
android: {
115-
channelId,
116-
pressAction: {
117-
id: 'default',
118-
},
119-
},
120-
body,
121-
title,
122-
data,
123-
});
124-
}
163+
164+
await displayNotification(remoteMessage, channelId);
125165
});
126166

127167
unsubscribePushListenersRef.current = () => {

0 commit comments

Comments
 (0)