{"metadata":{"image":[],"title":"","description":""},"api":{"url":"","auth":"required","results":{"codes":[]},"settings":"","params":[]},"next":{"description":"","pages":[]},"title":"iOS: Extensions Framework","type":"basic","slug":"ios-extensions-framework","excerpt":"Description of the Extensions Framework and how to integrate it.","body":"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/](https://developer.apple.com/app-extensions/).\n\nExtensions 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.\n\n# App Groups\nIn 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](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups?language=objc)).\n\nApp 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/](https://developer.apple.com/)) in the Certificates, Identities and Profiles section.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/f71d09a-Screen_Shot_2019-06-11_at_4.30.18_PM.png\",\n        \"Screen Shot 2019-06-11 at 4.30.18 PM.png\",\n        1333,\n        228,\n        \"#f9f9f9\"\n      ]\n    }\n  ]\n}\n[/block]\nYou can then add the App Group in the Capabilities tab in your app settings.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Note\",\n  \"body\": \"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.\"\n}\n[/block]\n# Adding the Extensions Framework\n## Cocoapods\nIf you are using Cocoapods you can add the Extension Framework to your extension target directly like so:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"target 'YourAppExtension' do\\n    pod 'SailthruMobile/Extension', '8.3.0'\\nend\",\n      \"language\": \"ruby\"\n    }\n  ]\n}\n[/block]\nThe extension is a subspec of the main SDK pod so it will be automatically added to your main app target.\n\n## Carthage\nIf you import the SDK as normal using Carthage you will notice that the SailthruMobile.framework file contains both the main SailthruMobile.framework and the SailthruMobileExtension.framework. You should add both frameworks to your main app and the extensions framework to any app extensions that you plan to use it in.\n\n## Manually\nIf 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.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Note\",\n  \"body\": \"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.\"\n}\n[/block]\n# Setting up the Framework\nOnce the Extensions Framework has been added you will need to initialize it both in the main app and in the extension.\n\n## Main App\nIn the main app you simply need to register any shared App Groups that you have created:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[SailthruMobile new] registerExtensionGroups::::at:::[@\\\"group.your.group.name\\\"]];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"SailthruMobile().registerExtensionGroups([\\\"group.your.group.name\\\"])\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    }\n  ]\n}\n[/block]\nIf you want to use different app groups for different extensions you will need to register all the app groups in the array provided here.\n\n## Extensions\nThe Extensions Framework is primarily designed to work with the UNNotificationServiceExtension and UNNotificationContentExtension extensions.\n\n### UNNotificationServiceExtension\nIn 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:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import \\\"NotificationService.h\\\"\\n#import <SailthruMobileExtension/STMNotificationServiceExtension.h>\\n\\[email protected] NotificationService ()\\n\\[email protected] (nonatomic, strong) STMNotificationServiceExtension *stmServiceExtension;\\n\\[email protected]\\n\\[email protected] NotificationService\\n\\n- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {\\n  \\n    // setup sailthru service extension\\n    self.stmServiceExtension = [[STMNotificationServiceExtension alloc] initWithAppKey:@\\\"YOUR_APP_KEY\\\" andGroupName:@\\\"group.your.group.name\\\"];\\n  \\t\\n  \\t// handle notification request\\n    [self.stmServiceExtension didReceiveNotificationRequest:request withContentHandler:contentHandler];\\n}\\n\\n- (void)serviceExtensionTimeWillExpire {\\n  \\t// handle extension timeout\\n    [self.stmServiceExtension serviceExtensionTimeWillExpire];\\n}\\n\\[email protected]\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"import UserNotifications\\nimport SailthruMobileExtension\\n\\nclass NotificationService: UNNotificationServiceExtension {\\n    var sailthruNotificationServiceExtension : STMNotificationServiceExtension?\\n    \\n    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler:@escaping (UNNotificationContent) -> Void) {\\n    \\n        // setup sailthru service extension\\n        self.sailthruNotificationServiceExtension = STMNotificationServiceExtension(appKey: \\\"YOUR_APP_KEY\\\", andGroupName: \\\"group.your.group.name\\\")\\n        \\n        // handle notification request\\n        self.sailthruNotificationServiceExtension?.didReceive(request, withContentHandler: contentHandler)\\n    }\\n    \\n    override func serviceExtensionTimeWillExpire() {\\n    \\t\\t// handle extension timeout\\n      self.sailthruNotificationServiceExtension?.serviceExtensionTimeWillExpire()\\n    }\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    }\n  ]\n}\n[/block]\nHowever, if you would prefer to set up your service extension manually then you can include and use the SailthruMobileExtension class directly:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@property (nullable, nonatomic, strong) SailthruMobileExtension *extension;\\[email protected] (nullable, nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);\\[email protected] (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;\\[email protected] (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;\\n\\n- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {\\n    self.contentHandler = contentHandler;\\n    self.bestAttemptContent = [request.content mutableCopy];\\n    \\n  \\t// retrieve instance for app group\\n    self.extension = [[SailthruMobileExtension alloc] initWithAppKey:@\\\"YOUR_APP_KEY\\\" groupName:@\\\"group.your.group.name\\\"];\\n  \\n  \\t// handle notification request\\n    [self.extension handleNotificationRequest:request];\\n    \\n    // Register any custom events\\n\\t\\t[self.extension logEvent:@\\\"my event\\\"];\\n  \\n  \\t// Continue as normal\\n}\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"var extension : SailthruMobileExtension?\\nvar contentHandler: ((UNNotificationContent) -> Void)?\\nvar bestAttemptContent: UNMutableNotificationContent?\\nvar downloadTask: URLSessionDownloadTask?\\n\\noverride func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler:@escaping (UNNotificationContent) -> Void) {\\n    self.contentHandler = contentHandler\\n    self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)\\n    \\n    self.extension = SailthruMobileExtension(appKey: \\\"YOUR_APP_KEY\\\", groupName: \\\"group.your.group.name\\\")\\n  \\n  \\t// handle notification request\\n    self.extension?.handleNotificationRequest(request)\\n    \\n    // Register any custom events\\n\\t\\tself.extension?.logEvent(\\\"my event\\\")\\n  \\n  \\t// Continue as normal\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    }\n  ]\n}\n[/block]\n### UNNotificationContentExtension\nIn 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:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@property (strong, nonatomic) SailthruMobileExtension *extension;\\n\\[email protected] NotificationViewController\\n\\n- (void)viewDidLoad {\\n    [super viewDidLoad];\\n  \\n    self.extension = [[SailthruMobileExtension alloc] initWithAppKey:@\\\"YOUR_APP_KEY\\\" groupName:@\\\"group.your.group.name\\\"];\\n}\\n\\n- (void)didReceiveNotification:(UNNotification *)notification {\\n  \\t// handle notification\\n    [self.extension handleNotification:notification];\\n  \\n  \\t// Register any custom events\\n\\t\\t[self.extension logEvent:@\\\"my event\\\"];\\n    \\n    // Continue as normal\\n}\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"var extension : SailthruMobileExtension?\\n\\[email protected] NotificationViewController\\n\\noverride func viewDidLoad() {\\n    super.viewDidLoad()\\n  \\n    self.extension = SailthruMobileExtension(appKey: \\\"YOUR_APP_KEY\\\", groupName: \\\"group.your.group.name\\\")\\n}\\n\\n- (void)didReceiveNotification:(UNNotification *)notification {\\n  \\t// handle notification\\n    self.extension?.handleNotification(notification)\\n  \\n  \\t// Register any custom events\\n\\t\\tself.extension?.logEvent(\\\"my event\\\")\\n    \\n    // Continue as normal\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"iOS (Swift)\"\n    }\n  ]\n}\n[/block]","updates":[],"order":7,"isReference":false,"hidden":false,"sync_unique":"","link_url":"","link_external":false,"_id":"5e6156bf5e4a51006dcd8185","project":"55e67aaa9cc7c62b00c4a1ea","version":{"version":"1.5","version_clean":"1.5.0","codename":"ST Rebrand","is_stable":true,"is_beta":false,"is_hidden":false,"is_deprecated":false,"categories":["5e6156bf5e4a51006dcd8120","5e6156bf5e4a51006dcd8121","5e6156bf5e4a51006dcd8122","5e6156bf5e4a51006dcd8123","5e6156bf5e4a51006dcd8124","561c61b4ad272c0d00a892df","586c014c0abf1d0f000d04d4","58991d2ad207df0f0002186b","5e6156bf5e4a51006dcd8125","5e6156bf5e4a51006dcd8126","5af0fe494ca2730003cbc98a","5af0fe55ec80af0003804ca2","5e69868cbd5dcb006b35867b","5e6986ca2c6652006791b6e8"],"_id":"5e6156bf5e4a51006dcd818c","project":"55e67aaa9cc7c62b00c4a1ea","__v":2,"forked_from":"5b720760c44b7600034b7a08","createdAt":"2015-09-02T04:27:23.612Z","releaseDate":"2015-09-02T04:27:23.612Z"},"category":{"sync":{"isSync":false,"url":""},"pages":[],"title":"iOS Techniques","slug":"ios-techniques","order":9999,"from_sync":false,"reference":false,"_id":"5e6986ca2c6652006791b6e8","createdAt":"2020-03-12T00:48:10.039Z","version":"5e6156bf5e4a51006dcd818c","project":"55e67aaa9cc7c62b00c4a1ea","__v":0},"user":"5b0b7a46a26e6400036604fd","createdAt":"2019-06-11T04:13:42.592Z","__v":0,"parentDoc":null}

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/](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](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/](https://developer.apple.com/)) in the Certificates, Identities and Profiles section. [block:image] { "images": [ { "image": [ "https://files.readme.io/f71d09a-Screen_Shot_2019-06-11_at_4.30.18_PM.png", "Screen Shot 2019-06-11 at 4.30.18 PM.png", 1333, 228, "#f9f9f9" ] } ] } [/block] You can then add the App Group in the Capabilities tab in your app settings. [block:callout] { "type": "info", "title": "Note", "body": "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." } [/block] # Adding the Extensions Framework ## Cocoapods If you are using Cocoapods you can add the Extension Framework to your extension target directly like so: [block:code] { "codes": [ { "code": "target 'YourAppExtension' do\n pod 'SailthruMobile/Extension', '8.3.0'\nend", "language": "ruby" } ] } [/block] 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.framework and the SailthruMobileExtension.framework. 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. [block:callout] { "type": "info", "title": "Note", "body": "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." } [/block] # 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: [block:code] { "codes": [ { "code": "[[SailthruMobile new] registerExtensionGroups:@[@\"group.your.group.name\"]];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "SailthruMobile().registerExtensionGroups([\"group.your.group.name\"])", "language": "swift", "name": "iOS (Swift)" } ] } [/block] 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: [block:code] { "codes": [ { "code": "#import \"NotificationService.h\"\n#import <SailthruMobileExtension/STMNotificationServiceExtension.h>\n\[email protected] NotificationService ()\n\[email protected] (nonatomic, strong) STMNotificationServiceExtension *stmServiceExtension;\n\[email protected]\n\[email protected] NotificationService\n\n- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {\n \n // setup sailthru service extension\n self.stmServiceExtension = [[STMNotificationServiceExtension alloc] initWithAppKey:@\"YOUR_APP_KEY\" andGroupName:@\"group.your.group.name\"];\n \t\n \t// handle notification request\n [self.stmServiceExtension didReceiveNotificationRequest:request withContentHandler:contentHandler];\n}\n\n- (void)serviceExtensionTimeWillExpire {\n \t// handle extension timeout\n [self.stmServiceExtension serviceExtensionTimeWillExpire];\n}\n\[email protected]", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "import UserNotifications\nimport SailthruMobileExtension\n\nclass NotificationService: UNNotificationServiceExtension {\n var sailthruNotificationServiceExtension : STMNotificationServiceExtension?\n \n override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler:@escaping (UNNotificationContent) -> Void) {\n \n // setup sailthru service extension\n self.sailthruNotificationServiceExtension = STMNotificationServiceExtension(appKey: \"YOUR_APP_KEY\", andGroupName: \"group.your.group.name\")\n \n // handle notification request\n self.sailthruNotificationServiceExtension?.didReceive(request, withContentHandler: contentHandler)\n }\n \n override func serviceExtensionTimeWillExpire() {\n \t\t// handle extension timeout\n self.sailthruNotificationServiceExtension?.serviceExtensionTimeWillExpire()\n }\n}", "language": "swift", "name": "iOS (Swift)" } ] } [/block] However, if you would prefer to set up your service extension manually then you can include and use the SailthruMobileExtension class directly: [block:code] { "codes": [ { "code": "@property (nullable, nonatomic, strong) SailthruMobileExtension *extension;\[email protected] (nullable, nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);\[email protected] (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;\[email protected] (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;\n\n- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {\n self.contentHandler = contentHandler;\n self.bestAttemptContent = [request.content mutableCopy];\n \n \t// retrieve instance for app group\n self.extension = [[SailthruMobileExtension alloc] initWithAppKey:@\"YOUR_APP_KEY\" groupName:@\"group.your.group.name\"];\n \n \t// handle notification request\n [self.extension handleNotificationRequest:request];\n \n // Register any custom events\n\t\t[self.extension logEvent:@\"my event\"];\n \n \t// Continue as normal\n}", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "var extension : SailthruMobileExtension?\nvar contentHandler: ((UNNotificationContent) -> Void)?\nvar bestAttemptContent: UNMutableNotificationContent?\nvar downloadTask: URLSessionDownloadTask?\n\noverride func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler:@escaping (UNNotificationContent) -> Void) {\n self.contentHandler = contentHandler\n self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)\n \n self.extension = SailthruMobileExtension(appKey: \"YOUR_APP_KEY\", groupName: \"group.your.group.name\")\n \n \t// handle notification request\n self.extension?.handleNotificationRequest(request)\n \n // Register any custom events\n\t\tself.extension?.logEvent(\"my event\")\n \n \t// Continue as normal\n}", "language": "swift", "name": "iOS (Swift)" } ] } [/block] ### 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: [block:code] { "codes": [ { "code": "@property (strong, nonatomic) SailthruMobileExtension *extension;\n\[email protected] NotificationViewController\n\n- (void)viewDidLoad {\n [super viewDidLoad];\n \n self.extension = [[SailthruMobileExtension alloc] initWithAppKey:@\"YOUR_APP_KEY\" groupName:@\"group.your.group.name\"];\n}\n\n- (void)didReceiveNotification:(UNNotification *)notification {\n \t// handle notification\n [self.extension handleNotification:notification];\n \n \t// Register any custom events\n\t\t[self.extension logEvent:@\"my event\"];\n \n // Continue as normal\n}", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "var extension : SailthruMobileExtension?\n\[email protected] NotificationViewController\n\noverride func viewDidLoad() {\n super.viewDidLoad()\n \n self.extension = SailthruMobileExtension(appKey: \"YOUR_APP_KEY\", groupName: \"group.your.group.name\")\n}\n\n- (void)didReceiveNotification:(UNNotification *)notification {\n \t// handle notification\n self.extension?.handleNotification(notification)\n \n \t// Register any custom events\n\t\tself.extension?.logEvent(\"my event\")\n \n // Continue as normal\n}", "language": "swift", "name": "iOS (Swift)" } ] } [/block]