Push Notifications
7 min
step 1 — add a notification service extension in xcode, go to file → new → target → notification service extension make sure you pick notification service extension — not notification content extension they look identical in the list product name appstorynotificationext language swift click finish → activate step 2 — enable app groups on both targets you need to enable app groups on two targets — your main app and the extension — using the same identifier choose an identifier in this format group com yourcompany yourapp for both targets (main app + appstorynotificationext) select the target → signing & capabilities click + capability → app groups add / tick the same identifier on both step 3 — link the framework to the nse target select the appstorynotificationext target go to general → frameworks and libraries → + add appstorys ios step 4 — nse code replace the contents of the auto generated notificationservice swift with this update the appgroup value to your identifier from step 2 import usernotifications import appstorys ios final class notificationservice unnotificationserviceextension { private static let appgroup = "group com yourcompany yourapp" // update this private var contenthandler ((unnotificationcontent) > void)? private var bestattempt unmutablenotificationcontent? override func didreceive( request unnotificationrequest, withcontenthandler contenthandler @escaping (unnotificationcontent) > void ) { self contenthandler = contenthandler self bestattempt = (request content mutablecopy() as? unmutablenotificationcontent) let userinfo = request content userinfo appstorysmessagingservice configureappgroup(self appgroup) = appstorysmessagingservice handlemessagereceivedblocking(userinfo userinfo) let imageurlstring = self extractimageurl(from userinfo) if let urlstring = imageurlstring, let url = url(string urlstring) { self downloadandattach(url url, to bestattempt) { \[weak self] in guard let self else { return } if let best = self bestattempt { contenthandler(best) } else { contenthandler(request content) } } } else { if let best = bestattempt { contenthandler(best) } else { contenthandler(request content) } } } // mark image helpers private static func extractimageurl(from userinfo \[anyhashable any]) > string? { if let fcmoptions = userinfo\["fcm options"] as? \[string any], let img = fcmoptions\["image"] as? string { return img } if let img = userinfo\["gcm notification image"] as? string { return img } if let notif = userinfo\["notification"] as? \[string any], let img = notif\["image"] as? string { return img } if let content = userinfo\["content"] as? \[string any], let img = content\["image"] as? string { return img } if let img = userinfo\["image"] as? string { return img } return nil } private static func downloadandattach( url url, to content unmutablenotificationcontent?, completion @escaping () > void ) { urlsession shared downloadtask(with url) { tempurl, , error in defer { completion() } guard let tempurl, error == nil else { return } let ext = url pathextension isempty ? "jpg" url pathextension let dest = tempurl deletinglastpathcomponent() appendingpathcomponent(uuid() uuidstring) appendingpathextension(ext) do { try filemanager default moveitem(at tempurl, to dest) let attachment = try unnotificationattachment( identifier "appstorys image", url dest, options nil ) content? attachments = \[attachment] } catch { } } resume() } override func serviceextensiontimewillexpire() { if let handler = contenthandler, let best = bestattempt { handler(best) } } } step 5 — appdelegate add or update your appdelegate with the code below update the appgroupid to match your identifier from step 2 import firebase import firebasemessaging import usernotifications import appstorys ios final class appdelegate nsobject, uiapplicationdelegate { static let appgroupid = "group com yourcompany yourapp" // update this func application( application uiapplication, didfinishlaunchingwithoptions \[uiapplication launchoptionskey any]? = nil ) > bool { firebaseapp configure() appstorysmessagingservice configureappgroup(self appgroupid) // must be before appstorys initialize messaging messaging() delegate = self unusernotificationcenter current() delegate = self unusernotificationcenter current() requestauthorization( options \[ alert, badge, sound] ) { , in } application registerforremotenotifications() return true } func application( uiapplication, didregisterforremotenotificationswithdevicetoken token data) { messaging messaging() apnstoken = token } } // mark this method is to use only when you want to set the token when the app initializes extension appdelegate messagingdelegate { func messaging( messaging, didreceiveregistrationtoken fcmtoken string?) { if let token = fcmtoken { appstorysmessagingservice handlenewtoken(token) } } } extension appdelegate unusernotificationcenterdelegate { func usernotificationcenter( unusernotificationcenter, willpresent notification unnotification, withcompletionhandler completionhandler @escaping (unnotificationpresentationoptions) > void ) { appstorysmessagingservice handlemessagereceived( userinfo notification request content userinfo ) completionhandler(\[ banner, list, sound]) } func usernotificationcenter( unusernotificationcenter, didreceive response unnotificationresponse, withcompletionhandler completionhandler @escaping () > void ) { appstorysmessagingservice handlenotificationclick( userinfo response notification request content userinfo ) completionhandler() } } with this in place, appstorys handles the delivery tracking, click tracking, and rendering side of things for you — you just forward the firebase cloud messaging (fcm) token and delegate callbacks as shown above call appstorys shared setfirebasetoken(token) whenever you have an fcm token appstorys shared setfirebasetoken(token) this registers the device with the appstorys outreach backend so push campaigns can be delivered when to call it on every new token from firebase fcm rotates tokens periodically — after app reinstall, data clear, long inactivity, or at firebase's discretion your messagingdelegate will be notified via didreceiveregistrationtoken forward it using the same appstorys shared setfirebasetoken(token) call each time managing push opt in/opt out if your app has its own notification preference toggle (separate from the os permission), use appstorys shared subscribenotifications() appstorys shared unsubscribenotifications() call unsubscribenotifications() when the user turns your in app push toggle off, and subscribenotifications() when they turn it back on this only affects whether appstorys sends campaigns to the user server side — it doesn't remove the fcm token os level permission changes (user denies/allows notifications from system settings) are already detected and synced automatically — you don't need to call this yourself for that case requires the sdk to already be initialized and userid to be set