How to set up iOS SDK for your native app push?

Do you have an iOS application where you want to add push notifications? In this tutorial, we will show you how to integrate PushEngage with your iOS application. Let’s understand step by step how to get started with iOS app push notifications.

Configuring the App

You can go through the below steps to enable your App to receive push notifications.

  1. Select Root project. Then navigate to Main App target > Signing & Capabilities > All.
  2. Next, you need to check if the Background Modes capability is added, if it is not added then search for it and add it from “+ Capability”.
  3. You should also confirm if Push Notifications capability is added, If it is not added search for it and add it from “+ Capability”.

Do you not see the Push Notifications option in capability? You can also enable it from Apple Developer’s account.

If you did not see the Push Notifications option in capability then you can also enable it from Apple Developer’s account. The next section talks about it. Please skip if you have enabled it.

  • Go to the Apple developer account.
  • Navigate to Certificate, identifier and profile > select identifier > Select bundle ID of iOS App > Edit your APP ID Config > Enable Push Notifications

  • Try again to add the Push Notifications capability to the project.

Note: If you are using the latest Xcode version it will give you an auto signing option if you have provided your developer account details to Xcode.

4. Next you need to enable Remote notifications & Background fetch. You can navigate to Background Modes > Remote notifications and  Background Modes > Background fetch to add them.

Integrating PushEngage iOS SDK

If cocoa pods is not available,

  1. Close your current xcode project.
  2. In the project root, run sudo gem install cocoapods to install Cocoapods.

Skip the above steps if Cocoapods is already installed,

  1. Run pod init from the terminal in your project directory.
  2. Open the newly created Podfile.
  3. Add the PushEngage dependency under your project name target as shown below.
target 'PEDemo' do
  pod 'PushEngage'
  post_install do |installer|
    installer.pods_project.targets.each do |target|
      target.build_configurations.each do |config|
        config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO'
      end
    end
  end

4. Run the following commands in your terminal in your project directory.

pod repo update
pod install

5. Open the newly created <project-name>.xcworkspace file. 

Note: Make sure to always open the .xcworkspace for opening the project in xcode from now onwards.

Initialising PushEngage iOS SDK

Navigate to your AppDelegate file and add the PushEngage initialization code to didFinishLaunchingWithOptions.

Make sure to import the PushEngage headers:

  • Swift: import PushEngage
  • Objective-C:  @import PushEngage;

Swift :

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    
    override init() {
        super.init()
       PushEngage.swizzleInjection(isEnabled: true)
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        PushEngage.setAppId(key: "APP_ID_FROM_PUSH_ENGAGE_DASHBOARD")
        PushEngage.startNotificationServices(for: application,
                                             with: launchOptions)
        
        PushEngage.enableLogs = true
        return true
    }
}

Note: If you are using SwitUI Appdelegate won’t be available by default, you have to initialize in your App file as given below.

SwiftUI Code

import SwiftUI
import PushEngage

@main
struct PEDemoApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class AppDelegate: NSObject, UIApplicationDelegate {
    
    override init() {
        super.init()
        PushEngage.swizzleInjection(isEnabled: true)
    }
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        PushEngage.setAppId(key: "APP_ID_FROM_PUSH_ENGAGE_DASHBOARD")
        PushEngage.startNotificationServices(for: application,
                                             with: launchOptions)
        
        PushEngage.enableLogs = true
        return true
    }
}

Note: PushEngageService.enableLogs provides the logs if enabled. Make sure to set false for the production build.

Objective C

@implementation AppDelegate


- (instancetype)init
{
    self = [super init];
    if (self) {
       [PushEngage swizzleInjectionWithIsEnabled: YES];
    }
    return self;
}
-(BOOL)application:(UIApplication*)application  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [PushEngage setAppIdWithKey:@"APP_ID_FROM_PUSH_ENGAGE_DASHBOARD"];
    [PushEngage startNotificationServicesFor:application with:launchOptions];
    [PushEngage setEnableLogs:true];
    return YES;
}

@end

Create Notification Service Extension

The NotificationServiceExtension allows your iOS application to receive rich notifications with images, buttons, and badges. 

  1.  In Xcode Select File > New > Target
  2.  Select Notification Service Extension then press Next.
  1. Enter the product name as PushEngageNotificationServiceExtension press Finish. 
  1. Do not select Activate on the dialog that is shown after selecting Finish.

Note: By canceling, you are keeping Xcode debugging your app, instead of the extension you just created.If you are activated by accident, you can switch back to debug your app within Xcode (next to the play button).

  1. In the project navigator, select the top-level project directory and select the PushEnagageNotificationServiceExtension target in the project and targets list.
  2. Set the Deployment Target to be iOS 10 which is the version of iOS that Apple released Rich Media for push. 

Note: iOS versions under 10 will not be able to get Rich Media.

Initialise PushEngage Sdk for Notification Service Extension:

  1. To set up the SDK in Notification service extension we need to add dependency of pushengage to the  notification Service extension target. 
  2. Open the Podfile and add the code as shown below.
target 'PEDemo' do
      pod 'PushEngage'
      post_install do |installer|
          installer.pods_project.targets.each do |target|
            target.build_configurations.each do |config|
              config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO'
          end
        end
      end
      
      target 'PushEngageNotificationServiceExtension' do
              pod 'PushEngage'
      end
end

3. Run the following commands in your terminal in your project directory.

1 pod repo update
2 pod install

4. Import PushEngage in your PushEngageNotificationServiceExtension and add the following code snippet.

Swift code

import UserNotifications
import PushEngage

@available(iOSApplicationExtension 10.0, *)
class PushEngageNotificationServiceExtension: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?
    var request : UNNotificationRequest?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.request = request
        self.contentHandler = contentHandler
        self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestContent = bestAttemptContent {
            PushEngage.didReceiveNotificationExtensionRequest(request, bestContentHandler: bestContent)
            contentHandler(bestContent)
        }
    }
    
    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 request = request ,let bestAttemptContent =  bestAttemptContent {
            guard let content = PushEngage.serviceExtensionTimeWillExpire(request, content: bestAttemptContent) else {
                contentHandler(bestAttemptContent)
                return
            }
            contentHandler(content)
        }
    }

}

Add App Groups

App Groups allow your app to execute code when a notification is received and share data between the main target and extensions so that when the app gets in the background And notification service extension modifies the contents of notifications and gets the shared data. And It helps to manage the badges and Confirm the delivery of notifications. 

  1. If you have created an app group please provide the name of the group in your application info plist with key PushEngage_App_Group_Key.
  2. if you are not having any group or using please make one group in this format “group._applicationName_.pushEngage”

Note: Provide the name of the application name in place of _applicationName_

  1. Make sure you select the same app group in both Main Application Target and the PushEngageNotificationServiceExtension.

PushEngageNotificationServiceExtension

Main Application Target

App is ready to Receive Notifications from the PushEngage Dashboard.

Deep Linking:

DeepLinks enables your subscriber to redirect to the specific screen inside the Application or redirect to a particular webpage. 

  • If you provide a url then we would redirect to that web page by default.

Handling Web URLs:

  • Provide the PushEngageInAppEnabled to 1 in Info.plist, then the URL will load within the application using WKWebview.
  • Provide the PushEngageInAppEnabled to 0 in Info.plist, if you want your subscriber to redirect to safari to load the URL.

Note: If the key is not provided then the user will be redirected to safari only.

If you provide a string that is not a URL, then we should configure navigation using setNotificationOpenHandler in the AppDelegate within the didFinishLaunchingWithOptions method to navigate to any screen based on the string provided as shown below.

Swift Code

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    
    override init() {
        super.init()
        // method Swizzling enabled for the application.
      PushEngage.swizzleInjection(isEnabled: true)
    }

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

     PushEngage.setAppId(key: "APP_ID_FROM_PUSH_ENGAGE_DASHBOARD")
     PushEngage.startNotificationServices(for: application,
                                             with: launchOptions)
        
        
     // Notification open handler.
     // deep linking screen
     PushEngage.setNotificationOpenHandler { (result) in
            let additionData = result.notification.additionalData
            if result.notificationAction.actionID == "ShoesScreen" {
                print(additionData ?? [])
                let storyBoard = UIStoryboard(name: "Main", bundle: .main)
                let viewController = storyBoard.instantiateViewController(withIdentifier: "SportViewController")
                let navcontroller = application.windows.first?.rootViewController as? UINavigationController
                navcontroller?.popToRootViewController(animated: true)
                navcontroller?.pushViewController(viewController, animated: true)
            } else if result.notificationAction.actionID == "SalesScreen" {
      let storyBoard = UIStoryboard(name: "Main", bundle: .main)
     let viewController = storyBoard.instantiateViewController(withIdentifier: "NotificationApiTestViewconttoller")
                let navcontroller = application.windows.first?.rootViewController as? UINavigationController
                navcontroller?.popToRootViewController(animated: true)
                navcontroller?.pushViewController(viewController, animated: true)
            } else if result.notificationAction.actionID == "pepay" {
                let storyBoard = UIStoryboard(name: "Main", bundle: .main)
                let viewController = storyBoard.instantiateViewController(withIdentifier: "PEPay")
                let navcontroller = application.windows.first?.rootViewController as? UINavigationController
                navcontroller?.popToRootViewController(animated: true)
                navcontroller?.pushViewController(viewController, animated: true)
            }
        }
        
        PushEngage.enableLogs = true
        
        return true
    }
}

Objective C

@implementation AppDelegate


- (instancetype)init
{
    self = [super init];
    if (self) {
       [PushEngage swizzleInjectionWithIsEnabled: YES];
    }
    return self;
}

typedef void (^PEnotificationOpenHandler)(PENotificationOpenResult * nonnull);

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    UNUserNotificationCenter.currentNotificationCenter.delegate = self;
    PEnotificationOpenHandler actionHandler = ^void(PENotificationOpenResult *result) {
        if ([result.notificationAction.actionID isEqualToString: @"ShoesScreen"]) {
            AddToCart *controller = [AddToCart new];
            UINavigationController *navigationController = (UINavigationController *) application.windows.firstObject.rootViewController;
            [navigationController popToRootViewControllerAnimated:YES];
            [navigationController pushViewController:controller animated:YES];
        } else if ([result.notificationAction.actionID isEqualToString: @"SalesScreen"]) {
            SportsViewcontroller *controller = [SportsViewcontroller new];
            UINavigationController *navigationController = (UINavigationController *) application.windows.firstObject.rootViewController;
            [navigationController popToRootViewControllerAnimated:YES];
            [navigationController pushViewController:controller animated:YES];
        }
    };
    application.applicationIconBadgeNumber = 0;
    [PushEngage setAppIdWithKey:@"APP_ID_FROM_PUSH_ENGAGE_DASHBOARD"];
    [PushEngage startNotificationServicesFor:application with:launchOptions];
    [PushEngage setNotificationOpenHandlerWithBlock:actionHandler];
    [PushEngage setEnableLogs:true];
    return YES;
}
@end

Handle Notifications in Foreground:

When notifications come in the foreground you have to make a decision whether or not to show the notification alert to the device.To handle notifications in the foreground use the setNotificationWillShowInForgroundHandler

If the completion block is not called by you at all SDK will call the completion block after 29 sec.

In any case silent or alert notification when the application is in foreground mode.

Swift code

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    
    override init() {
        super.init()
        // method Swizzling enabled for the application.
       PushEngage.swizzleInjection(isEnabled: true)
    }

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

        PushEngage.setAppId(key: "APP_ID_FROM_PUSH_ENGAGE_DASHBOARD")
        PushEngage.startNotificationServices(for: application,
                                             with: launchOptions)
        
        // Notification handler when notification deliver's and app is in foreground.
        
        PushEngage.setNotificationWillShowInForgroundHandler { notification, completion in
            if notification.contentAvailable == 1 {
                // in case the developer failed to set the completion handler. After 29 sec the handler will call from the SDK after 29 sec.
                completion(nil)
            } else {
                completion(notification)
            }
        }
        
        PushEngage.enableLogs = true
        
        return true
    }
}

Objective c

@implementation AppDelegate


- (instancetype)init
{
    self = [super init];
    if (self) {
       [PushEngage swizzleInjectionWithIsEnabled: YES];
    }
    return self;
}
// please create this handlers 
typedef void (^ _Nonnull PENotificationDisplayHandler)(PENotification * _Nullable);

-(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    UNUserNotificationCenter.currentNotificationCenter.delegate = self;
    
    [PushEngage setNotificationWillShowInForgroundHandlerWithBlock:^(PENotification * _Nonnull notification,
                                                                     PENotificationDisplayHandler completion) {
        if (notification.contentAvailable == 1) {
            completion(nil);
        } else {
            completion(notification);
        }
    }];
    [PushEngage setAppIdWithKey:@"APP_ID_FROM_PUSH_ENGAGE_DASHBOARD"];
    [PushEngage startNotificationServicesFor:application with:launchOptions];
    [PushEngage setEnableLogs:true];
    return YES;
}
@end

Handle Silent Push Notifications:

iOS provides a great feature of the silent push notification in which if your application is not killed or out of the memory you can send a silent push from the dashboard. 

Send content-available = 1 from the dashboard without title, message, and sound. It will wake your app in the background and you can perform any task, for example, updating local data with API call or do sync before your subscriber opens the app, etc. 

Use the method PushEngage.silentPushHandler to handle the silent push notification.

Swift

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    
    override init() {
        super.init()
        // method Swizzling enabled for the application.
       PushEngage.swizzleInjection(isEnabled: true)
    }

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

        PushEngage.setAppId(key: "APP_ID_FROM_PUSH_ENGAGE_DASHBOARD")
        PushEngage.startNotificationServices(for: application,
                                             with: launchOptions)
        
        PushEngage.silentPushHandler { notification , completion  in
            // note:- in case the developer failed to set the completion handler. After 29 sec the handler will call and set.
            completion?(.newData)
        }
        
        PushEngage.enableLogs = true
        
        return true
    }
}

Objective C

@implementation AppDelegate


- (instancetype)init
{
    self = [super init];
    if (self) {
       [PushEngage swizzleInjectionWithIsEnabled: YES];
    }
    return self;
}

typedef void (^ _Nullable SilentPushHandler)(UIBackgroundFetchResult);

-(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    UNUserNotificationCenter.currentNotificationCenter.delegate = self;
    
    
    [PushEngage silentPushHandler:^(PENotification * _Nonnull notification, SilentPushHandler completionblock) {
        // use notification info for your updates of local storage or sync if needed.
        // and please ensure to set completionblock
        completionblock(UIBackgroundFetchResultNewData);
    }];
    
    application.applicationIconBadgeNumber = 0;
    [PushEngage setAppIdWithKey:@"APP_ID_FROM_PUSH_ENGAGE_DASHBOARD"];
    [PushEngage startNotificationServicesFor:application with:launchOptions];
    [PushEngage setEnableLogs:true];
    return YES;
}
@end

If you are having any trouble with the installation of the iOS SDK then we can arrange a call with our product team. Please write to us at care@pushengage.com.

Still stuck? How can we help?
Last updated on November 10th, 2021

Engage and Retain Visitors AfterThey’ve Left Your Website

Increase the value of every web visit with Push Notifications that are hard to miss.

  • Forever Free Plan
  • Easy Setup
  • 5 Star Support