> ## Documentation Index
> Fetch the complete documentation index at: https://docs.castled.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Push Notification

> [!NOTE]
>
> **Prerequisites**
>
> * [Firebase account already setup and is added to your app](https://docs.castled.io/developer-resources/sdk-integration/android/fcm-private-key-setup.md)
> * [SDK integration completed](https://docs.castled.io/developer-resources/sdk-integration/reactnative/getting-started.md)

This section covers how to setup push notification in React Native.

## Enabling Push Notification in SDK

Set `enablePush` to `true` during SDK initialization. More details about SDK initialization can be found
[here](https://docs.castled.io/developer-resources/sdk-integration/reactnative/getting-started.md#initialization)

```tsx
// Set config
const configs = new CastledConfigs()
configs.appId = "<app-id>"
configs.location = CastledLocation.US
configs.enablePush = true
configs.appgroupId = '<your_ios_appgroup_id>'

// Initialize SDK
CastledNotifications.initialize(configs)
```

## Native setup

> [tab] Android
>
> #### Step 1: Add required permissions
>
> Add the following permission to android app `AndroidManifest.xml`. This allows the app to receive push notifications
>
> ```xml AndroidManifest.xml
>     <manifest ...>
>         <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
>         <application ...>
>             ...
>         </application>
>     </manifest>
> ```
>
> #### Step 2: Firebase push messaging handling service
>
> By default SDK takes care of push token fetch and notification handling once app gets the permission to post notification.
> In case the app has registered its own Firebase message service class (`FirebaseMessagingService`) for handling push tokens,
> SDK needs to be notified of the new token and any push notification received from Castled platform.
> Folow these [instructions](https://docs.castled.io/developer-resources/sdk-integration/android/push-notifications.md#firebase-push-messaging-handling-service)
> if you already have a `FirebaseMessagingService` registered.
>
> #### Step 3: Notification default configs
>
> You can also configure default values for **Notification Channels** and **Notification Icons**. Please find the instructions
> [here](https://docs.castled.io/developer-resources/sdk-integration/android/push-notifications.md#notification-default-configs)

> [tab] iOS
>
> #### Step 1: Configure App Target for iOS Push
>
> Follow these [instructions](https://docs.castled.io/developer-resources/sdk-integration/ios/push-notifications.md#configuring-app-target-for-push-notification) for app target setup.
>
> > [!NOTE]
> >
> > Ensure the **appgroupId** mentioned above matches the one enabled in the App Groups section of the Signing & Capabilities tab for all relevant targets in Xcode, including extensions. If App Groups are not enabled, there is no need to set an appgroupId.
> >
> > We recommend configuring the [appgroupId](https://docs.castled.io/developer-resources/sdk-integration/ios/push-notifications.md#3-adding-an-app-group-id) and using the [Notification Service Extension](https://docs.castled.io/developer-resources/sdk-integration/ios/rich-push-notification.md) for enhanced tracking of notification impressions, accurate badge counts, and media support.
>
> #### Step 2: Configuring Notification Categories and Actions (Optional)
>
> Apps are required to enable support for actionable notifications. During app launch, it is necessary to register one or more notification categories that define the types of notifications your app sends.
> Each category is associated with specific actions that users can take when receiving a notification of that type.
> While each category can have up to four actions, the actual number of displayed actions may vary depending on the notification display. For instance, banners typically show a maximum of two actions.
>
> **Registering the Notification Categories for Your App**
>
> By passing the notificationCategories parameter, you can define a set of categories and associated actions for your notifications.
> Each category corresponds to a type of notification that your app can receive, and for each category,
> you can specify the actions that a user can take directly from the notification.
>
> This flexibility allows app developers to create a rich and interactive notification experience,
> tailored to the needs of their application and its users.
>
> ```objc objc
> // Import any of the below depending on whether the castled-react-native-sdk is provided as a static library or a dynamic library:
> #import "CastledReactBridge.h"
>         // OR
> #import <castled-react-native-sdk/CastledReactBridge.h>
>
> - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
>     self.moduleName = @"TestApp";
>
>     // You can add your custom initial props in the dictionary below.
>     // They will be passed down to the ViewController used by React Native.
>     self.initialProps = @{};
>     [[CastledReactBridge sharedInstance] setNotificationCategoriesWithItems:[self getNotificationCategories]];
>     return [super application:application didFinishLaunchingWithOptions:launchOptions];
> }
>
> - (NSSet<UNNotificationCategory *> *)getNotificationCategories {
>     // Create the custom actions
>     UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"ACCEPT" title:@"Accept" options:UNNotificationActionOptionForeground];
>     UNNotificationAction *action2 = [UNNotificationAction actionWithIdentifier:@"DECLINE" title:@"Decline" options:0];
>     // Create the category with the custom actions
>     UNNotificationCategory *customCategory1 = [UNNotificationCategory categoryWithIdentifier:@"ACCEPT_DECLINE" actions:@[action1, action2] intentIdentifiers:@[] options:0];
>
>     UNNotificationAction *action3 = [UNNotificationAction actionWithIdentifier:@"YES" title:@"Yes" options:UNNotificationActionOptionForeground];
>     UNNotificationAction *action4 = [UNNotificationAction actionWithIdentifier:@"NO" title:@"No" options:0];
>     // Create the category with the custom actions
>     UNNotificationCategory *customCategory2 = [UNNotificationCategory categoryWithIdentifier:@"YES_NO" actions:@[action3, action4] intentIdentifiers:@[] options:0];
>     NSSet<UNNotificationCategory *> *categoriesSet = [NSSet setWithObjects:customCategory1, customCategory2, nil];
>     return categoriesSet;
> }
>
> ```
>
> ```swift swift
> // Import any of the below in Bridging Header depending on whether the castled-react-native-sdk is provided as a static library or a dynamic library:
> #import "CastledReactBridge.h"
>         // OR
> #import <castled-react-native-sdk/CastledReactBridge.h>
>
>
> func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
>     self.moduleName = "Module Name”
>
>     // You can add your custom initial props in the dictionary below.
>     // They will be passed down to the ViewController used by React Native.
>     self.initialProps = [:]
>     CastledReactBridge.sharedInstance().setNotificationCategoriesWithItems(getNotificationCategories())
>     return super.application(application, didFinishLaunchingWithOptions: launchOptions)
> }
>
> func getNotificationCategories() -> Set<UNNotificationCategory> {
>     // Create the custom actions
>     let action1 = UNNotificationAction(identifier: "ACCEPT", title: "Accept", options: UNNotificationActionOptions.foreground)
>     let action2 = UNNotificationAction(identifier: "DECLINE", title: "Decline", options: UNNotificationActionOptions.foreground)
>     // Create the category with the custom actions
>     let customCategory1 = UNNotificationCategory(identifier: "ACCEPT_DECLINE", actions: [action1, action2], intentIdentifiers: [], options: [])
>
>     let action3 = UNNotificationAction(identifier: "YES", title: "Yes", options: [UNNotificationActionOptions.foreground])
>     let action4 = UNNotificationAction(identifier: "NO", title: "No", options: [])
>     // Create the category with the custom actions
>     let customCategory2 = UNNotificationCategory(identifier: "YES_NO", actions: [action3, action4], intentIdentifiers: [], options: [])
>     let categoriesSet = Set([customCategory1, customCategory2])
>     return categoriesSet
> }
>
> ```
>
> #### Step 3: Support for Rich Push Notification
>
> Follow the [instructions](https://docs.castled.io/developer-resources/sdk-integration/ios/rich-push-notification.md) here
> for setting up rich push notifications.
>
> Also in the /ios directory of your project,
> open the Podfile and add the following outside of the main target (should be at the same level as your main target):
>
> ```pod
> target 'CastledNotificationServiceExtension' do
>    pod 'CastledNotificationService'
> end
>
> target 'CastledNotificationContentExtension' do
>    pod 'CastledNotificationContent'
> end
> ```
>
> > [!NOTE]
> >
> > We recommend configuring the **appgroupId** and using the [Notification Service Extension](https://docs.castled.io/developer-resources/sdk-integration/ios/rich-push-notification.md) for enhanced tracking of notification impressions, accurate badge counts, and media support.
>
> #### **Step 4: AppDelegate Swizzling in Castled SDK**
>
> Castled SDK is designed to simplify push notification handling. By default, swizzling is enabled, which means the SDK automatically handles the registration of device tokens,
> the presentation of notifications, and the response to user interactions with those notifications.
>
> **Disable Swizzling**
>
> This step is applicable only if:
>
> 1. Your app is using other SDKs along with Castled for handling push notification.
> 2. You prefer to have more granular control over notification handling or may need to comply with specific architectural requirements.
>
> To disable method swizzling with Castled SDK, you must update the Info.plist file of your application.
>
> ```xml info.plist
> <key>CastledSwizzlingDisabled</key>
> <true/>
> ```
>
> Once swizzling is disabled, the responsibility of invoking the necessary methods falls on the developer.
> Developer needs to implement various `UNUserNotificationCenterDelegate` and `UIApplicationDelegate` methods to handle
> different notification scenarios.
>
> #### Manual Handling of Push Notifications
>
> Initializing Castled React SDK and Setting Delegates
>
> ```objc objc
>     #import "AppDelegate.h"
>     // 1: Import the Castled React SDK
>     #import "CastledReactBridge.h"
>     #import <UserNotifications/UserNotifications.h>
>
>     // 2: Declare AppDelegate conforming to UIApplicationDelegate and UNUserNotificationCenterDelegate protocols to manage notifications.
>     @interface AppDelegate ()<UIApplicationDelegate,UNUserNotificationCenterDelegate>
>     {
>     }
>     @end
>
>     @implementation AppDelegate
>
>     - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
>         self.moduleName = @"Module Name";
>
>         // 3: Assign AppDelegate as the delegate for UNUserNotificationCenter to handle notification events
>         [UNUserNotificationCenter currentNotificationCenter].delegate = self;
>
>         // You can add your custom initial props in the dictionary below.
>         // They will be passed down to the ViewController used by React Native.
>         self.initialProps = @{};
>
>         return [super application:application didFinishLaunchingWithOptions:launchOptions];
>     }
>
> ```
>
> ```swift swift
>     // 1: Import any of the below in Bridging Header depending on whether the castled-react-native-sdk is provided as a static library or a dynamic library:
>     #import "CastledReactBridge.h"
>                 // OR
>     #import <castled-react-native-sdk/CastledReactBridge.h>
>
>
>     // 2: Declare AppDelegate conforming to UIApplicationDelegate and UNUserNotificationCenterDelegate protocols to manage notifications.
>     class AppDelegate: UIResponder, UIApplicationDelegate {
>
>         func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
>             self.moduleName = "Module Name”
>
>             // 3: Assign AppDelegate as the delegate for UNUserNotificationCenter to handle notification events
>             UNUserNotificationCenter.current().delegate = self
>
>             // You can add your custom initial props in the dictionary below.
>             // They will be passed down to the ViewController used by React Native.
>             self.initialProps = [:]
>
>             return super.application(application, didFinishLaunchingWithOptions: launchOptions)
>         }
>     }
>
> ```
>
> > [!NOTE]
> >
> > If your **Swift** project doesn't have a bridging header yet, you need to create one. To acheive this,
> > Create a new **Objective-C** file in your Swift project. Xcode will prompt you to create a bridging header.
> > Accept and let Xcode create it.
>
> Handling Push Notifications Delegates (Copy Below Delegate Methods to AppDelegate)
>
> ```objc objc
>      // Handling Device Token Registration
>     -(void) application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
>             NSMutableString *deviceTokenString =[NSMutableString string];
>             if (@available(iOS 13.0, *)) {
>                     deviceTokenString = [NSMutableString string];
>                     const unsigned char *bytes = (const unsigned char *)[deviceToken bytes];
>                     NSInteger count = deviceToken.length;
>                     for (int i = 0; i < count; i++) {
>                         [deviceTokenString appendFormat:@"%02x", bytes[i]&0x000000FF];
>                     }
>                 } else {
>                     NSString *deviceToken1 =  [[[[deviceToken description]
>                                             stringByReplacingOccurrencesOfString:@"<" withString:@""]
>                                             stringByReplacingOccurrencesOfString:@">" withString:@""]
>                                         stringByReplacingOccurrencesOfString:@" " withString:@""];
>                     deviceTokenString = [[NSMutableString alloc] initWithString:deviceToken1];
>                 }
>             NSLog(@"didRegisterForRemoteNotificationsWithDeviceToken: %@", deviceTokenString);
>             [[CastledReactBridge sharedInstance] setPushToken:deviceTokenString type: apns];
>     }
>
>     // Handling Registration Failure
>     -(void) application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
>             NSLog(@"failed to register for remote notifications: %@ %@", self.description, error.localizedDescription);
>     }
>
>     // Handling Notification Responses
>     -(void) userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler{
>             [[CastledReactBridge sharedInstance] userNotificationCenter:center didReceiveNotificationResponse:response];
>             completionHandler();
>     }
>
>     // Handling Foreground Notification Presentation
>     -(void) userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{
>             [[CastledReactBridge sharedInstance] userNotificationCenter:center willPresentNotification:notification];
>             if (@available(iOS 14.0, *)) {
>                 // For iOS 14 and later
>                 completionHandler(UNNotificationPresentationOptionBanner | UNNotificationPresentationOptionList | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound);
>             } else {
>                 // For iOS 13 and earlier
>                 completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound);
>             }
>     }
>
>     // Handling Background Notifications
>     - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
>
>         [[CastledReactBridge sharedInstance] didReceiveRemoteNotification:userInfo];
>
>         // Implement your logic here...
>
>         completionHandler(UIBackgroundFetchResultNoData);
>     }
>
> ```
>
> ```swift swift
>    extension AppDelegate: UNUserNotificationCenterDelegate {
>       // Handling Device Token Registration
>       func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
>         let deviceTokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
>         CastledReactBridge.sharedInstance().setPushToken(deviceTokenString, type: apns)
>         print("APNs token \(deviceTokenString) \(self.description)")
>       }
>
>       // Handling Registration Failure
>       func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
>         print("Failed to register for remote notifications \(error.localizedDescription)")
>       }
>
>       // Handling Notification Responses
>       func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
>         // Handle the click events
>         CastledReactBridge.sharedInstance().userNotificationCenter(center, didReceive: response)
>         completionHandler()
>       }
>
>       // Handling Foreground Notification Presentation
>       func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
>             CastledReactBridge.sharedInstance().userNotificationCenter(center, willPresent: notification)
>         if #available(iOS 14.0, *) {
>             // For iOS 14 and later
>             completionHandler([.banner, .list, .badge, .sound])
>         } else {
>             // For iOS 13 and earlier
>             completionHandler([.alert, .badge, .sound])
>         }
>      }
>
>       // Handling Background Notifications
>       func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
>
>             CastledReactBridge.sharedInstance().didReceiveRemoteNotification(userInfo)
>
>             // Implement your logic here...
>
>             completionHandler(.noData)
>       }
>     }
>
> ```
>
> > [!NOTE]
> >
> > If the App is handling the push notification click actions itself, please
> > disable the default url handling by the SDK by setting `skipUrlHandling` to
> > `true` in the SDK configs during initialization.

## Requesting Push Notification Permission

Following SDK method can be used by the app to fetch user permission for showing push notifications. User will be shown the native
notification permission dialog based on the mobile platform he is on.

```tsx
CastledNotifications.requestPushPermission()
  .then((isGranted) => {
    if (isGranted) {
      console.log("Push notification permission granted")
    } else {
      console.log("Push notification permission not granted")
    }
  })
  .catch((error) => {
    console.log("Request failed, error: " + error.message)
  })
```

## Push Notification Events Listener

App can listen to push notification events by registering a listener. This is useful when you want to override the default click actions implemented by the SDK with
your own custom implementations.

Currently the following push events as supported:

* Notification Received
* Notification Clicked
* Notification Dimissed

Please find the sample code snippet below

```tsx
import {
  CastledEvents,
  type CastledClickAction,
  type CastledPushNotification,
  type CastledPushNotificationClickEvent,
} from "castled-react-native-sdk"

// Push received listener
const pushReceivedListener = CastledNotifications.addListener(
  CastledEvents.PUSH_NOTIFICATION_RECEIVED,
  (notification: CastledPushNotification) => {
    console.log("Push notification received:", notification)
  }
)

// Click action listener
const pushClickedListener = CastledNotifications.addListener(
  CastledEvents.PUSH_NOTIFICATION_CLICKED,
  (event: CastledPushNotificationClickEvent) => {
    console.log(
      "Push notification clicked: notification object ",
      event.notification
    )
    console.log("Push notification clicked: clickAction", event.clickAction)
  }
)

// Push dismissed listener
const pushDismissedListener = CastledNotifications.addListener(
  CastledEvents.PUSH_NOTIFICATION_DISMISSED,
  (notification: CastledPushNotification) => {
    console.log("Push notification dismissed:", notification)
  }
)

// Unsubscribing the listeners
pushReceivedListener.remove()
pushClickedListener.remove()
pushDismissedListener.remove()
```

> [!NOTE]
>
> If the App is handling the push notification click actions itself, please
> disable the default url handling by the SDK by setting `skipUrlHandling` to
> `true` in the SDK configs during initialization.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.