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

# iOS Push Setup

> Step-by-step guide to setup APNS iOSpush notifications in your react native app.

<Warning>
  **Major Release (V 1.0.0)** 🚧

  Starting from iOS version v1.0.0, we have introduced explicit push notification permission and option to add images in your notification. Also, introduced background mode for improved tracking of notification delivery.

  If you are using an iOS version older than v1.0.0 and upgrading to the new version. Please ensure to use the latest integration steps, especially for below methods:

  1. [Adding Background mode capability (point 3 of capabilities)](/docs/react-native-ios-push-integration)

  2. [Calling registerPush method](/docs/react-native-ios-push-integration)

  3. [Tracking delivery methods](/docs/react-native-ios-push-integration)
</Warning>

<Steps>
  <Step title="Add capabilities in iOS application">
    1. Inside Targets select **signing and capabilities**

    2. Click on **+capabilities** and select **Push Notifications** and **Background Modes**

    <Frame>
      <img src="https://mintcdn.com/suprsend/3ix_OjxB_ZGM-pa-/images/docs/29bafbe-Screenshot_2022-05-19_at_5.48.52_PM.png?fit=max&auto=format&n=3ix_OjxB_ZGM-pa-&q=85&s=6dc8960bc305b9ff439cfd265cd4f1dc" width="2880" height="1800" data-path="images/docs/29bafbe-Screenshot_2022-05-19_at_5.48.52_PM.png" />
    </Frame>

    In Background Modes, select Remote Notifications option. We use background notifications to receive delivery reports when your app is in quit and background state. Refer [doc](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app) to know more about background notification

    <Frame>
      <img src="https://mintcdn.com/suprsend/09Y8zJBSaqwwb23r/images/docs/75c5310-Screenshot_2022-09-27_at_1.48.11_PM.png?fit=max&auto=format&n=09Y8zJBSaqwwb23r&q=85&s=3455b9ac0218ac1621399be197c1b46a" width="1756" height="1066" data-path="images/docs/75c5310-Screenshot_2022-09-27_at_1.48.11_PM.png" />
    </Frame>
  </Step>

  <Step title="Register for push notifications">
    Call *registerForPushNotifications* method below the SuprSend SDK initialised code which will register the iOS device for push service.

    If you have AppDelegate.m file then make follow code changes given in AppDelegate.h and AppDelegate.m file. If you have AppDelegate.swift file then make follow code changes given in AppDelegate.swift file.

    <CodeGroup>
      ```objectivec AppDelegate.h theme={"system"}
        #import <UserNotifications/UserNotifications.h> // Add this
          
        @interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate> // Add UNUserNotificationCenterDelegate in the already existing line
      ```

      ```objectivec AppDelegate.m theme={"system"}
      #import <UserNotifications/UserNotifications.h> // Add this

      // ... existing code ...

      [SuprSend.shared configureWithConfiguration:configuration launchOptions:launchOptions]; // init code which is already added at time of initialisation

      UNAuthorizationOptions options = UNAuthorizationOptionAlert+UNAuthorizationOptionBadge+UNAuthorizationOptionSound;  // Add this
      [SuprSend.shared registerForPushNotificationsWithOptions:options]; // Add this
      ```

      ```swift AppDelegate.swift theme={"system"}
      import UserNotifications // Add this

      // extend AppDelegate with UNUserNotificationCenterDelegate
      class AppDelegate: RCTAppDelegate, UNUserNotificationCenterDelegate { 
          override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {

           // ... existing code ...

           SuprSend.shared.configureWith(configuration: suprSendConfiguration  , launchOptions: launchOptions) // init code which is already added at time of initialisation
           var options: UNAuthorizationOptions = [.badge, .alert, .sound] // Add this
           SuprSend.shared.registerForPushNotifications(options: options) // Add this
          }
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Asking User to send push notifications">
    There are 2 ways in which your app can prompt the users to allow push notifications on their device:

    <Accordion title="Explicit Authorization" defaultOpen={false}>
      Explicit authorization allows you to display alerts, add a badge to the app icon, or play sounds whenever a notification is delivered. In this type of authorization, the request is made the first time user launches your app. If the user denies the request, you can't send subsequent prompts to send the notification.

      <Frame>
        <img src="https://mintcdn.com/suprsend/JOwfEC79k-vs3tUR/images/docs/8538f91-app_permission.png?fit=max&auto=format&n=JOwfEC79k-vs3tUR&q=85&s=3e3be8e0b3762dd835a490e6c4c1af7f" width="448" height="312" data-path="images/docs/8538f91-app_permission.png" />
      </Frame>

      <Info>
        Explicit authorization is our default authorization method as it automatically sets alert, sound and badge as soon as the user allows this request.
      </Info>
    </Accordion>

    <Accordion title="Provisional Authorization (Supported in iOS 12.0 and above)" defaultOpen={false}>
      Provisional notifications are sent quietly to the users —they don’t interrupt the user with a sound or banner. Also, they will not be shown when your app is in foreground. First time this type of notifications are sent, user is asked to "Keep" or "Turn off" the notifications. If they click on "Keep", the further notifications continue to be sent

      <Frame>
        <img src="https://mintcdn.com/suprsend/ftswjUsq0JlUh-RL/images/docs/0367021-provisional.png?fit=max&auto=format&n=ftswjUsq0JlUh-RL&q=85&s=c44246faebb35ddb646e77c3ea29a522" width="816" height="474" data-path="images/docs/0367021-provisional.png" />
      </Frame>

      Add below code in `AppDelegate` file for provisional authorization.

      <CodeGroup>
        ```objectivec AppDelegate.m theme={"system"}
        [SuprSend.shared configureWithConfiguration:configuration launchOptions:launchOptions]; // init code which is already added at time of initialisation

        UNAuthorizationOptions options = UNAuthorizationOptionAlert+UNAuthorizationOptionBadge+UNAuthorizationOptionSound;  // Add this
        if (@available(iOS 12.0, *)) {
        	options = options | UNAuthorizationOptionProvisional;
        }
        [SuprSend.shared registerForPushNotificationsWithOptions:options]; // Add this
        ```

        ```swift AppDelegate.swift theme={"system"}
        SuprSend.shared.configureWith(configuration: suprSendConfiguration  , launchOptions: launchOptions) // init code which is already added at time of initialisation

        var options: UNAuthorizationOptions = [.badge, .alert, .sound]

        // If you want to use provisional authorization
        if #available(iOS 12.0, *) {
         options = [.badge, .alert, .sound, .provisional]
        }
        SuprSend.shared.registerForPushNotifications(options: options)
        ```
      </CodeGroup>
    </Accordion>
  </Step>

  <Step title="Enable sending and tracking of push notifications">
    To enable sending iOS APNS token to SuprSend backend, delivery and tracking of push notification delivery/clicks/dismiss events, add below 4 methods in **AppDelegate file** after last existing method.

    <CodeGroup>
      ```objectivec AppDelegate.m theme={"system"}
      - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
        NSUInteger dataLength = deviceToken.length;
          if (dataLength == 0) {
            return;
          }
          const unsigned char *dataBuffer = (const unsigned char *)deviceToken.bytes;
          NSMutableString *hexString  = [NSMutableString stringWithCapacity:(dataLength * 2)];
          for (int i = 0; i < dataLength; ++i) {
            [hexString appendFormat:@"%02x", dataBuffer[i]];
          }
        [SuprSend.shared setPushNotificationTokenWithToken:hexString];
      }

      - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
          if (@available(iOS 14.0, *)) {
            completionHandler(UNAuthorizationOptionSound | UNNotificationPresentationOptionBanner | UNAuthorizationOptionBadge);
          } else {
            completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
          }
      }

      - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler API_AVAILABLE(ios(7.0)){
          [SuprSend.shared application:application didReceiveRemoteNotification:userInfo];
          completionHandler(UIBackgroundFetchResultNewData);
      }

      - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler{
       if ([response isSuprSendNotification]) {
         [SuprSend.shared userNotificationCenter:center didReceive:response];
       }
       completionHandler();
      }

      @end // before this line
      ```

      ```swift AppDelegate.swift theme={"system"}
      override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
        let  token = tokenParts.joined()
        SuprSend.shared.setPushNotificationToken(token: token)  // Send APNS Token to SuprSend
      }

      @available(iOS 10.0, *)
      func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
      ) {
        if response.isSuprSendNotification() {
          SuprSend.shared.userNotificationCenter(center, didReceive: response)
        }
        completionHandler()
      }

      override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]){
        SuprSend.shared.application(application, didReceiveRemoteNotification: userInfo)
      }
          
      @available(iOS 10.0, *)
      func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        if #available(iOS 14.0, *) {
          completionHandler([.banner, .badge, .sound])
        } else {
          completionHandler([.alert, .badge, .sound])
        }
      }
      ```
    </CodeGroup>

    <Warning>
      iOS Push notifications only work on real devices so while developing/testing use real device to test it instead of simulators
    </Warning>
  </Step>

  <Step title="Adding support for Notification service">
    For better notification status (delivered, seen) tracking this step is needed.

    1. In Xcode go to **File > New > Target**.

    2. Select Notification Service Extension from the template list.

    3. Then in Next popup give it any product name, select your team, select swift language and click finish.

    <Frame>
      <img src="https://mintcdn.com/suprsend/3ix_OjxB_ZGM-pa-/images/docs/2545534-Screenshot_2022-09-27_at_8.23.30_PM.png?fit=max&auto=format&n=3ix_OjxB_ZGM-pa-&q=85&s=7d5b605ac23ad4753e43f6bbfc846424" width="1678" height="1138" data-path="images/docs/2545534-Screenshot_2022-09-27_at_8.23.30_PM.png" />
    </Frame>

    After clicking on "Finish", a folder will be created with your given product name. Inside that there will be **NotificationService.swift** file like below.

    <Frame>
      <img src="https://mintcdn.com/suprsend/09Y8zJBSaqwwb23r/images/docs/507d91a-Screenshot_2022-09-27_at_8.30.25_PM.png?fit=max&auto=format&n=09Y8zJBSaqwwb23r&q=85&s=844b510f372bafdcb4ff19dc6120c314" width="1746" height="838" data-path="images/docs/507d91a-Screenshot_2022-09-27_at_8.30.25_PM.png" />
    </Frame>

    In your project podFile add following snippet at the end of existing code like shown in image. Replace **\<your notification service name>** with name you given to notification service while creating it. After that Run `pod install`.

    <CodeGroup>
      ```yaml podFile theme={"system"}
      target '<your notification service name>' do
        pod 'SuprsendCore'
        pod 'SuprSendSdk'
      end
      ```
    </CodeGroup>

    <Frame>
      <img src="https://mintcdn.com/suprsend/jhGzZpggWCp1KSgu/images/docs/df1b9d550359532399612d3427d3a075b3e9c2bc70578e3b201fc15fc1c1cabf-Screenshot_2024-09-03_at_2.08.29_PM.png?fit=max&auto=format&n=jhGzZpggWCp1KSgu&q=85&s=bf848ecd8670edf6e18060ab38d4fe0c" width="2396" height="1370" data-path="images/docs/df1b9d550359532399612d3427d3a075b3e9c2bc70578e3b201fc15fc1c1cabf-Screenshot_2024-09-03_at_2.08.29_PM.png" />
    </Frame>

    Replace the content in **NotificationService.swift** file with below code. In this snippet on line 11, 12 replace values with your workspace key and workspace secret.

    <CodeGroup>
      ```swift NotificationService.swift theme={"system"}
      import UserNotifications
      import UIKit

      class NotificationService: UNNotificationServiceExtension {
      var contentHandler: ((UNNotificationContent) -> Void)?
      var modifiedNotificationContent: UNMutableNotificationContent?
        
        private func track(request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {

          let suprSendConfiguration = SuprSendSDKConfiguration(
            withKey: "your workspace key",
            secret: "your workspace secret"
          )

          SuprSend.shared.configureWith(configuration: suprSendConfiguration , launchOptions: [:])
          SuprSend.shared.didReceive(request, withContentHandler: contentHandler)
        }

      override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
          self.contentHandler = contentHandler
          modifiedNotificationContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
           track(request: request, withContentHandler: contentHandler)
          
          if let modifiedNotificationContent = modifiedNotificationContent {
              // Modify the notification content here...
              // 1
              guard let imageURLString =
                      modifiedNotificationContent.userInfo["image_url"] as? String else {
                  contentHandler(modifiedNotificationContent)
                  return
              }
              
              getMediaAttachment(for: imageURLString) { [weak self] image in
                  guard let self = self, let image = image, let fileURL = self.saveImageAttachment(
                      image: image,
                      forIdentifier: "attachment.png")
                  else {
                      contentHandler(modifiedNotificationContent)
                      return
                  }
                  
                  let imageAttachment = try? UNNotificationAttachment(
                      identifier: "image",
                      url: fileURL,
                      options: nil)
                  
                  if let imageAttachment = imageAttachment {
                      modifiedNotificationContent.attachments = [imageAttachment]
                  }
                  
                  contentHandler(modifiedNotificationContent)
              }
          }
      }

      override func serviceExtensionTimeWillExpire() {
          // Called just before the extension will be terminated by the system.
          // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
          if let contentHandler = contentHandler, let bestAttemptContent =  modifiedNotificationContent {
              contentHandler(bestAttemptContent)
          }
          
      }

      }

      extension NotificationService {

      private func saveImageAttachment(image: UIImage, forIdentifier identifier: String
      ) -> URL? {
        let tempDirectory = URL(fileURLWithPath: NSTemporaryDirectory())
        let directoryPath = tempDirectory.appendingPathComponent(
          ProcessInfo.processInfo.globallyUniqueString,
          isDirectory: true)

        do {
          try FileManager.default.createDirectory(
            at: directoryPath,
            withIntermediateDirectories: true,
            attributes: nil)

          let fileURL = directoryPath.appendingPathComponent(identifier)

          guard let imageData = image.pngData() else {
            return nil
          }

          try imageData.write(to: fileURL)
            return fileURL
          } catch {
            return nil
        }
      }

      private func getMediaAttachment(for urlString: String, completion: @escaping (UIImage?) -> Void
      ) {
          // 1
          guard let url = URL(string: urlString) else {
              completion(nil)
              return
          }
          
          let task = URLSession.shared.dataTask(with: url) { data, response, error in
              if error != nil {
                  completion(nil)
                  return
              }
              
              guard let data = data else {
                  completion(nil)
                  return
              }
              
              guard let image = UIImage(data: data) else {
                  completion(nil)
                  return
              }
              completion(image)
          }
          task.resume()
      }
      }
      ```
    </CodeGroup>

    You are now all set to send push notifications. All you have to do is add [iOS vendor configuration](/docs/ios-push-vendor-integration) on SuprSend dashboard and your push notifications will be configured. Please refer [vendor integration guide](/docs/ios-push-vendor-integration) to integrate your apns push service
  </Step>
</Steps>

***
