iOS: Extensions Framework

Description of the Extensions Framework and how to integrate it.

The iOS Extensions Framework is a new addition to the Sailthru Mobile iOS SDK that allows apps to save events in app extensions - https://developer.apple.com/app-extensions/.

Extensions only have access to a limited set of the iOS APIs, so it's not possible to use the main Sailthru Mobile iOS SDK Framework in an extension. To solve this we have developed the Extensions Framework specifically to operate in app extensions in order to allow you to properly integrate them with the Sailthru Mobile platform.

App Groups

In order for the Extension Framework to communicate with the main Sailthru Mobile iOS SDK your app needs to set up an App Group (https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups?language=objc).

App groups allow apps and extensions to share an NSUserDefaults instance. You can set up an App Group in the Apple Developer site (https://developer.apple.com/) in the Certificates, Identities and Profiles section.

13331333

You can then add the App Group in the Capabilities tab in your app settings.

📘

Note

Both the main app and the extension will need to have the App Group Capability added and the same App Group must be active on both targets.

Adding the Extensions Framework

Swift Package Manager

If you are using Swift Package Manager you will see the extension SDK as an option to add to your project when you add SailthruMobile as a dependency. This will add it automatically to your main app target. You should then manually add it to the list of linked binaries in your extensions targets.

Cocoapods

If you are using Cocoapods you should add the Extension Framework to your main app target and to any extension targets like so:

target 'YourAppExtension' do
    pod 'SailthruMobile-Extension', '12.0.0'
end

The extension is a subspec of the main SDK pod so it will be automatically added to your main app target.

Carthage

If you import the SDK as normal using Carthage you will notice that the SailthruMobile.framework file contains both the main SailthruMobile.xcframework and the SailthruMobileExtension.xcframework. You should add both frameworks to your main app and the extensions framework to any app extensions that you plan to use it in.

Manually

If you add the Frameworks manually then you will find the SailthruMobileExtension.framework bundled next to the main SailthruMobile.framework. You should ensure this is added to your Extension target and to your app target.

📘

Note

The Extensions Framework needs to be embedded in your main app target as well as added to the Extension Target. If you are not setting up the SDK with Cocoapods you must ensure the Extension Framework is added to both targets.

Setting up the Framework

Once the Extensions Framework has been added you will need to initialize it both in the main app and in the extension.

Main App

In the main app you simply need to register any shared App Groups that you have created:

[[SailthruMobile new] registerExtensionGroups:@[@"group.your.group.name"]];
SailthruMobile().registerExtensionGroups(["group.your.group.name"])

If you want to use different app groups for different extensions you will need to register all the app groups in the array provided here.

Extensions

The Extensions Framework is primarily designed to work with the UNNotificationServiceExtension and UNNotificationContentExtension extensions.

UNNotificationServiceExtension

In order to simplify the UNNotificationServiceExtension integration we have created our own implementation that you can use to quickly and easily set up both the Extensions Framework and Rich Push Notification handling:

#import "NotificationService.h"
#import <SailthruMobileExtension/STMNotificationServiceExtension.h>

@interface NotificationService ()

@property (nonatomic, strong) STMNotificationServiceExtension *stmServiceExtension;

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
  
    // setup sailthru service extension
    self.stmServiceExtension = [[STMNotificationServiceExtension alloc] initWithAppKey:@"YOUR_APP_KEY" andGroupName:@"group.your.group.name"];
    
    // handle notification request
    [self.stmServiceExtension didReceiveNotificationRequest:request withContentHandler:contentHandler];
}

- (void)serviceExtensionTimeWillExpire {
    // handle extension timeout
    [self.stmServiceExtension serviceExtensionTimeWillExpire];
}

@end
import UserNotifications
import SailthruMobileExtension

class NotificationService: UNNotificationServiceExtension {
    var sailthruNotificationServiceExtension : STMNotificationServiceExtension?
    
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler:@escaping (UNNotificationContent) -> Void) {
    
        // setup sailthru service extension
        self.sailthruNotificationServiceExtension = STMNotificationServiceExtension(appKey: "YOUR_APP_KEY", andGroupName: "group.your.group.name")
        
        // handle notification request
        self.sailthruNotificationServiceExtension?.didReceive(request, withContentHandler: contentHandler)
    }
    
    override func serviceExtensionTimeWillExpire() {
            // handle extension timeout
      self.sailthruNotificationServiceExtension?.serviceExtensionTimeWillExpire()
    }
}

However, if you would prefer to set up your service extension manually then you can include and use the SailthruMobileExtension class directly:

@property (nullable, nonatomic, strong) SailthruMobileExtension *extension;
@property (nullable, nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    
    // retrieve instance for app group
    self.extension = [[SailthruMobileExtension alloc] initWithAppKey:@"YOUR_APP_KEY" groupName:@"group.your.group.name"];
  
    // handle notification request
    [self.extension handleNotificationRequest:request];
    
    // Register any custom events
        [self.extension logEvent:@"my event"];
  
    // Continue as normal
}
var extension : SailthruMobileExtension?
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
var downloadTask: URLSessionDownloadTask?

override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler:@escaping (UNNotificationContent) -> Void) {
    self.contentHandler = contentHandler
    self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
    
    self.extension = SailthruMobileExtension(appKey: "YOUR_APP_KEY", groupName: "group.your.group.name")
  
    // handle notification request
    self.extension?.handleNotificationRequest(request)
    
    // Register any custom events
        self.extension?.logEvent("my event")
  
    // Continue as normal
}

UNNotificationContentExtension

In the UNNotificationContentExtension you should start the engine and retrieve the instance in the viewDidLoad method and the use the extension to handle the notification when it is received:

@property (strong, nonatomic) SailthruMobileExtension *extension;

@implementation NotificationViewController

- (void)viewDidLoad {
    [super viewDidLoad];
  
    self.extension = [[SailthruMobileExtension alloc] initWithAppKey:@"YOUR_APP_KEY" groupName:@"group.your.group.name"];
}

- (void)didReceiveNotification:(UNNotification *)notification {
    // handle notification
    [self.extension handleNotification:notification];
  
    // Register any custom events
        [self.extension logEvent:@"my event"];
    
    // Continue as normal
}
var extension : SailthruMobileExtension?

@implementation NotificationViewController

override func viewDidLoad() {
    super.viewDidLoad()
  
    self.extension = SailthruMobileExtension(appKey: "YOUR_APP_KEY", groupName: "group.your.group.name")
}

- (void)didReceiveNotification:(UNNotification *)notification {
    // handle notification
    self.extension?.handleNotification(notification)
  
    // Register any custom events
        self.extension?.logEvent("my event")
    
    // Continue as normal
}

Did this page help you?