|
21 | 21 | - [Swipe message left to delete and right to reply](#swipe-message-left-to-delete-and-right-to-reply-message-example-9) |
22 | 22 |
|
23 | 23 | - [How to customize actionsheet styles](#actionsheet-styling) |
| 24 | + |
24 | 25 | - [What is KeyboardCompatibleView and how to customize collapsing/expanding animation](#keyboard) |
| 26 | + |
25 | 27 | - [How to customize underlying `FlatList` in `MessageList` or `ChannelList`?](#how-to-customizemodify-underlying-flatlist-of-messagelist-or-channellist) |
| 28 | + |
26 | 29 | - [Image upload takes too long. How can I fix it?](#image-upload-takes-too-long-how-can-i-fix-it) |
| 30 | + |
27 | 31 | - [How can I override/intercept message actions such as edit, delete, reaction, reply? e.g. to track analytics](#how-can-i-overrideintercept-message-actions-such-as-edit-delete-reaction-reply-eg-to-track-analytics) |
28 | 32 |
|
29 | 33 | - MessageInput customizations |
|
36 | 40 |
|
37 | 41 | - [Growing input box with content](#growing-input-box-with-content) |
38 | 42 |
|
| 43 | +- [Checklist for Push notifications](#checklist-for-push-notifications) |
| 44 | + |
39 | 45 | # How to customize message component |
40 | 46 |
|
41 | 47 | `MessageList` component accepts `Message` prop, where you can mention or provide custom message (UI) component. |
@@ -1298,4 +1304,139 @@ class ChannelScreen extends React.Component { |
1298 | 1304 | ) |
1299 | 1305 | } |
1300 | 1306 | } |
1301 | | -``` |
| 1307 | +``` |
| 1308 | + |
| 1309 | +## Checklist for Push notifications |
| 1310 | + |
| 1311 | +### Setup |
| 1312 | + |
| 1313 | +For setup regarding push notifications, first of all make sure you have followed all the steps: |
| 1314 | + |
| 1315 | +#### For iOS |
| 1316 | + |
| 1317 | + - https://getstream.io/chat/docs/push_ios/?language=java |
| 1318 | + - https://getstream.io/chat/docs/rn_push_initial/?language=java |
| 1319 | + - https://getstream.io/chat/docs/rn_push_ios/?language=java |
| 1320 | + |
| 1321 | +#### For android |
| 1322 | + |
| 1323 | + - https://getstream.io/chat/docs/push_android/?language=java |
| 1324 | + - https://getstream.io/chat/docs/rn_push_initial/?language=java |
| 1325 | + - https://getstream.io/chat/docs/rn_push_android/?language=java |
| 1326 | + |
| 1327 | +### Requirements |
| 1328 | + |
| 1329 | +- User must be a member of channel, if he expects a push notification for a message on that channel. |
| 1330 | + |
| 1331 | +- We only send a push notification, when user is **NOT** connected to chat, or in other words, if user does **NOT** have any active WS (websocket) connection. WS connection is established when you do |
| 1332 | + |
| 1333 | + `await client.setUser({ id: 'user_id' })`. |
| 1334 | + |
| 1335 | +### Caveats |
| 1336 | + |
| 1337 | +Usually you want to receive push notification, when your app goes to background. When you put your app to background, WS connection stays active for approximately 15-20 seconds, after which system will break the connection automatically. But for those 15-20 seconds, you won't receive any push (since WS is still active). |
| 1338 | + |
| 1339 | +- To handle this case, you will have to manually break the WS connection, when your app goes to background: |
| 1340 | + |
| 1341 | + ```js |
| 1342 | + await client.wsConnection.disconnect(); |
| 1343 | + ``` |
| 1344 | + |
| 1345 | + And when app comes to foreground, re-establish the connection: |
| 1346 | + |
| 1347 | + ```js |
| 1348 | + await client._setupConnection(); |
| 1349 | + ``` |
| 1350 | + |
| 1351 | + You can use [AppState](https://reactnative.dev/docs/appstate) module of react-native to detect weather app is on foreground or background. |
| 1352 | + |
| 1353 | +- If you don't like the idea of manually breaking websocket connection, but still want to receive push notification immediately when app goes to background, please use the following approach: |
| 1354 | + |
| 1355 | + 1. Add a listener for `message.new` (and/or `notification.message_new`) event. |
| 1356 | + |
| 1357 | + 2. When you receive one of these events, check if your app is in foreground or background. If the app is backgrounded, then generate a [local notification](https://github.com/zo0r/react-native-push-notification#local-notifications) |
| 1358 | + |
| 1359 | + |
| 1360 | + ```js |
| 1361 | + const _handleMessageNewEvent = event => { |
| 1362 | + // If the app is on foreground, then do nothing. |
| 1363 | + if (appState === 'active') return; |
| 1364 | + |
| 1365 | + // If app is on background, then generate a local notification. |
| 1366 | + PushNotification.localNotification({ |
| 1367 | + bigText: event.message.text |
| 1368 | + }); |
| 1369 | + } |
| 1370 | + |
| 1371 | + client.on('message.new', _handleMessageNewEvent) |
| 1372 | + client.on('notification.message_new', _handleMessageNewEvent) |
| 1373 | + |
| 1374 | + ``` |
| 1375 | + |
| 1376 | + App example will look something like following: |
| 1377 | + |
| 1378 | + ```js |
| 1379 | + import React, { useEffect, useState } from "react"; |
| 1380 | + import { AppState, StyleSheet, Text, View } from "react-native"; |
| 1381 | + import PushNotifications from 'react-native-push-notification'; |
| 1382 | + |
| 1383 | + const ChatExample = () => { |
| 1384 | + const [appState, setAppState] = useState(AppState.currentState); |
| 1385 | + const [client, setClient] = useState(null); |
| 1386 | + |
| 1387 | + useEffect(() => { |
| 1388 | + const setupClient = async () => { |
| 1389 | + const client = new StreamChat("API_KEY"); |
| 1390 | + await client.setUser({id: 'userId'}, 'token'); |
| 1391 | + |
| 1392 | + client.on('message.new', _handleMessageNewEvent) |
| 1393 | + client.on('notification.message_new', _handleMessageNewEvent) |
| 1394 | + |
| 1395 | + setClient(client); |
| 1396 | + } |
| 1397 | + |
| 1398 | + setupClient(); |
| 1399 | + |
| 1400 | + return () => { |
| 1401 | + client.off('message.new'); |
| 1402 | + client.off('notification.message_new'); |
| 1403 | + } |
| 1404 | + }, []) |
| 1405 | + |
| 1406 | + useEffect(() => { |
| 1407 | + PushNotification.configure({ /** push notification config */ }) |
| 1408 | + AppState.addEventListener("change", _handleAppStateChange); |
| 1409 | + |
| 1410 | + return () => { |
| 1411 | + AppState.removeEventListener("change", _handleAppStateChange); |
| 1412 | + }; |
| 1413 | + }, []); |
| 1414 | + |
| 1415 | + const _handleAppStateChange = nextAppState => { |
| 1416 | + if (appState.match(/inactive|background/) && nextAppState === "active") { |
| 1417 | + console.log("App has come to the foreground!"); |
| 1418 | + } |
| 1419 | + setAppState(nextAppState); |
| 1420 | + }; |
| 1421 | + |
| 1422 | + const _handleMessageNewEvent = event => { |
| 1423 | + // If the app is on foreground, then do nothing. |
| 1424 | + if (appState === 'active') return; |
| 1425 | + |
| 1426 | + // If app is on background, then generate a local notification. |
| 1427 | + PushNotification.localNotification({ |
| 1428 | + bigText: event.message.text |
| 1429 | + }); |
| 1430 | + } |
| 1431 | + |
| 1432 | + if (!client) return null; |
| 1433 | + |
| 1434 | + return ( |
| 1435 | + <View style={styles.container}> |
| 1436 | + <Chat client={client}> |
| 1437 | + {/** All the chat components */} |
| 1438 | + </Chat> |
| 1439 | + </View> |
| 1440 | + ); |
| 1441 | + }; |
| 1442 | + ``` |
0 commit comments