{"_id":"5cff2a76c5972b0043825368","project":"55e67aaa9cc7c62b00c4a1ea","version":{"_id":"5b720760c44b7600034b7a08","project":"55e67aaa9cc7c62b00c4a1ea","__v":0,"forked_from":"5b1f2cbdfd653400031d8d9f","createdAt":"2015-09-02T04:27:23.612Z","releaseDate":"2015-09-02T04:27:23.612Z","categories":["5b720760c44b7600034b79a7","5b720760c44b7600034b79a8","5b720760c44b7600034b79a9","5b720760c44b7600034b79aa","5b720760c44b7600034b79ab","561c61b4ad272c0d00a892df","586c014c0abf1d0f000d04d4","58991d2ad207df0f0002186b","5b720760c44b7600034b79ac","5b720760c44b7600034b79ad","5af0fe494ca2730003cbc98a","5af0fe55ec80af0003804ca2"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"API V6","version_clean":"1.4.0","version":"1.4"},"category":{"_id":"5b720760c44b7600034b79ac","project":"55e67aaa9cc7c62b00c4a1ea","__v":0,"version":"5b720760c44b7600034b7a08","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2017-02-08T21:31:11.878Z","from_sync":false,"order":6,"slug":"advanced-techniques","title":"Advanced Techniques"},"user":"5b0b7a46a26e6400036604fd","__v":0,"parentDoc":null,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2019-06-11T04:13:42.592Z","link_external":false,"link_url":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":23,"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 'Carnival/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 Carnival.framework file contains both the main Carnival.framework and the CarnivalExtension.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 CarnivalExtension.framework bundled next to the main Carnival.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\": \"[Carnival registerExtensionGroups::::at:::[@\\\"group.your.group.name\\\"]];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"Carnival.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 <CarnivalExtension/CarnivalNotificationServiceExtension.h>\\n\\n@interface NotificationService ()\\n\\n@property (nonatomic, strong) CarnivalNotificationServiceExtension *carnivalServiceExtension;\\n\\n@end\\n\\n@implementation NotificationService\\n\\n- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {\\n  \\n    // setup carnival service extension\\n    self.carnivalServiceExtension = [[CarnivalNotificationServiceExtension alloc] initWithAppKey:@\\\"YOUR_APP_KEY\\\" andGroupName:@\\\"group.your.group.name\\\"];\\n  \\t\\n  \\t// handle notification request\\n    [self.carnivalServiceExtension didReceiveNotificationRequest:request withContentHandler:contentHandler];\\n}\\n\\n- (void)serviceExtensionTimeWillExpire {\\n  \\t// handle extension timeout\\n    [self.carnivalServiceExtension serviceExtensionTimeWillExpire];\\n}\\n\\n@end\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS (Objective-C)\"\n    },\n    {\n      \"code\": \"import UserNotifications\\nimport CarnivalExtension\\n\\nclass NotificationService: UNNotificationServiceExtension {\\n    var carnivalNotificationServiceExtension : CarnivalNotificationServiceExtension?\\n    \\n    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler:@escaping (UNNotificationContent) -> Void) {\\n    \\n        // setup carnival service extension\\n        self.carnivalNotificationServiceExtension = CarnivalNotificationServiceExtension(appKey: \\\"YOUR_APP_KEY\\\", andGroupName: \\\"group.your.group.name\\\")\\n        \\n        // handle notification request\\n        self.carnivalNotificationServiceExtension?.didReceive(request, withContentHandler: contentHandler)\\n    }\\n    \\n    override func serviceExtensionTimeWillExpire() {\\n    \\t\\t// handle extension timeout\\n      self.carnivalNotificationServiceExtension?.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 CarnivalExtension class directly:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@property (nullable, nonatomic, strong) CarnivalExtension *extension;\\n@property (nullable, nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);\\n@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;\\n@property (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// start engine with app key\\n    [CarnivalExtension startEngine:@\\\"YOUR_APP_KEY\\\"];\\n    \\n  \\t// retrieve instance for app group\\n    self.extension = [CarnivalExtension getInstanceForGroup:\\\"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 : CarnivalExtension?\\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\\t\\t// start engine with app key\\n\\t\\tCarnivalExtension.startEngine(\\\"YOUR_APP_KEY\\\")\\n    \\n    // retrieve instance for app group\\n    self.extension = CarnivalExtension.getInstanceForGroup(\\\"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) CarnivalExtension *extension;\\n\\n@implementation NotificationViewController\\n\\n- (void)viewDidLoad {\\n    [super viewDidLoad];\\n \\n  \\t// start engine with app key\\n    [CarnivalExtension startEngine:@\\\"YOUR_APP_KEY\\\"];\\n  \\n  \\t// retrieve instance for app group\\n    self.extension = [CarnivalExtension getInstanceForGroup:@\\\"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 : CarnivalExtension?\\n\\n@implementation NotificationViewController\\n\\noverride func viewDidLoad() {\\n    super.viewDidLoad()\\n \\n  \\t// start engine with app key\\n    CarnivalExtension.startEngine(\\\"YOUR_APP_KEY\\\")\\n  \\n  \\t// retrieve instance for app group\\n    self.extension = CarnivalExtension.getInstanceForGroup(\\\"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]","excerpt":"Description of the Extensions Framework and how to integrate it.","slug":"ios-extensions-framework","type":"basic","title":"iOS: Extensions Framework"}

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 'Carnival/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 Carnival.framework file contains both the main Carnival.framework and the CarnivalExtension.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 CarnivalExtension.framework bundled next to the main Carnival.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": "[Carnival registerExtensionGroups:@[@\"group.your.group.name\"]];", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "Carnival.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 <CarnivalExtension/CarnivalNotificationServiceExtension.h>\n\n@interface NotificationService ()\n\n@property (nonatomic, strong) CarnivalNotificationServiceExtension *carnivalServiceExtension;\n\n@end\n\n@implementation NotificationService\n\n- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {\n \n // setup carnival service extension\n self.carnivalServiceExtension = [[CarnivalNotificationServiceExtension alloc] initWithAppKey:@\"YOUR_APP_KEY\" andGroupName:@\"group.your.group.name\"];\n \t\n \t// handle notification request\n [self.carnivalServiceExtension didReceiveNotificationRequest:request withContentHandler:contentHandler];\n}\n\n- (void)serviceExtensionTimeWillExpire {\n \t// handle extension timeout\n [self.carnivalServiceExtension serviceExtensionTimeWillExpire];\n}\n\n@end", "language": "objectivec", "name": "iOS (Objective-C)" }, { "code": "import UserNotifications\nimport CarnivalExtension\n\nclass NotificationService: UNNotificationServiceExtension {\n var carnivalNotificationServiceExtension : CarnivalNotificationServiceExtension?\n \n override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler:@escaping (UNNotificationContent) -> Void) {\n \n // setup carnival service extension\n self.carnivalNotificationServiceExtension = CarnivalNotificationServiceExtension(appKey: \"YOUR_APP_KEY\", andGroupName: \"group.your.group.name\")\n \n // handle notification request\n self.carnivalNotificationServiceExtension?.didReceive(request, withContentHandler: contentHandler)\n }\n \n override func serviceExtensionTimeWillExpire() {\n \t\t// handle extension timeout\n self.carnivalNotificationServiceExtension?.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 CarnivalExtension class directly: [block:code] { "codes": [ { "code": "@property (nullable, nonatomic, strong) CarnivalExtension *extension;\n@property (nullable, nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);\n@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;\n@property (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// start engine with app key\n [CarnivalExtension startEngine:@\"YOUR_APP_KEY\"];\n \n \t// retrieve instance for app group\n self.extension = [CarnivalExtension getInstanceForGroup:\"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 : CarnivalExtension?\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\t\t// start engine with app key\n\t\tCarnivalExtension.startEngine(\"YOUR_APP_KEY\")\n \n // retrieve instance for app group\n self.extension = CarnivalExtension.getInstanceForGroup(\"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) CarnivalExtension *extension;\n\n@implementation NotificationViewController\n\n- (void)viewDidLoad {\n [super viewDidLoad];\n \n \t// start engine with app key\n [CarnivalExtension startEngine:@\"YOUR_APP_KEY\"];\n \n \t// retrieve instance for app group\n self.extension = [CarnivalExtension getInstanceForGroup:@\"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 : CarnivalExtension?\n\n@implementation NotificationViewController\n\noverride func viewDidLoad() {\n super.viewDidLoad()\n \n \t// start engine with app key\n CarnivalExtension.startEngine(\"YOUR_APP_KEY\")\n \n \t// retrieve instance for app group\n self.extension = CarnivalExtension.getInstanceForGroup(\"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]