@knocklabs/expo 0.4.2 → 0.4.3
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.
- package/CHANGELOG.md +10 -0
- package/dist/cjs/modules/push/KnockExpoPushNotificationProvider.js +1 -1
- package/dist/cjs/modules/push/KnockExpoPushNotificationProvider.js.map +1 -1
- package/dist/esm/modules/push/KnockExpoPushNotificationProvider.mjs +72 -62
- package/dist/esm/modules/push/KnockExpoPushNotificationProvider.mjs.map +1 -1
- package/dist/types/modules/push/KnockExpoPushNotificationProvider.d.ts +2 -1
- package/dist/types/modules/push/KnockExpoPushNotificationProvider.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/modules/push/KnockExpoPushNotificationProvider.tsx +33 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @knocklabs/expo
|
|
2
2
|
|
|
3
|
+
## 0.4.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e154ed9: Fix Android push notification channel registration issue and add customization options. The `KnockExpoPushNotificationProvider` had a race condition where the push token was not being properly registered with Knock's channel data on Android (and potentially iOS). This was caused by checking the state value immediately after setting it, before React had a chance to update the state. Additionally, added proper Android notification channel setup using `setNotificationChannelAsync`, which is required for Android push notifications to work correctly. Apps can now customize the Android notification channel setup by providing a `setupAndroidNotificationChannel` prop.
|
|
8
|
+
- Updated dependencies [01d07af]
|
|
9
|
+
- @knocklabs/client@0.20.1
|
|
10
|
+
- @knocklabs/react-core@0.12.1
|
|
11
|
+
- @knocklabs/react-native@0.7.3
|
|
12
|
+
|
|
3
13
|
## 0.4.2
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("react/jsx-runtime"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("react/jsx-runtime"),j=require("@knocklabs/react-core"),x=require("@knocklabs/react-native"),_=require("expo-constants"),q=require("expo-device"),A=require("expo-notifications"),i=require("react"),R=t=>t&&typeof t=="object"&&"default"in t?t:{default:t};function v(t){if(t&&typeof t=="object"&&"default"in t)return t;const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const a in t)if(a!=="default"){const u=Object.getOwnPropertyDescriptor(t,a);Object.defineProperty(r,a,u.get?u:{enumerable:!0,get:()=>t[a]})}}return r.default=t,Object.freeze(r)}const d=R(_),m=v(q),s=v(A);s.setNotificationHandler({handleNotification:async()=>({shouldShowAlert:!0,shouldPlaySound:!0,shouldSetBadge:!0,shouldShowBanner:!0,shouldShowList:!0})});const D=async t=>({shouldShowAlert:!0,shouldPlaySound:!0,shouldSetBadge:!0,shouldShowBanner:!0,shouldShowList:!0}),S=i.createContext(void 0);async function F(){const{status:t}=await s.getPermissionsAsync();if(t!=="granted"){const{status:r}=await s.requestPermissionsAsync();return r}return t}async function H(){try{return!d.default.expoConfig||!d.default.expoConfig.extra||!d.default.expoConfig.extra.eas?(console.error("[Knock] Expo Project ID is not defined in the app configuration."),null):await s.getExpoPushTokenAsync({projectId:d.default.expoConfig.extra.eas.projectId})}catch(t){return console.error("[Knock] Error getting Expo push token:",t),null}}async function I(){m.osName==="Android"&&await s.setNotificationChannelAsync("default",{name:"Default",importance:s.AndroidImportance.MAX,vibrationPattern:[0,250,250,250],lightColor:"#FF231F7C"})}async function O(t){return m.isDevice?(await t(),await F()!=="granted"?(console.warn("[Knock] Push notification permission not granted"),null):H()):(console.warn("[Knock] Must use physical device for Push Notifications"),null)}const M=({knockExpoChannelId:t,customNotificationHandler:r,setupAndroidNotificationChannel:a=I,children:u,autoRegister:p=!0})=>{const{registerPushTokenToChannel:g,unregisterPushTokenFromChannel:y}=x.usePushNotifications(),[K,C]=i.useState(null),n=j.useKnockClient(),[k,w]=i.useState(()=>()=>{}),[P,E]=i.useState(()=>()=>{}),b=i.useCallback(e=>{w(()=>e)},[]),T=i.useCallback(e=>{E(()=>e)},[]),l=i.useCallback(async()=>{try{n.log("[Knock] Registering for push notifications");const e=await O(a);return n.log(`[Knock] Token received: ${e==null?void 0:e.data}`),e!=null&&e.data?(n.log(`[Knock] Setting push token: ${e.data}`),C(e.data),e.data):null}catch(e){return console.error("[Knock] Error registering for push notifications:",e),null}},[n,a]),N=i.useCallback(async(e,f)=>{var c;const o=(c=e.request.content.data)==null?void 0:c.knock_message_id;if(!o){n.log("[Knock] Skipping status update for non-Knock notification");return}return n.messages.updateStatus(o,f)},[n]);return i.useEffect(()=>{s.setNotificationHandler({handleNotification:r??D}),p&&l().then(o=>{o&&g(o,t).then(c=>{n.log("[Knock] setChannelData success")}).catch(c=>{console.error("[Knock] Error in setting push token or channel data",c)})}).catch(o=>{console.error("[Knock] Error in setting push token or channel data",o)});const e=s.addNotificationReceivedListener(o=>{n.log("[Knock] Expo Push Notification received in foreground:"),N(o,"interacted"),k(o)}),f=s.addNotificationResponseReceivedListener(o=>{n.log("[Knock] Expo Push Notification was interacted with"),N(o.notification,"interacted"),P(o)});return()=>{e.remove(),f.remove()}},[l,k,P,r,p,t,n]),h.jsx(S.Provider,{value:{expoPushToken:K,registerForPushNotifications:l,registerPushTokenToChannel:g,unregisterPushTokenFromChannel:y,onNotificationReceived:b,onNotificationTapped:T},children:u})},B=t=>h.jsx(x.KnockPushNotificationProvider,{children:h.jsx(M,{...t})}),L=()=>{const t=i.useContext(S);if(t===void 0)throw new Error("[Knock] useExpoPushNotifications must be used within a KnockExpoPushNotificationProvider");return t};exports.KnockExpoPushNotificationProvider=B;exports.useExpoPushNotifications=L;
|
|
2
2
|
//# sourceMappingURL=KnockExpoPushNotificationProvider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KnockExpoPushNotificationProvider.js","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"sourcesContent":["import { Message, MessageEngagementStatus } from \"@knocklabs/client\";\nimport { useKnockClient } from \"@knocklabs/react-core\";\nimport {\n type KnockPushNotificationContextType,\n KnockPushNotificationProvider,\n usePushNotifications,\n} from \"@knocklabs/react-native\";\nimport Constants from \"expo-constants\";\nimport * as Device from \"expo-device\";\nimport * as Notifications from \"expo-notifications\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface KnockExpoPushNotificationContextType\n extends KnockPushNotificationContextType {\n expoPushToken: string | null;\n registerForPushNotifications: () => Promise<void>;\n onNotificationReceived: (\n handler: (notification: Notifications.Notification) => void,\n ) => void;\n onNotificationTapped: (\n handler: (response: Notifications.NotificationResponse) => void,\n ) => void;\n}\n\nNotifications.setNotificationHandler({\n handleNotification: async () => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n shouldShowBanner: true,\n shouldShowList: true,\n };\n },\n});\n\nconst defaultNotificationHandler = async (\n _notification: Notifications.Notification,\n): Promise<Notifications.NotificationBehavior> => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n shouldShowBanner: true,\n shouldShowList: true,\n };\n};\n\nconst KnockExpoPushNotificationContext = createContext<\n KnockExpoPushNotificationContextType | undefined\n>(undefined);\n\nexport interface KnockExpoPushNotificationProviderProps {\n knockExpoChannelId: string;\n customNotificationHandler?: (\n notification: Notifications.Notification,\n ) => Promise<Notifications.NotificationBehavior>;\n children?: React.ReactElement;\n autoRegister?: boolean;\n}\n\nasync function requestPushPermissionIfNeeded(): Promise<string> {\n const { status: existingStatus } = await Notifications.getPermissionsAsync();\n\n if (existingStatus !== \"granted\") {\n const { status } = await Notifications.requestPermissionsAsync();\n return status;\n }\n\n return existingStatus;\n}\n\nasync function getExpoPushToken(): Promise<Notifications.ExpoPushToken | null> {\n try {\n if (\n !Constants.expoConfig ||\n !Constants.expoConfig.extra ||\n !Constants.expoConfig.extra.eas\n ) {\n console.error(\n \"[Knock] Expo Project ID is not defined in the app configuration.\",\n );\n return null;\n }\n const token = await Notifications.getExpoPushTokenAsync({\n projectId: Constants.expoConfig.extra.eas.projectId,\n });\n return token;\n } catch (error) {\n console.error(\"[Knock] Error getting Expo push token:\", error);\n return null;\n }\n}\n\nasync function requestPermissionAndGetPushToken(): Promise<Notifications.ExpoPushToken | null> {\n // Check for device support\n if (!Device.isDevice) {\n console.warn(\"[Knock] Must use physical device for Push Notifications\");\n return null;\n }\n\n const permissionStatus = await requestPushPermissionIfNeeded();\n\n if (permissionStatus !== \"granted\") {\n console.warn(\"[Knock] Push notification permission not granted\");\n return null;\n }\n\n return getExpoPushToken();\n}\n\nconst InternalKnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = ({\n knockExpoChannelId,\n customNotificationHandler,\n children,\n autoRegister = true,\n}) => {\n const { registerPushTokenToChannel, unregisterPushTokenFromChannel } =\n usePushNotifications();\n const [expoPushToken, setExpoPushToken] = useState<string | null>(null);\n const knockClient = useKnockClient();\n\n const [notificationReceivedHandler, setNotificationReceivedHandler] =\n useState<(notification: Notifications.Notification) => void>(\n () => () => {},\n );\n\n const [notificationTappedHandler, setNotificationTappedHandler] = useState<\n (response: Notifications.NotificationResponse) => void\n >(() => () => {});\n\n const handleNotificationReceived = useCallback(\n (handler: (notification: Notifications.Notification) => void) => {\n setNotificationReceivedHandler(() => handler);\n },\n [],\n );\n\n const handleNotificationTapped = useCallback(\n (handler: (response: Notifications.NotificationResponse) => void) => {\n setNotificationTappedHandler(() => handler);\n },\n [],\n );\n\n const registerForPushNotifications = useCallback(async (): Promise<void> => {\n try {\n knockClient.log(`[Knock] Registering for push notifications`);\n const token = await requestPermissionAndGetPushToken();\n knockClient.log(`[Knock] Token received: ${token?.data}`);\n if (token?.data) {\n knockClient.log(`[Knock] Setting push token: ${token.data}`);\n setExpoPushToken(token.data);\n }\n } catch (error) {\n console.error(`[Knock] Error registering for push notifications:`, error);\n }\n }, [knockClient]);\n\n const updateKnockMessageStatusFromNotification = useCallback(\n async (\n notification: Notifications.Notification,\n status: MessageEngagementStatus,\n ): Promise<Message | void> => {\n const messageId = notification.request.content.data?.[\n \"knock_message_id\"\n ] as string | undefined;\n\n // Skip status update if this isn't a Knock notification\n // Fixes issue: https://github.com/knocklabs/javascript/issues/589\n if (!messageId) {\n knockClient.log(\n \"[Knock] Skipping status update for non-Knock notification\",\n );\n return;\n }\n\n return knockClient.messages.updateStatus(messageId, status);\n },\n [knockClient],\n );\n\n useEffect(() => {\n Notifications.setNotificationHandler({\n handleNotification:\n customNotificationHandler ?? defaultNotificationHandler,\n });\n\n if (autoRegister) {\n registerForPushNotifications()\n .then(() => {\n if (expoPushToken) {\n registerPushTokenToChannel(expoPushToken, knockExpoChannelId)\n .then((_result) => {\n knockClient.log(\"[Knock] setChannelData success\");\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n\n const notificationReceivedSubscription =\n Notifications.addNotificationReceivedListener((notification) => {\n knockClient.log(\n \"[Knock] Expo Push Notification received in foreground:\",\n );\n updateKnockMessageStatusFromNotification(notification, \"interacted\");\n notificationReceivedHandler(notification);\n });\n\n const notificationResponseSubscription =\n Notifications.addNotificationResponseReceivedListener((response) => {\n knockClient.log(\"[Knock] Expo Push Notification was interacted with\");\n updateKnockMessageStatusFromNotification(\n response.notification,\n \"interacted\",\n );\n notificationTappedHandler(response);\n });\n\n return () => {\n notificationReceivedSubscription.remove();\n notificationResponseSubscription.remove();\n };\n\n // TODO: Remove when possible and ensure dependency array is correct\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n registerForPushNotifications,\n notificationReceivedHandler,\n notificationTappedHandler,\n customNotificationHandler,\n autoRegister,\n expoPushToken,\n knockExpoChannelId,\n knockClient,\n ]);\n\n return (\n <KnockExpoPushNotificationContext.Provider\n value={{\n expoPushToken,\n registerForPushNotifications,\n registerPushTokenToChannel,\n unregisterPushTokenFromChannel,\n onNotificationReceived: handleNotificationReceived,\n onNotificationTapped: handleNotificationTapped,\n }}\n >\n {children}\n </KnockExpoPushNotificationContext.Provider>\n );\n};\n\nexport const KnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = (props) => {\n return (\n <KnockPushNotificationProvider>\n <InternalKnockExpoPushNotificationProvider {...props} />\n </KnockPushNotificationProvider>\n );\n};\n\nexport const useExpoPushNotifications =\n (): KnockExpoPushNotificationContextType => {\n const context = useContext(KnockExpoPushNotificationContext);\n if (context === undefined) {\n throw new Error(\n \"[Knock] useExpoPushNotifications must be used within a KnockExpoPushNotificationProvider\",\n );\n }\n return context;\n };\n"],"names":["Notifications","defaultNotificationHandler","_notification","KnockExpoPushNotificationContext","createContext","requestPushPermissionIfNeeded","existingStatus","status","getExpoPushToken","Constants","error","requestPermissionAndGetPushToken","Device","InternalKnockExpoPushNotificationProvider","knockExpoChannelId","customNotificationHandler","children","autoRegister","registerPushTokenToChannel","unregisterPushTokenFromChannel","usePushNotifications","expoPushToken","setExpoPushToken","useState","knockClient","useKnockClient","notificationReceivedHandler","setNotificationReceivedHandler","notificationTappedHandler","setNotificationTappedHandler","handleNotificationReceived","useCallback","handler","handleNotificationTapped","registerForPushNotifications","token","updateKnockMessageStatusFromNotification","notification","messageId","_a","useEffect","_result","_error","notificationReceivedSubscription","notificationResponseSubscription","response","jsx","KnockExpoPushNotificationProvider","props","KnockPushNotificationProvider","useExpoPushNotifications","context","useContext"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"KnockExpoPushNotificationProvider.js","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"sourcesContent":["import { Message, MessageEngagementStatus } from \"@knocklabs/client\";\nimport { useKnockClient } from \"@knocklabs/react-core\";\nimport {\n type KnockPushNotificationContextType,\n KnockPushNotificationProvider,\n usePushNotifications,\n} from \"@knocklabs/react-native\";\nimport Constants from \"expo-constants\";\nimport * as Device from \"expo-device\";\nimport * as Notifications from \"expo-notifications\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface KnockExpoPushNotificationContextType\n extends KnockPushNotificationContextType {\n expoPushToken: string | null;\n registerForPushNotifications: () => Promise<string | null>;\n onNotificationReceived: (\n handler: (notification: Notifications.Notification) => void,\n ) => void;\n onNotificationTapped: (\n handler: (response: Notifications.NotificationResponse) => void,\n ) => void;\n}\n\nNotifications.setNotificationHandler({\n handleNotification: async () => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n shouldShowBanner: true,\n shouldShowList: true,\n };\n },\n});\n\nconst defaultNotificationHandler = async (\n _notification: Notifications.Notification,\n): Promise<Notifications.NotificationBehavior> => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n shouldShowBanner: true,\n shouldShowList: true,\n };\n};\n\nconst KnockExpoPushNotificationContext = createContext<\n KnockExpoPushNotificationContextType | undefined\n>(undefined);\n\nexport interface KnockExpoPushNotificationProviderProps {\n knockExpoChannelId: string;\n customNotificationHandler?: (\n notification: Notifications.Notification,\n ) => Promise<Notifications.NotificationBehavior>;\n setupAndroidNotificationChannel?: () => Promise<void>;\n children?: React.ReactElement;\n autoRegister?: boolean;\n}\n\nasync function requestPushPermissionIfNeeded(): Promise<string> {\n const { status: existingStatus } = await Notifications.getPermissionsAsync();\n\n if (existingStatus !== \"granted\") {\n const { status } = await Notifications.requestPermissionsAsync();\n return status;\n }\n\n return existingStatus;\n}\n\nasync function getExpoPushToken(): Promise<Notifications.ExpoPushToken | null> {\n try {\n if (\n !Constants.expoConfig ||\n !Constants.expoConfig.extra ||\n !Constants.expoConfig.extra.eas\n ) {\n console.error(\n \"[Knock] Expo Project ID is not defined in the app configuration.\",\n );\n return null;\n }\n const token = await Notifications.getExpoPushTokenAsync({\n projectId: Constants.expoConfig.extra.eas.projectId,\n });\n return token;\n } catch (error) {\n console.error(\"[Knock] Error getting Expo push token:\", error);\n return null;\n }\n}\n\nasync function defaultSetupAndroidNotificationChannel(): Promise<void> {\n if (Device.osName === \"Android\") {\n await Notifications.setNotificationChannelAsync(\"default\", {\n name: \"Default\",\n importance: Notifications.AndroidImportance.MAX,\n vibrationPattern: [0, 250, 250, 250],\n lightColor: \"#FF231F7C\",\n });\n }\n}\n\nasync function requestPermissionAndGetPushToken(\n setupAndroidChannel: () => Promise<void>,\n): Promise<Notifications.ExpoPushToken | null> {\n // Check for device support\n if (!Device.isDevice) {\n console.warn(\"[Knock] Must use physical device for Push Notifications\");\n return null;\n }\n\n // Setup Android notification channel before requesting permissions\n await setupAndroidChannel();\n\n const permissionStatus = await requestPushPermissionIfNeeded();\n\n if (permissionStatus !== \"granted\") {\n console.warn(\"[Knock] Push notification permission not granted\");\n return null;\n }\n\n return getExpoPushToken();\n}\n\nconst InternalKnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = ({\n knockExpoChannelId,\n customNotificationHandler,\n setupAndroidNotificationChannel = defaultSetupAndroidNotificationChannel,\n children,\n autoRegister = true,\n}) => {\n const { registerPushTokenToChannel, unregisterPushTokenFromChannel } =\n usePushNotifications();\n const [expoPushToken, setExpoPushToken] = useState<string | null>(null);\n const knockClient = useKnockClient();\n\n const [notificationReceivedHandler, setNotificationReceivedHandler] =\n useState<(notification: Notifications.Notification) => void>(\n () => () => {},\n );\n\n const [notificationTappedHandler, setNotificationTappedHandler] = useState<\n (response: Notifications.NotificationResponse) => void\n >(() => () => {});\n\n const handleNotificationReceived = useCallback(\n (handler: (notification: Notifications.Notification) => void) => {\n setNotificationReceivedHandler(() => handler);\n },\n [],\n );\n\n const handleNotificationTapped = useCallback(\n (handler: (response: Notifications.NotificationResponse) => void) => {\n setNotificationTappedHandler(() => handler);\n },\n [],\n );\n\n const registerForPushNotifications = useCallback(async (): Promise<\n string | null\n > => {\n try {\n knockClient.log(`[Knock] Registering for push notifications`);\n const token = await requestPermissionAndGetPushToken(\n setupAndroidNotificationChannel,\n );\n knockClient.log(`[Knock] Token received: ${token?.data}`);\n if (token?.data) {\n knockClient.log(`[Knock] Setting push token: ${token.data}`);\n setExpoPushToken(token.data);\n return token.data;\n }\n return null;\n } catch (error) {\n console.error(`[Knock] Error registering for push notifications:`, error);\n return null;\n }\n }, [knockClient, setupAndroidNotificationChannel]);\n\n const updateKnockMessageStatusFromNotification = useCallback(\n async (\n notification: Notifications.Notification,\n status: MessageEngagementStatus,\n ): Promise<Message | void> => {\n const messageId = notification.request.content.data?.[\n \"knock_message_id\"\n ] as string | undefined;\n\n // Skip status update if this isn't a Knock notification\n // Fixes issue: https://github.com/knocklabs/javascript/issues/589\n if (!messageId) {\n knockClient.log(\n \"[Knock] Skipping status update for non-Knock notification\",\n );\n return;\n }\n\n return knockClient.messages.updateStatus(messageId, status);\n },\n [knockClient],\n );\n\n useEffect(() => {\n Notifications.setNotificationHandler({\n handleNotification:\n customNotificationHandler ?? defaultNotificationHandler,\n });\n\n if (autoRegister) {\n registerForPushNotifications()\n .then((token) => {\n if (token) {\n registerPushTokenToChannel(token, knockExpoChannelId)\n .then((_result) => {\n knockClient.log(\"[Knock] setChannelData success\");\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n\n const notificationReceivedSubscription =\n Notifications.addNotificationReceivedListener((notification) => {\n knockClient.log(\n \"[Knock] Expo Push Notification received in foreground:\",\n );\n updateKnockMessageStatusFromNotification(notification, \"interacted\");\n notificationReceivedHandler(notification);\n });\n\n const notificationResponseSubscription =\n Notifications.addNotificationResponseReceivedListener((response) => {\n knockClient.log(\"[Knock] Expo Push Notification was interacted with\");\n updateKnockMessageStatusFromNotification(\n response.notification,\n \"interacted\",\n );\n notificationTappedHandler(response);\n });\n\n return () => {\n notificationReceivedSubscription.remove();\n notificationResponseSubscription.remove();\n };\n\n // TODO: Remove when possible and ensure dependency array is correct\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n registerForPushNotifications,\n notificationReceivedHandler,\n notificationTappedHandler,\n customNotificationHandler,\n autoRegister,\n knockExpoChannelId,\n knockClient,\n ]);\n\n return (\n <KnockExpoPushNotificationContext.Provider\n value={{\n expoPushToken,\n registerForPushNotifications,\n registerPushTokenToChannel,\n unregisterPushTokenFromChannel,\n onNotificationReceived: handleNotificationReceived,\n onNotificationTapped: handleNotificationTapped,\n }}\n >\n {children}\n </KnockExpoPushNotificationContext.Provider>\n );\n};\n\nexport const KnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = (props) => {\n return (\n <KnockPushNotificationProvider>\n <InternalKnockExpoPushNotificationProvider {...props} />\n </KnockPushNotificationProvider>\n );\n};\n\nexport const useExpoPushNotifications =\n (): KnockExpoPushNotificationContextType => {\n const context = useContext(KnockExpoPushNotificationContext);\n if (context === undefined) {\n throw new Error(\n \"[Knock] useExpoPushNotifications must be used within a KnockExpoPushNotificationProvider\",\n );\n }\n return context;\n };\n"],"names":["Notifications","defaultNotificationHandler","_notification","KnockExpoPushNotificationContext","createContext","requestPushPermissionIfNeeded","existingStatus","status","getExpoPushToken","Constants","error","defaultSetupAndroidNotificationChannel","Device","requestPermissionAndGetPushToken","setupAndroidChannel","InternalKnockExpoPushNotificationProvider","knockExpoChannelId","customNotificationHandler","setupAndroidNotificationChannel","children","autoRegister","registerPushTokenToChannel","unregisterPushTokenFromChannel","usePushNotifications","expoPushToken","setExpoPushToken","useState","knockClient","useKnockClient","notificationReceivedHandler","setNotificationReceivedHandler","notificationTappedHandler","setNotificationTappedHandler","handleNotificationReceived","useCallback","handler","handleNotificationTapped","registerForPushNotifications","token","updateKnockMessageStatusFromNotification","notification","messageId","_a","useEffect","_result","_error","notificationReceivedSubscription","notificationResponseSubscription","response","jsx","KnockExpoPushNotificationProvider","props","KnockPushNotificationProvider","useExpoPushNotifications","context","useContext"],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { useKnockClient as
|
|
3
|
-
import { KnockPushNotificationProvider as
|
|
4
|
-
import
|
|
5
|
-
import * as
|
|
1
|
+
import { jsx as l } from "react/jsx-runtime";
|
|
2
|
+
import { useKnockClient as A } from "@knocklabs/react-core";
|
|
3
|
+
import { KnockPushNotificationProvider as R, usePushNotifications as F } from "@knocklabs/react-native";
|
|
4
|
+
import a from "expo-constants";
|
|
5
|
+
import * as N from "expo-device";
|
|
6
6
|
import * as i from "expo-notifications";
|
|
7
|
-
import { createContext as H, useContext as I, useState as f, useCallback as
|
|
7
|
+
import { createContext as H, useContext as I, useState as f, useCallback as c, useEffect as b } from "react";
|
|
8
8
|
i.setNotificationHandler({
|
|
9
9
|
handleNotification: async () => ({
|
|
10
10
|
shouldShowAlert: !0,
|
|
@@ -14,14 +14,14 @@ i.setNotificationHandler({
|
|
|
14
14
|
shouldShowList: !0
|
|
15
15
|
})
|
|
16
16
|
});
|
|
17
|
-
const
|
|
17
|
+
const D = async (t) => ({
|
|
18
18
|
shouldShowAlert: !0,
|
|
19
19
|
shouldPlaySound: !0,
|
|
20
20
|
shouldSetBadge: !0,
|
|
21
21
|
shouldShowBanner: !0,
|
|
22
22
|
shouldShowList: !0
|
|
23
23
|
}), x = H(void 0);
|
|
24
|
-
async function
|
|
24
|
+
async function j() {
|
|
25
25
|
const { status: t } = await i.getPermissionsAsync();
|
|
26
26
|
if (t !== "granted") {
|
|
27
27
|
const { status: r } = await i.requestPermissionsAsync();
|
|
@@ -29,117 +29,127 @@ async function q() {
|
|
|
29
29
|
}
|
|
30
30
|
return t;
|
|
31
31
|
}
|
|
32
|
-
async function
|
|
32
|
+
async function q() {
|
|
33
33
|
try {
|
|
34
|
-
return !
|
|
34
|
+
return !a.expoConfig || !a.expoConfig.extra || !a.expoConfig.extra.eas ? (console.error(
|
|
35
35
|
"[Knock] Expo Project ID is not defined in the app configuration."
|
|
36
36
|
), null) : await i.getExpoPushTokenAsync({
|
|
37
|
-
projectId:
|
|
37
|
+
projectId: a.expoConfig.extra.eas.projectId
|
|
38
38
|
});
|
|
39
39
|
} catch (t) {
|
|
40
40
|
return console.error("[Knock] Error getting Expo push token:", t), null;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
async function
|
|
44
|
-
|
|
43
|
+
async function B() {
|
|
44
|
+
N.osName === "Android" && await i.setNotificationChannelAsync("default", {
|
|
45
|
+
name: "Default",
|
|
46
|
+
importance: i.AndroidImportance.MAX,
|
|
47
|
+
vibrationPattern: [0, 250, 250, 250],
|
|
48
|
+
lightColor: "#FF231F7C"
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async function L(t) {
|
|
52
|
+
return N.isDevice ? (await t(), await j() !== "granted" ? (console.warn("[Knock] Push notification permission not granted"), null) : q()) : (console.warn("[Knock] Must use physical device for Push Notifications"), null);
|
|
45
53
|
}
|
|
46
|
-
const
|
|
54
|
+
const _ = ({
|
|
47
55
|
knockExpoChannelId: t,
|
|
48
56
|
customNotificationHandler: r,
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
setupAndroidNotificationChannel: h = B,
|
|
58
|
+
children: v,
|
|
59
|
+
autoRegister: p = !0
|
|
51
60
|
}) => {
|
|
52
|
-
const { registerPushTokenToChannel:
|
|
61
|
+
const { registerPushTokenToChannel: g, unregisterPushTokenFromChannel: K } = F(), [S, w] = f(null), e = A(), [k, E] = f(
|
|
53
62
|
() => () => {
|
|
54
63
|
}
|
|
55
|
-
), [
|
|
56
|
-
}),
|
|
64
|
+
), [P, y] = f(() => () => {
|
|
65
|
+
}), C = c(
|
|
57
66
|
(o) => {
|
|
58
|
-
|
|
67
|
+
E(() => o);
|
|
59
68
|
},
|
|
60
69
|
[]
|
|
61
|
-
),
|
|
70
|
+
), T = c(
|
|
62
71
|
(o) => {
|
|
63
|
-
|
|
72
|
+
y(() => o);
|
|
64
73
|
},
|
|
65
74
|
[]
|
|
66
|
-
), u =
|
|
75
|
+
), u = c(async () => {
|
|
67
76
|
try {
|
|
68
|
-
|
|
69
|
-
const o = await
|
|
70
|
-
|
|
77
|
+
e.log("[Knock] Registering for push notifications");
|
|
78
|
+
const o = await L(
|
|
79
|
+
h
|
|
80
|
+
);
|
|
81
|
+
return e.log(`[Knock] Token received: ${o == null ? void 0 : o.data}`), o != null && o.data ? (e.log(`[Knock] Setting push token: ${o.data}`), w(o.data), o.data) : null;
|
|
71
82
|
} catch (o) {
|
|
72
|
-
console.error("[Knock] Error registering for push notifications:", o);
|
|
83
|
+
return console.error("[Knock] Error registering for push notifications:", o), null;
|
|
73
84
|
}
|
|
74
|
-
}, [
|
|
85
|
+
}, [e, h]), m = c(
|
|
75
86
|
async (o, d) => {
|
|
76
|
-
var
|
|
77
|
-
const
|
|
78
|
-
if (!
|
|
79
|
-
|
|
87
|
+
var s;
|
|
88
|
+
const n = (s = o.request.content.data) == null ? void 0 : s.knock_message_id;
|
|
89
|
+
if (!n) {
|
|
90
|
+
e.log(
|
|
80
91
|
"[Knock] Skipping status update for non-Knock notification"
|
|
81
92
|
);
|
|
82
93
|
return;
|
|
83
94
|
}
|
|
84
|
-
return
|
|
95
|
+
return e.messages.updateStatus(n, d);
|
|
85
96
|
},
|
|
86
|
-
[
|
|
97
|
+
[e]
|
|
87
98
|
);
|
|
88
99
|
return b(() => {
|
|
89
100
|
i.setNotificationHandler({
|
|
90
|
-
handleNotification: r ??
|
|
91
|
-
}),
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}).catch((
|
|
101
|
+
handleNotification: r ?? D
|
|
102
|
+
}), p && u().then((n) => {
|
|
103
|
+
n && g(n, t).then((s) => {
|
|
104
|
+
e.log("[Knock] setChannelData success");
|
|
105
|
+
}).catch((s) => {
|
|
95
106
|
console.error(
|
|
96
107
|
"[Knock] Error in setting push token or channel data",
|
|
97
|
-
|
|
108
|
+
s
|
|
98
109
|
);
|
|
99
110
|
});
|
|
100
|
-
}).catch((
|
|
111
|
+
}).catch((n) => {
|
|
101
112
|
console.error(
|
|
102
113
|
"[Knock] Error in setting push token or channel data",
|
|
103
|
-
|
|
114
|
+
n
|
|
104
115
|
);
|
|
105
116
|
});
|
|
106
|
-
const o = i.addNotificationReceivedListener((
|
|
107
|
-
|
|
117
|
+
const o = i.addNotificationReceivedListener((n) => {
|
|
118
|
+
e.log(
|
|
108
119
|
"[Knock] Expo Push Notification received in foreground:"
|
|
109
|
-
),
|
|
110
|
-
}), d = i.addNotificationResponseReceivedListener((
|
|
111
|
-
|
|
112
|
-
|
|
120
|
+
), m(n, "interacted"), k(n);
|
|
121
|
+
}), d = i.addNotificationResponseReceivedListener((n) => {
|
|
122
|
+
e.log("[Knock] Expo Push Notification was interacted with"), m(
|
|
123
|
+
n.notification,
|
|
113
124
|
"interacted"
|
|
114
|
-
),
|
|
125
|
+
), P(n);
|
|
115
126
|
});
|
|
116
127
|
return () => {
|
|
117
128
|
o.remove(), d.remove();
|
|
118
129
|
};
|
|
119
130
|
}, [
|
|
120
131
|
u,
|
|
121
|
-
g,
|
|
122
132
|
k,
|
|
133
|
+
P,
|
|
123
134
|
r,
|
|
124
|
-
|
|
125
|
-
s,
|
|
135
|
+
p,
|
|
126
136
|
t,
|
|
127
|
-
|
|
128
|
-
]), /* @__PURE__ */
|
|
137
|
+
e
|
|
138
|
+
]), /* @__PURE__ */ l(
|
|
129
139
|
x.Provider,
|
|
130
140
|
{
|
|
131
141
|
value: {
|
|
132
|
-
expoPushToken:
|
|
142
|
+
expoPushToken: S,
|
|
133
143
|
registerForPushNotifications: u,
|
|
134
|
-
registerPushTokenToChannel:
|
|
144
|
+
registerPushTokenToChannel: g,
|
|
135
145
|
unregisterPushTokenFromChannel: K,
|
|
136
|
-
onNotificationReceived:
|
|
137
|
-
onNotificationTapped:
|
|
146
|
+
onNotificationReceived: C,
|
|
147
|
+
onNotificationTapped: T
|
|
138
148
|
},
|
|
139
|
-
children:
|
|
149
|
+
children: v
|
|
140
150
|
}
|
|
141
151
|
);
|
|
142
|
-
},
|
|
152
|
+
}, J = (t) => /* @__PURE__ */ l(R, { children: /* @__PURE__ */ l(_, { ...t }) }), O = () => {
|
|
143
153
|
const t = I(x);
|
|
144
154
|
if (t === void 0)
|
|
145
155
|
throw new Error(
|
|
@@ -148,7 +158,7 @@ const L = ({
|
|
|
148
158
|
return t;
|
|
149
159
|
};
|
|
150
160
|
export {
|
|
151
|
-
|
|
152
|
-
|
|
161
|
+
J as KnockExpoPushNotificationProvider,
|
|
162
|
+
O as useExpoPushNotifications
|
|
153
163
|
};
|
|
154
164
|
//# sourceMappingURL=KnockExpoPushNotificationProvider.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KnockExpoPushNotificationProvider.mjs","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"sourcesContent":["import { Message, MessageEngagementStatus } from \"@knocklabs/client\";\nimport { useKnockClient } from \"@knocklabs/react-core\";\nimport {\n type KnockPushNotificationContextType,\n KnockPushNotificationProvider,\n usePushNotifications,\n} from \"@knocklabs/react-native\";\nimport Constants from \"expo-constants\";\nimport * as Device from \"expo-device\";\nimport * as Notifications from \"expo-notifications\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface KnockExpoPushNotificationContextType\n extends KnockPushNotificationContextType {\n expoPushToken: string | null;\n registerForPushNotifications: () => Promise<void>;\n onNotificationReceived: (\n handler: (notification: Notifications.Notification) => void,\n ) => void;\n onNotificationTapped: (\n handler: (response: Notifications.NotificationResponse) => void,\n ) => void;\n}\n\nNotifications.setNotificationHandler({\n handleNotification: async () => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n shouldShowBanner: true,\n shouldShowList: true,\n };\n },\n});\n\nconst defaultNotificationHandler = async (\n _notification: Notifications.Notification,\n): Promise<Notifications.NotificationBehavior> => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n shouldShowBanner: true,\n shouldShowList: true,\n };\n};\n\nconst KnockExpoPushNotificationContext = createContext<\n KnockExpoPushNotificationContextType | undefined\n>(undefined);\n\nexport interface KnockExpoPushNotificationProviderProps {\n knockExpoChannelId: string;\n customNotificationHandler?: (\n notification: Notifications.Notification,\n ) => Promise<Notifications.NotificationBehavior>;\n children?: React.ReactElement;\n autoRegister?: boolean;\n}\n\nasync function requestPushPermissionIfNeeded(): Promise<string> {\n const { status: existingStatus } = await Notifications.getPermissionsAsync();\n\n if (existingStatus !== \"granted\") {\n const { status } = await Notifications.requestPermissionsAsync();\n return status;\n }\n\n return existingStatus;\n}\n\nasync function getExpoPushToken(): Promise<Notifications.ExpoPushToken | null> {\n try {\n if (\n !Constants.expoConfig ||\n !Constants.expoConfig.extra ||\n !Constants.expoConfig.extra.eas\n ) {\n console.error(\n \"[Knock] Expo Project ID is not defined in the app configuration.\",\n );\n return null;\n }\n const token = await Notifications.getExpoPushTokenAsync({\n projectId: Constants.expoConfig.extra.eas.projectId,\n });\n return token;\n } catch (error) {\n console.error(\"[Knock] Error getting Expo push token:\", error);\n return null;\n }\n}\n\nasync function requestPermissionAndGetPushToken(): Promise<Notifications.ExpoPushToken | null> {\n // Check for device support\n if (!Device.isDevice) {\n console.warn(\"[Knock] Must use physical device for Push Notifications\");\n return null;\n }\n\n const permissionStatus = await requestPushPermissionIfNeeded();\n\n if (permissionStatus !== \"granted\") {\n console.warn(\"[Knock] Push notification permission not granted\");\n return null;\n }\n\n return getExpoPushToken();\n}\n\nconst InternalKnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = ({\n knockExpoChannelId,\n customNotificationHandler,\n children,\n autoRegister = true,\n}) => {\n const { registerPushTokenToChannel, unregisterPushTokenFromChannel } =\n usePushNotifications();\n const [expoPushToken, setExpoPushToken] = useState<string | null>(null);\n const knockClient = useKnockClient();\n\n const [notificationReceivedHandler, setNotificationReceivedHandler] =\n useState<(notification: Notifications.Notification) => void>(\n () => () => {},\n );\n\n const [notificationTappedHandler, setNotificationTappedHandler] = useState<\n (response: Notifications.NotificationResponse) => void\n >(() => () => {});\n\n const handleNotificationReceived = useCallback(\n (handler: (notification: Notifications.Notification) => void) => {\n setNotificationReceivedHandler(() => handler);\n },\n [],\n );\n\n const handleNotificationTapped = useCallback(\n (handler: (response: Notifications.NotificationResponse) => void) => {\n setNotificationTappedHandler(() => handler);\n },\n [],\n );\n\n const registerForPushNotifications = useCallback(async (): Promise<void> => {\n try {\n knockClient.log(`[Knock] Registering for push notifications`);\n const token = await requestPermissionAndGetPushToken();\n knockClient.log(`[Knock] Token received: ${token?.data}`);\n if (token?.data) {\n knockClient.log(`[Knock] Setting push token: ${token.data}`);\n setExpoPushToken(token.data);\n }\n } catch (error) {\n console.error(`[Knock] Error registering for push notifications:`, error);\n }\n }, [knockClient]);\n\n const updateKnockMessageStatusFromNotification = useCallback(\n async (\n notification: Notifications.Notification,\n status: MessageEngagementStatus,\n ): Promise<Message | void> => {\n const messageId = notification.request.content.data?.[\n \"knock_message_id\"\n ] as string | undefined;\n\n // Skip status update if this isn't a Knock notification\n // Fixes issue: https://github.com/knocklabs/javascript/issues/589\n if (!messageId) {\n knockClient.log(\n \"[Knock] Skipping status update for non-Knock notification\",\n );\n return;\n }\n\n return knockClient.messages.updateStatus(messageId, status);\n },\n [knockClient],\n );\n\n useEffect(() => {\n Notifications.setNotificationHandler({\n handleNotification:\n customNotificationHandler ?? defaultNotificationHandler,\n });\n\n if (autoRegister) {\n registerForPushNotifications()\n .then(() => {\n if (expoPushToken) {\n registerPushTokenToChannel(expoPushToken, knockExpoChannelId)\n .then((_result) => {\n knockClient.log(\"[Knock] setChannelData success\");\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n\n const notificationReceivedSubscription =\n Notifications.addNotificationReceivedListener((notification) => {\n knockClient.log(\n \"[Knock] Expo Push Notification received in foreground:\",\n );\n updateKnockMessageStatusFromNotification(notification, \"interacted\");\n notificationReceivedHandler(notification);\n });\n\n const notificationResponseSubscription =\n Notifications.addNotificationResponseReceivedListener((response) => {\n knockClient.log(\"[Knock] Expo Push Notification was interacted with\");\n updateKnockMessageStatusFromNotification(\n response.notification,\n \"interacted\",\n );\n notificationTappedHandler(response);\n });\n\n return () => {\n notificationReceivedSubscription.remove();\n notificationResponseSubscription.remove();\n };\n\n // TODO: Remove when possible and ensure dependency array is correct\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n registerForPushNotifications,\n notificationReceivedHandler,\n notificationTappedHandler,\n customNotificationHandler,\n autoRegister,\n expoPushToken,\n knockExpoChannelId,\n knockClient,\n ]);\n\n return (\n <KnockExpoPushNotificationContext.Provider\n value={{\n expoPushToken,\n registerForPushNotifications,\n registerPushTokenToChannel,\n unregisterPushTokenFromChannel,\n onNotificationReceived: handleNotificationReceived,\n onNotificationTapped: handleNotificationTapped,\n }}\n >\n {children}\n </KnockExpoPushNotificationContext.Provider>\n );\n};\n\nexport const KnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = (props) => {\n return (\n <KnockPushNotificationProvider>\n <InternalKnockExpoPushNotificationProvider {...props} />\n </KnockPushNotificationProvider>\n );\n};\n\nexport const useExpoPushNotifications =\n (): KnockExpoPushNotificationContextType => {\n const context = useContext(KnockExpoPushNotificationContext);\n if (context === undefined) {\n throw new Error(\n \"[Knock] useExpoPushNotifications must be used within a KnockExpoPushNotificationProvider\",\n );\n }\n return context;\n };\n"],"names":["Notifications","defaultNotificationHandler","_notification","KnockExpoPushNotificationContext","createContext","requestPushPermissionIfNeeded","existingStatus","status","getExpoPushToken","Constants","error","requestPermissionAndGetPushToken","Device","InternalKnockExpoPushNotificationProvider","knockExpoChannelId","customNotificationHandler","children","autoRegister","registerPushTokenToChannel","unregisterPushTokenFromChannel","usePushNotifications","expoPushToken","setExpoPushToken","useState","knockClient","useKnockClient","notificationReceivedHandler","setNotificationReceivedHandler","notificationTappedHandler","setNotificationTappedHandler","handleNotificationReceived","useCallback","handler","handleNotificationTapped","registerForPushNotifications","token","updateKnockMessageStatusFromNotification","notification","messageId","_a","useEffect","_result","_error","notificationReceivedSubscription","notificationResponseSubscription","response","jsx","KnockExpoPushNotificationProvider","props","KnockPushNotificationProvider","useExpoPushNotifications","context","useContext"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"KnockExpoPushNotificationProvider.mjs","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"sourcesContent":["import { Message, MessageEngagementStatus } from \"@knocklabs/client\";\nimport { useKnockClient } from \"@knocklabs/react-core\";\nimport {\n type KnockPushNotificationContextType,\n KnockPushNotificationProvider,\n usePushNotifications,\n} from \"@knocklabs/react-native\";\nimport Constants from \"expo-constants\";\nimport * as Device from \"expo-device\";\nimport * as Notifications from \"expo-notifications\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface KnockExpoPushNotificationContextType\n extends KnockPushNotificationContextType {\n expoPushToken: string | null;\n registerForPushNotifications: () => Promise<string | null>;\n onNotificationReceived: (\n handler: (notification: Notifications.Notification) => void,\n ) => void;\n onNotificationTapped: (\n handler: (response: Notifications.NotificationResponse) => void,\n ) => void;\n}\n\nNotifications.setNotificationHandler({\n handleNotification: async () => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n shouldShowBanner: true,\n shouldShowList: true,\n };\n },\n});\n\nconst defaultNotificationHandler = async (\n _notification: Notifications.Notification,\n): Promise<Notifications.NotificationBehavior> => {\n return {\n shouldShowAlert: true,\n shouldPlaySound: true,\n shouldSetBadge: true,\n shouldShowBanner: true,\n shouldShowList: true,\n };\n};\n\nconst KnockExpoPushNotificationContext = createContext<\n KnockExpoPushNotificationContextType | undefined\n>(undefined);\n\nexport interface KnockExpoPushNotificationProviderProps {\n knockExpoChannelId: string;\n customNotificationHandler?: (\n notification: Notifications.Notification,\n ) => Promise<Notifications.NotificationBehavior>;\n setupAndroidNotificationChannel?: () => Promise<void>;\n children?: React.ReactElement;\n autoRegister?: boolean;\n}\n\nasync function requestPushPermissionIfNeeded(): Promise<string> {\n const { status: existingStatus } = await Notifications.getPermissionsAsync();\n\n if (existingStatus !== \"granted\") {\n const { status } = await Notifications.requestPermissionsAsync();\n return status;\n }\n\n return existingStatus;\n}\n\nasync function getExpoPushToken(): Promise<Notifications.ExpoPushToken | null> {\n try {\n if (\n !Constants.expoConfig ||\n !Constants.expoConfig.extra ||\n !Constants.expoConfig.extra.eas\n ) {\n console.error(\n \"[Knock] Expo Project ID is not defined in the app configuration.\",\n );\n return null;\n }\n const token = await Notifications.getExpoPushTokenAsync({\n projectId: Constants.expoConfig.extra.eas.projectId,\n });\n return token;\n } catch (error) {\n console.error(\"[Knock] Error getting Expo push token:\", error);\n return null;\n }\n}\n\nasync function defaultSetupAndroidNotificationChannel(): Promise<void> {\n if (Device.osName === \"Android\") {\n await Notifications.setNotificationChannelAsync(\"default\", {\n name: \"Default\",\n importance: Notifications.AndroidImportance.MAX,\n vibrationPattern: [0, 250, 250, 250],\n lightColor: \"#FF231F7C\",\n });\n }\n}\n\nasync function requestPermissionAndGetPushToken(\n setupAndroidChannel: () => Promise<void>,\n): Promise<Notifications.ExpoPushToken | null> {\n // Check for device support\n if (!Device.isDevice) {\n console.warn(\"[Knock] Must use physical device for Push Notifications\");\n return null;\n }\n\n // Setup Android notification channel before requesting permissions\n await setupAndroidChannel();\n\n const permissionStatus = await requestPushPermissionIfNeeded();\n\n if (permissionStatus !== \"granted\") {\n console.warn(\"[Knock] Push notification permission not granted\");\n return null;\n }\n\n return getExpoPushToken();\n}\n\nconst InternalKnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = ({\n knockExpoChannelId,\n customNotificationHandler,\n setupAndroidNotificationChannel = defaultSetupAndroidNotificationChannel,\n children,\n autoRegister = true,\n}) => {\n const { registerPushTokenToChannel, unregisterPushTokenFromChannel } =\n usePushNotifications();\n const [expoPushToken, setExpoPushToken] = useState<string | null>(null);\n const knockClient = useKnockClient();\n\n const [notificationReceivedHandler, setNotificationReceivedHandler] =\n useState<(notification: Notifications.Notification) => void>(\n () => () => {},\n );\n\n const [notificationTappedHandler, setNotificationTappedHandler] = useState<\n (response: Notifications.NotificationResponse) => void\n >(() => () => {});\n\n const handleNotificationReceived = useCallback(\n (handler: (notification: Notifications.Notification) => void) => {\n setNotificationReceivedHandler(() => handler);\n },\n [],\n );\n\n const handleNotificationTapped = useCallback(\n (handler: (response: Notifications.NotificationResponse) => void) => {\n setNotificationTappedHandler(() => handler);\n },\n [],\n );\n\n const registerForPushNotifications = useCallback(async (): Promise<\n string | null\n > => {\n try {\n knockClient.log(`[Knock] Registering for push notifications`);\n const token = await requestPermissionAndGetPushToken(\n setupAndroidNotificationChannel,\n );\n knockClient.log(`[Knock] Token received: ${token?.data}`);\n if (token?.data) {\n knockClient.log(`[Knock] Setting push token: ${token.data}`);\n setExpoPushToken(token.data);\n return token.data;\n }\n return null;\n } catch (error) {\n console.error(`[Knock] Error registering for push notifications:`, error);\n return null;\n }\n }, [knockClient, setupAndroidNotificationChannel]);\n\n const updateKnockMessageStatusFromNotification = useCallback(\n async (\n notification: Notifications.Notification,\n status: MessageEngagementStatus,\n ): Promise<Message | void> => {\n const messageId = notification.request.content.data?.[\n \"knock_message_id\"\n ] as string | undefined;\n\n // Skip status update if this isn't a Knock notification\n // Fixes issue: https://github.com/knocklabs/javascript/issues/589\n if (!messageId) {\n knockClient.log(\n \"[Knock] Skipping status update for non-Knock notification\",\n );\n return;\n }\n\n return knockClient.messages.updateStatus(messageId, status);\n },\n [knockClient],\n );\n\n useEffect(() => {\n Notifications.setNotificationHandler({\n handleNotification:\n customNotificationHandler ?? defaultNotificationHandler,\n });\n\n if (autoRegister) {\n registerForPushNotifications()\n .then((token) => {\n if (token) {\n registerPushTokenToChannel(token, knockExpoChannelId)\n .then((_result) => {\n knockClient.log(\"[Knock] setChannelData success\");\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n })\n .catch((_error) => {\n console.error(\n \"[Knock] Error in setting push token or channel data\",\n _error,\n );\n });\n }\n\n const notificationReceivedSubscription =\n Notifications.addNotificationReceivedListener((notification) => {\n knockClient.log(\n \"[Knock] Expo Push Notification received in foreground:\",\n );\n updateKnockMessageStatusFromNotification(notification, \"interacted\");\n notificationReceivedHandler(notification);\n });\n\n const notificationResponseSubscription =\n Notifications.addNotificationResponseReceivedListener((response) => {\n knockClient.log(\"[Knock] Expo Push Notification was interacted with\");\n updateKnockMessageStatusFromNotification(\n response.notification,\n \"interacted\",\n );\n notificationTappedHandler(response);\n });\n\n return () => {\n notificationReceivedSubscription.remove();\n notificationResponseSubscription.remove();\n };\n\n // TODO: Remove when possible and ensure dependency array is correct\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n registerForPushNotifications,\n notificationReceivedHandler,\n notificationTappedHandler,\n customNotificationHandler,\n autoRegister,\n knockExpoChannelId,\n knockClient,\n ]);\n\n return (\n <KnockExpoPushNotificationContext.Provider\n value={{\n expoPushToken,\n registerForPushNotifications,\n registerPushTokenToChannel,\n unregisterPushTokenFromChannel,\n onNotificationReceived: handleNotificationReceived,\n onNotificationTapped: handleNotificationTapped,\n }}\n >\n {children}\n </KnockExpoPushNotificationContext.Provider>\n );\n};\n\nexport const KnockExpoPushNotificationProvider: React.FC<\n KnockExpoPushNotificationProviderProps\n> = (props) => {\n return (\n <KnockPushNotificationProvider>\n <InternalKnockExpoPushNotificationProvider {...props} />\n </KnockPushNotificationProvider>\n );\n};\n\nexport const useExpoPushNotifications =\n (): KnockExpoPushNotificationContextType => {\n const context = useContext(KnockExpoPushNotificationContext);\n if (context === undefined) {\n throw new Error(\n \"[Knock] useExpoPushNotifications must be used within a KnockExpoPushNotificationProvider\",\n );\n }\n return context;\n };\n"],"names":["Notifications","defaultNotificationHandler","_notification","KnockExpoPushNotificationContext","createContext","requestPushPermissionIfNeeded","existingStatus","status","getExpoPushToken","Constants","error","defaultSetupAndroidNotificationChannel","Device","requestPermissionAndGetPushToken","setupAndroidChannel","InternalKnockExpoPushNotificationProvider","knockExpoChannelId","customNotificationHandler","setupAndroidNotificationChannel","children","autoRegister","registerPushTokenToChannel","unregisterPushTokenFromChannel","usePushNotifications","expoPushToken","setExpoPushToken","useState","knockClient","useKnockClient","notificationReceivedHandler","setNotificationReceivedHandler","notificationTappedHandler","setNotificationTappedHandler","handleNotificationReceived","useCallback","handler","handleNotificationTapped","registerForPushNotifications","token","updateKnockMessageStatusFromNotification","notification","messageId","_a","useEffect","_result","_error","notificationReceivedSubscription","notificationResponseSubscription","response","jsx","KnockExpoPushNotificationProvider","props","KnockPushNotificationProvider","useExpoPushNotifications","context","useContext"],"mappings":"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"}
|
|
@@ -3,13 +3,14 @@ import { default as React } from 'react';
|
|
|
3
3
|
import * as Notifications from "expo-notifications";
|
|
4
4
|
export interface KnockExpoPushNotificationContextType extends KnockPushNotificationContextType {
|
|
5
5
|
expoPushToken: string | null;
|
|
6
|
-
registerForPushNotifications: () => Promise<
|
|
6
|
+
registerForPushNotifications: () => Promise<string | null>;
|
|
7
7
|
onNotificationReceived: (handler: (notification: Notifications.Notification) => void) => void;
|
|
8
8
|
onNotificationTapped: (handler: (response: Notifications.NotificationResponse) => void) => void;
|
|
9
9
|
}
|
|
10
10
|
export interface KnockExpoPushNotificationProviderProps {
|
|
11
11
|
knockExpoChannelId: string;
|
|
12
12
|
customNotificationHandler?: (notification: Notifications.Notification) => Promise<Notifications.NotificationBehavior>;
|
|
13
|
+
setupAndroidNotificationChannel?: () => Promise<void>;
|
|
13
14
|
children?: React.ReactElement;
|
|
14
15
|
autoRegister?: boolean;
|
|
15
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KnockExpoPushNotificationProvider.d.ts","sourceRoot":"","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,gCAAgC,EAGtC,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAMN,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,oCACf,SAAQ,gCAAgC;IACxC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4BAA4B,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"KnockExpoPushNotificationProvider.d.ts","sourceRoot":"","sources":["../../../../src/modules/push/KnockExpoPushNotificationProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,gCAAgC,EAGtC,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAMN,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,oCACf,SAAQ,gCAAgC;IACxC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4BAA4B,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3D,sBAAsB,EAAE,CACtB,OAAO,EAAE,CAAC,YAAY,EAAE,aAAa,CAAC,YAAY,KAAK,IAAI,KACxD,IAAI,CAAC;IACV,oBAAoB,EAAE,CACpB,OAAO,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,oBAAoB,KAAK,IAAI,KAC5D,IAAI,CAAC;CACX;AA8BD,MAAM,WAAW,sCAAsC;IACrD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,yBAAyB,CAAC,EAAE,CAC1B,YAAY,EAAE,aAAa,CAAC,YAAY,KACrC,OAAO,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;IACjD,+BAA+B,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,QAAQ,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAuOD,eAAO,MAAM,iCAAiC,EAAE,KAAK,CAAC,EAAE,CACtD,sCAAsC,CAOvC,CAAC;AAEF,eAAO,MAAM,wBAAwB,QAC/B,oCAQH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knocklabs/expo",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"author": "@knocklabs",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"react-native": "*"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@knocklabs/client": "^0.20.
|
|
55
|
-
"@knocklabs/react-core": "^0.12.
|
|
56
|
-
"@knocklabs/react-native": "^0.7.
|
|
54
|
+
"@knocklabs/client": "^0.20.1",
|
|
55
|
+
"@knocklabs/react-core": "^0.12.1",
|
|
56
|
+
"@knocklabs/react-native": "^0.7.3",
|
|
57
57
|
"react-native-gesture-handler": "^2.27.1",
|
|
58
58
|
"react-native-render-html": "^6.3.4",
|
|
59
59
|
"react-native-svg": "^15.12.0"
|
|
@@ -19,7 +19,7 @@ import React, {
|
|
|
19
19
|
export interface KnockExpoPushNotificationContextType
|
|
20
20
|
extends KnockPushNotificationContextType {
|
|
21
21
|
expoPushToken: string | null;
|
|
22
|
-
registerForPushNotifications: () => Promise<
|
|
22
|
+
registerForPushNotifications: () => Promise<string | null>;
|
|
23
23
|
onNotificationReceived: (
|
|
24
24
|
handler: (notification: Notifications.Notification) => void,
|
|
25
25
|
) => void;
|
|
@@ -61,6 +61,7 @@ export interface KnockExpoPushNotificationProviderProps {
|
|
|
61
61
|
customNotificationHandler?: (
|
|
62
62
|
notification: Notifications.Notification,
|
|
63
63
|
) => Promise<Notifications.NotificationBehavior>;
|
|
64
|
+
setupAndroidNotificationChannel?: () => Promise<void>;
|
|
64
65
|
children?: React.ReactElement;
|
|
65
66
|
autoRegister?: boolean;
|
|
66
67
|
}
|
|
@@ -98,13 +99,29 @@ async function getExpoPushToken(): Promise<Notifications.ExpoPushToken | null> {
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
async function
|
|
102
|
+
async function defaultSetupAndroidNotificationChannel(): Promise<void> {
|
|
103
|
+
if (Device.osName === "Android") {
|
|
104
|
+
await Notifications.setNotificationChannelAsync("default", {
|
|
105
|
+
name: "Default",
|
|
106
|
+
importance: Notifications.AndroidImportance.MAX,
|
|
107
|
+
vibrationPattern: [0, 250, 250, 250],
|
|
108
|
+
lightColor: "#FF231F7C",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function requestPermissionAndGetPushToken(
|
|
114
|
+
setupAndroidChannel: () => Promise<void>,
|
|
115
|
+
): Promise<Notifications.ExpoPushToken | null> {
|
|
102
116
|
// Check for device support
|
|
103
117
|
if (!Device.isDevice) {
|
|
104
118
|
console.warn("[Knock] Must use physical device for Push Notifications");
|
|
105
119
|
return null;
|
|
106
120
|
}
|
|
107
121
|
|
|
122
|
+
// Setup Android notification channel before requesting permissions
|
|
123
|
+
await setupAndroidChannel();
|
|
124
|
+
|
|
108
125
|
const permissionStatus = await requestPushPermissionIfNeeded();
|
|
109
126
|
|
|
110
127
|
if (permissionStatus !== "granted") {
|
|
@@ -120,6 +137,7 @@ const InternalKnockExpoPushNotificationProvider: React.FC<
|
|
|
120
137
|
> = ({
|
|
121
138
|
knockExpoChannelId,
|
|
122
139
|
customNotificationHandler,
|
|
140
|
+
setupAndroidNotificationChannel = defaultSetupAndroidNotificationChannel,
|
|
123
141
|
children,
|
|
124
142
|
autoRegister = true,
|
|
125
143
|
}) => {
|
|
@@ -151,19 +169,26 @@ const InternalKnockExpoPushNotificationProvider: React.FC<
|
|
|
151
169
|
[],
|
|
152
170
|
);
|
|
153
171
|
|
|
154
|
-
const registerForPushNotifications = useCallback(async (): Promise<
|
|
172
|
+
const registerForPushNotifications = useCallback(async (): Promise<
|
|
173
|
+
string | null
|
|
174
|
+
> => {
|
|
155
175
|
try {
|
|
156
176
|
knockClient.log(`[Knock] Registering for push notifications`);
|
|
157
|
-
const token = await requestPermissionAndGetPushToken(
|
|
177
|
+
const token = await requestPermissionAndGetPushToken(
|
|
178
|
+
setupAndroidNotificationChannel,
|
|
179
|
+
);
|
|
158
180
|
knockClient.log(`[Knock] Token received: ${token?.data}`);
|
|
159
181
|
if (token?.data) {
|
|
160
182
|
knockClient.log(`[Knock] Setting push token: ${token.data}`);
|
|
161
183
|
setExpoPushToken(token.data);
|
|
184
|
+
return token.data;
|
|
162
185
|
}
|
|
186
|
+
return null;
|
|
163
187
|
} catch (error) {
|
|
164
188
|
console.error(`[Knock] Error registering for push notifications:`, error);
|
|
189
|
+
return null;
|
|
165
190
|
}
|
|
166
|
-
}, [knockClient]);
|
|
191
|
+
}, [knockClient, setupAndroidNotificationChannel]);
|
|
167
192
|
|
|
168
193
|
const updateKnockMessageStatusFromNotification = useCallback(
|
|
169
194
|
async (
|
|
@@ -196,9 +221,9 @@ const InternalKnockExpoPushNotificationProvider: React.FC<
|
|
|
196
221
|
|
|
197
222
|
if (autoRegister) {
|
|
198
223
|
registerForPushNotifications()
|
|
199
|
-
.then(() => {
|
|
200
|
-
if (
|
|
201
|
-
registerPushTokenToChannel(
|
|
224
|
+
.then((token) => {
|
|
225
|
+
if (token) {
|
|
226
|
+
registerPushTokenToChannel(token, knockExpoChannelId)
|
|
202
227
|
.then((_result) => {
|
|
203
228
|
knockClient.log("[Knock] setChannelData success");
|
|
204
229
|
})
|
|
@@ -250,7 +275,6 @@ const InternalKnockExpoPushNotificationProvider: React.FC<
|
|
|
250
275
|
notificationTappedHandler,
|
|
251
276
|
customNotificationHandler,
|
|
252
277
|
autoRegister,
|
|
253
|
-
expoPushToken,
|
|
254
278
|
knockExpoChannelId,
|
|
255
279
|
knockClient,
|
|
256
280
|
]);
|