Source: https://fyno.docs.pageloop.ai/sd-ks/mobile-push/swift

# Swift Push SDK

Fyno's iOS (Swift) Push Notification SDK offers a comprehensive set of notification features within your app. It's designed to efficiently deliver messages, ensuring optimal performance and user experience.

## Prerequisites

In order to get started, there are a few prerequisites that needs to be in place:

- **Fyno account:** A valid Fyno workspace with at least one active API Key. For more info, refer [Workspace Docs](./workspace-settings).
- **Configuration:** Configure your Fyno Push provider in Fyno App > [Integrations](https://app.fyno.io/integrations).
- **Swift iOS application:** A working Swift iOS application in which you want to integrate the SDK.
- **Apple developer account:** Required details are mentioned in [APNs Docs](./push-apns).

## Installation

1. **Install the SDK**

   Add `pod 'fyno-push-ios', '~> 1.1'` similar to the following to your `Podfile`:
   ```Text title="Podfile" wordWrap
   target 'MyApp' do
     pod 'fyno-push-ios', '~> 1.1'
   end
   ```
   Then run a pod install inside your terminal to download and install the fyno push sdk for iOS.
2. **Add Required Capabilities**
   1. Inside Targets select signing and capabilities.

   2. Click on +capabilities and add Push Notifications and Background Modes capabilities to your application.
      ![](/images/fyno_apns_1.jpeg)
      ![](/images/fyno_apns_2.jpeg)

   3. 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 notifications.
      ![](/images/fyno_apns_3.png)
3. **Add Notification Service Extension to your application**
   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.
      ![](/images/fyno_apns_4.png)
      ![](/images/fyno_apns_5.png)

   4. After clicking on "Finish", a folder will be created with your given product name. Replace the contents of the **NotificationService.swift** file with the below code.

      ```swift title="NotificationService.swift" wordWrap
      import UserNotifications
      import UIKit
      import fyno

      class NotificationService: UNNotificationServiceExtension {
          var contentHandler: ((UNNotificationContent) -> Void)?
          var bestAttemptContent: UNMutableNotificationContent?

          override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
              fyno.app.handleDidReceive(request, withContentHandler: contentHandler)
          }

          override func serviceExtensionTimeWillExpire() {
              if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
                  contentHandler(bestAttemptContent)
              }
          }
      }
      ```

   5. In order for the **Notification Service Extension** to be able to access the fyno SDK, you will have to import it by following the below steps:
      ![](/images/fyno_apns_6.png)
      ![](/images/fyno_apns_7.png)

   6. Search for `https://github.com/fynoio/ios-sdk` in the text box. Select and add the package named **ios-sdk**.
      ![](/images/fyno_apns_8.png)

   7. Select the Target as the Notification Service Extension you had created and click on `Add Package`.
      ![](/images/fyno_apns_9.png)
   > [!TIP]
   >
   > If you face any build issues similar to `Error (Xcode): Cycle inside Runner; building could produce unreliable results` after adding the notification service extension, follow [this](https://stackoverflow.com/a/77261331) answer to resolve it.
4. **Register for push notification in AppDelegate.swift file**

   Add the below code in your `AppDelegate.swift` file.
   #### Without FCM
   ```swift title="Without FCM" wordWrap
   // without FCM

   import Foundation
   import UIKit
   import fyno_push_ios

   class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
   let fynosdk = fyno.app

       func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
          UNUserNotificationCenter.current().delegate = fynosdk

          self.fynosdk.registerForRemoteNotifications()
          fynosdk.requestNotificationAuthorization{ _ in}

          return true
       }

       func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
           print("Failed to register for remote notifications: \(error.localizedDescription)")
       }

       func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
           // Send the device token to fynoServer
           fynosdk.setdeviceToken(deviceToken: deviceToken)
       }

   }

   ```
   #### With FCM
   ```swift title="With FCM" wordWrap
   // with FCM

   import Foundation
   import UIKit
   import fyno_push_ios

   // imports required for FCM integration
   import FirebaseCore
   import FirebaseMessaging

   class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate  {
       let fynosdk = fyno.app

       func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
          UNUserNotificationCenter.current().delegate = fynosdk

          self.fynosdk.registerForRemoteNotifications()

          FirebaseApp.configure() // add only if FCM has been integrated

          fynosdk.requestNotificationAuthorization{ _ in}

          return true
       }

       func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
           print("Failed to register for remote notifications: \(error.localizedDescription)")
       }

       func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
           // Send the device token to fynoServer
           fynosdk.setdeviceToken(deviceToken: deviceToken)

           Messaging.messaging().apnsToken = deviceToken // add only if FCM has been integrated
       }
   }
   ```

> [!TIP]
>
> You have successfully configured the iOS SDK for receiving push notifications.

## Usage

### Initialising the SDK (to be called on app launch)

To initialise the Fyno SDK, you need to provide the following information:

- **Workspace ID (Mandatory):** Your unique Fyno workspace ID, available on the Fyno App > [Workspace Settings](https://app.fyno.io/settings) page.
- **Integration ID (Mandatory):** The ID of the integration created in Fyno App > [Integrations](https://app.fyno.io/integrations).
- **Distinct ID (Optional):** A unique identifier for your user. If not provided, a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) is automatically generated.
- **Version (Optional):** Indicates the environment in which the user has to be created. Default is **"live"**, but you can set it to **"test"** for testing purposes.

```swift title="swift" wordWrap
fyno.app.initializeApp(
    workspaceID: workspaceId,
    integrationID: integrationID,
    distinctId: distinctID,
    version: version
){
    initResult in
    switch initResult {
    case .success(_):
        print("Initialization successful")
    case .failure(let error):
        print(error)
    }
}
```

### Identifying the User

To update/set a distinct ID or user name, call `fyno.app.identify()`.

- **Distinct ID (Mandatory):** The distinct ID you want to identify the user with.
- **User Name (Optional):** - The name you want to assign to the user.

```swift title="swift" wordWrap
fyno.app.identify(newDistinctId: distinctID, userName: userName) { identifyResult in
    switch identifyResult{
    case .success(_):
        print("Identify successful")
    case .failure(let error):
        print(error)
    }
}
```

### Registering for Push Notifications

To register the application for push notifications, call `fyno.app.registerPush()`.

- **isAPNs (Mandatory):** Use **true** if [APNs](./push-apns) is configured, **false** if [Google FCM](./push-fcm) is configured in the integration.

```swift title="swift" wordWrap
fyno.app.registerPush(isAPNs: isAPNs){
    registerPushResult in
    switch registerPushResult{
    case .success(_):
        print("registerPush successful")
    case .failure(let error):
        print(error)
    }
}
```

### Merging User Profiles

If you need to merge two user profiles, call `fyno.app.mergeProfile()` with the old and new distinct IDs.

```swift title="swift" wordWrap
fyno.app.mergeProfile(newDistinctId:newDistinctId){
    mergeResult in
    switch mergeResult{
    case .success(_):
        print("mergeProfile successful")
    case .failure(let error):
        print(error)
    }
}
```

### Updating Message Status

You can update the status of a notification (received, clicked or dismissed) using `fyno.app.updateStatus()`.

- **Callback URL (Mandatory):** You can obtain the Callback URL from the notification additional payload if the notification was triggered from Fyno.
- **Status (Mandatory):** The status of the notification (one of **RECEIVED**, **CLICKED** or **DISMISSED**).

```swift title="swift" wordWrap
fyno.app.updateStatus(callbackUrl: callbackUrl, status: status){
    updateStatusResult in
    switch updateStatusResult{
    case .success(_):
        print("updateStatus successful")
    case .failure(let error):
        print(error)
    }
}
```

### Resetting User Information

To reset user information, call `fyno.app.resetUser()`.

- You can invoke this function when the user logs out of the application.
- It handles the deletion of channel data associated with the current user, initiates the creation of a fresh user profile, and transfers this particular channel data (push token) to the newly created profile.
- This feature proves to be invaluable if you plan to send push notifications to an application even after the user has logged out.
- It is also **recommmended** as it ensures that devices where the users have logged out are no longer associated with them.

```swift title="swift" wordWrap
fyno.app.resetUser() {
    resetUserResult in
    switch resetUserResult{
    case .success(_):
        print("resetUser successful")
    case .failure(let error):
        print(error)
    }
}
```
