Mobile Apps – technical documentation for iOS

Requirements

Installation

To add the package as a dependency to your Xcode project, follow the steps:

  1. Select File > Add Package Dependency and enter the repository URL
    https://github.com/GetResponse/MobileSDK-IOS 
  2. Click Add package and select your main target.
  3. Repeat the steps for the Notification Service Extension target (see Preparation).

Alternatively:

  1. Go to your main target options.
  2. Under General > Frameworks, Libraries, and Embedded Content, click the + button
  3. Select Add other > Add package dependency and follow the steps above.
  4. Repeat the steps for Notification Service Extension target (see Preparation).

Preparation

To fully support notifications and collect statistics, you need to add the Notification Service Extension target.

  1. If you don’t have it already, add a Notification Service Extension target:
    • Go to File > New > Target.
    • Select Notification Service Extension, give it a name and click Finish.
    • Click Cancel on the next dialog that asks to activate the scheme.
  2. If you haven’t done it already, add this package to the newly created target.

Next, configure required app capabilities by going to Signing & Capabilities > + Capability:

  1. In main target, add:
    • App Groups
      • Select an existing group or create one.
    • Push Notifications
    • Background Modes
      • Select Background fetch and Remote notifications
  2. In Notification Service Extension target, add:
    • App Groups
      • Select the same group as in the main target
    • Push Notifications The SDK uses Firebase Cloud Messaging to handle push notifications from the GetResponse App. 
  1. Follow the steps in the official Firebase guide to add Firebase to your project. You only need the FirebaseMessaging package.
    • Note: Initialising Firebase in your app is covered in the code snippets below. 
  2. Upload your APN keys to Firebase.

Usage

Managing consent

  • Create a NotificationManager class – you will use it to manage notifications permission and request a token used for subscribing users to notifications.
@MainActor
class NotificationManager: ObservableObject{
    @Published private(set) var hasPermission = false
    @Published var token: String?
    
    init() {
        Task{
            await getAuthStatus()
        }
    }
    
    func request() async{
        do {
            try await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound])
            await getAuthStatus()
        } catch{
            print(error)
        }
    }
    
    func requestToken() {
        Messaging.messaging().token { token, error in
          if let error = error {
            print("Error fetching FCM registration token: \(error)")
          } else if let token = token {
            print("FCM registration token: \(token)")
              self.token  = token
          }
        }
    }
    
    func getAuthStatus() async {
        let status = await UNUserNotificationCenter.current().notificationSettings()
        switch status.authorizationStatus {
        case .authorized, .ephemeral, .provisional:
            hasPermission = true
        default:
            hasPermission = false
        }
    }
}

  • Extend the AppDelegate class to fully support token registration and sending tokens to GetResponse.
    • Go to app.getresponse.com > Web Push Notifications > Mobile apps to get the Application ID, Secret, and Entrypoint
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
  func application(_ application: UIApplication,
                    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        application.registerForRemoteNotifications()
        FirebaseApp.configure()
        Messaging.messaging().delegate = self
        UNUserNotificationCenter.current().delegate = self
        GetResponsePushNotificationService.shared.configure(secret: /*secret*/, applicationId:/*applicationId*/, entrypoint: /*entrypoint*/)
        return true
    }
 
    
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
          Messaging.messaging().apnsToken = deviceToken
      }
      
      
    @objc func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        guard let token = fcmToken else {
            return
        }
        let tokenDict = ["token": fcmToken ?? ""]
        NotificationCenter.default.post(
          name: Notification.Name("FCMToken"),
          object: nil,
          userInfo: tokenDict)
      }
}

  • Create an instance of the NotificationManager in your main view to use across the app   

@StateObject var notificationManager = NotificationManager()
Available methods
  • Request system notification permission
await notificationManager.request()
  • Check system notification permission status
notificationManager.hasPermission

Note that the notificationManager.hasPermission  is a @Published  property

  • Request and access the registration token to send targeted notifications to any particular instance of your app
notificationManager.requestToken()
notificationManager.token

Note that the notificationManager.token  is a @Published  property

The registration token may change when:

  • The app is restored on a new device
  • The user uninstalls/reinstalls the app
  • The user clears app data
  • Consent to the notifications in GetResponse with the registration token in GetResponse
await GetResponsePushNotificationService.shared.consent(lang:/*LanguageCode*/, externalId: /*externalId*/, email: \*email*\, fcmToken: notificationManager.token!)

The consent expires after 4 weeks. Refresh the consent on every app run to prevent it from being revoked.

  • lang  – user language
  • externalId  – custom unique user ID
  • email  – optional user email
  • Remove the consent to stop sending notifications (e.g. on logout)
await GetResponsePushNotificationService.shared.removeConsent()

Handling GetResponse notifications

To access all data in the incoming notification use the method below. It automatically sends statistics about the state of the notification lifecycle (see Handling notification statistics).

GetResponsePushNotificationService.shared.handleIncomingNotification(userInfo: /* userInfo */, eventType: /*EventType*/)

It returns a NotificationHandler object.

public struct NotificationHandler {
    public let title: String
    public let body: String
    public let imageURL: String?
    public let action: ActionType
    public let redirectionURL: String?
    public let deeplinkPath: String?
    public let customData: [String: String]
}
  • title – title of notification
  • body – message body of notification
  • imageURL – image url of notification (optional)
  • action – selected action on notification tap (see Handling actions)
public enum ActionType {
    case openApp
    case openURL
    case deeplink
}
  • redirectionURL  – URL to open for openURL action
  • deeplinkPath – path of deeplink for deeplink action
  • customData  – map (key, value) of custom properties that can be configured in notification settings in the GetResponse App

Handling actions

There are 3 types of actions:

  • open application
  • open URL
  • open deeplink

Open deeplink action requires additional configuration. You can access the deeplink path through the NotificationHandler.deeplinkPath and use it to redirect the user manually after they click the notification.

Modifying notifications before they are shown

You can modify the content of the incoming notifications with the NotificationService from the Notification Service Extension target. In the following code, it is used for handling the notification’s showed statistics.

class NotificationService: UNNotificationServiceExtension {
    ...
 
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        if let bestAttemptContent = bestAttemptContent {
            let _ = try? GetResponsePushNotificationService.handleIncomingNotification(userInfo: bestAttemptContent.userInfo, eventType: EventType.showed)
            Messaging.serviceExtension().populateNotificationContent(bestAttemptContent, withContentHandler: contentHandler)
        }
    }
    
    ...
}

Handling notification click

To handle a notification being clicked, add the following code to your AppDelegate class. This code also handles the notification’s clicked statistics.

   func userNotificationCenter(
      _ center: UNUserNotificationCenter,
      willPresent notification: UNNotification,
      withCompletionHandler completionHandler:
      @escaping (UNNotificationPresentationOptions) -> Void
    ) {
      completionHandler([[.banner, .sound]])
    }
    func userNotificationCenter(
      _ center: UNUserNotificationCenter,
      didReceive response: UNNotificationResponse,
      withCompletionHandler completionHandler: @escaping () -> Void
    ) {
        let userInfo = response.notification.request.content.userInfo
        let notification = try? GetResponsePushNotificationService.shared.handleIncomingNotification(userInfo: userInfo, eventType: EventType.clicked)
        completionHandler()
}

Handling notification statistics

There are 3 types of notification statistics:

  • showed
    • can be tracked in the didReceive  method of the UNNotificationServiceExtension  class (see Modifying notifications before they are shown)
  • clicked
    • can be tracked in the userNotificationCenter method of the AppDelegate class (see Handling notification click)
  • closed

To send notification statistics to GetResponse use the following method:

GetResponsePushNotificationService.shared.handleIncomingNotification(userInfo: /* userInfo */, eventType: /*EventType*/)