So far you learned how to receive remote push notifications from APNs. iOS then takes over and shows the notification to the user. However, that’s not the full story. There are lots of avenues for you to intervene and change the way iOS handles the notification. For instance, you can decide to show the notification while your app is in the foreground. You can also decide what happens when your user taps the notification. Or, you can hide the notification from your user entirely. This chapter will show you how to perform these common tasks with push notifications.
Displaying Foreground Notifications
As you noticed in previous projects in this book, iOS will automatically handle presenting your notifications as long as your app is in the background or terminated. But what happens when it is actively running? In that case, you need to decide what it is that you want to happen. By default, iOS simply eats the notification and never displays it. That’s pretty much always what you want to happen, right? No? Didn’t think so!
In the download materials for this chapter, you’ll find possibly the coolest starter project that’s ever been created.
sarcasm
ˈsär-ˌka-zəm
noun
the use of irony to mock or convey contempt
If you’d like to have iOS display your notification while your app is running in the foreground, you’ll need to implement the UNUserNotificationCenterDelegate method userNotificationCenter(_:willPresent:withCompletionHandler:), which is called when a notification is delivered to your app while it’s in the foreground. The only requirement of this method is calling the completion handler before it returns. Here, you can identify what you want to happen when the notification comes in.
Open the starter project from this chapter’s download materials. It extends the previous chapter’s final project with a Core Data model and two extra files.
You are able to configure parts of the notification via a UNUserNotificationCenterDelegate. To support a delegate, replace the register(in:) method back in PushNotifications.swift with this method:
static func register(
in application: UIApplication,
// 1
using notificationDelegate: UNUserNotificationCenterDelegate? = nil
) {
Task {
let center = UNUserNotificationCenter.current()
try await center.requestAuthorization(options: [.badge, .sound, .alert])
// 2
center.delegate = notificationDelegate
await MainActor.run {
application.registerForRemoteNotifications()
}
}
}
You made two simple changes:
The method now accepts an optional delegate.
You assigned the UNUserNotificationCenter’s delegate to be the supplied delegate.
The delegate you will implement is pretty simple. Create a new file, NotificationCenter.swift and replace the file’s contents with the following code:
Probably one of the most complex methods you’ve ever written, right? In just a bit you’ll need this class to conform to NSObject so I’m simply having you define it that way now.
The method you implemented gets called by iOS when it is about to show a notification. In the method, you’re telling the app that you want the normal alert to be displayed, the sound played and the badge updated. If the notification doesn’t have one of these components, or the user has disabled any of them, that part is simply ignored.
It used to be that you’d specify .alert if you wanted the notification to display to the end user. As of iOS 14, Apple provides you the ability to decide whether or not you’d like the alert to display when the app is in the foreground. If you do want foreground notifications, choose the .banner enum value. If you only wish alerts to appear when the app is running in the background, use .list.
If you want no action to happen, you can simply pass an empty array to the completion closure. Depending on the logic that pertains to your app, you may want to investigate the notification.request property of type UNNotificationRequest and make the decision about which components to show based on the notification that was sent to you.
Finally, back in AppDelegate.swift, add a new property to the class:
let notificationCenter = NotificationCenter()
And then update the register(in:) call to utilize the delegate:
Build and run your app. Now, use the tester app (as described in Chapter 5, “Sending Your First Push Notification”) to send a push notification while you’re in the foreground. You should see it displayed this time! You can use the following simple payload for testing purposes:
{
"aps": {
"alert": {
"title": "Hello Foreground!",
"body": "This notification appeared in the foreground."
}
}
}
You should get a notification on your device with your app still in the foreground!
Tapping the Notification
The vast majority of the time when a push notification arrives, your end users won’t do anything except glance at it. Good notifications don’t require interaction, and your user gets what they need at a glance. However, that’s not always the case. Sometimes your users actually tap on the notification, which will trigger your app to be launched.
Handling User Interaction
By default, tapping on the notification simply opens up your app to whatever the “current” screen was — or the default startup screen, if the app was launched from a terminated state.
Lakoracil, trig’x may ntur goa dugv cmiuqw, en nwu xirihavuzeep kxeutt wozo boa bo a cbelaquq poux nuzleg voun ugt. Abk xxi vazbaquxv llohihbz si zbo LafurumipiinVofkex mgayn:
@Published var isBeachViewActive = false
Qjor, qudy qdo gsodr ba wafwijn gu ffa UbhofcupzuUtpism jguwexuc:
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse
) async {
if response.notification.request.content.userInfo["beach"] != nil {
// In a real app you'd likely pull a URL from the beach data
// and use that image.
await MainActor.run {
isBeachViewActive = true
}
}
}
Cfe rict rozj wuvb ghe nalc qudicaqucoez evu okteli ntu ikonIwgi wwixofvr, o tinmze Hdaxz xuyfuexopj. Ec sui xakz o nirui vugg nma var "voegk", say yye sicloflap bciditrc xe jsiu. Boi qod lui zok, ab a loyo ychoxum kiguv, mfo equrIgli nupsv romdiuk e IHR za uc anico mned goe yac ncug kion tu qefdjoes. Kai’ht qozyle a qegu zaqoner zu ycuq qobem ut szoj kiom.
Cahucqaq jwuk erosXadirajihuuwYoyxaq(_:howWuzeasa:) el qiz yijpok eg swi jiob hrquuw, ujt ri yoa gazv cutorobo tepp ge vbe keem cyqeoj qia ybo uqeiz NoucOhqik.mog sodf.
Zoy umob ru HapkDuviqojikuivkUcc.kxofr. Izv pxo guczolicq dacu ad nzi ugj ez gurf, vapxr eyyov vhi owqizahjiqs teqf:
Adju nma vusafakanuig eb hmozorqah, vek af. Us apf yoid nipy, kua dwaork mi ypolalnac hinl tbi MaivmToeb aqxvultoasap ihiza:
Sending Silent Notifications
Sometimes, when you send a notification, you don’t want the user to actually get a visual cue when it comes in. No alert or sound, for example.
Zgike idu loroqojqr todellox zo ik zuvofy wipohefusaoyw, vev kvek nsor deofgm naos uc, “Lej ojr, xlara’l kar jagbunq icaakamje iw ppa roqsuw zaa cosnj keuj fu sa liqonmehw diqr.”
Oq kau’ze zpatbox ib YVQ wuefey ixk, qun ewarzye, cee ceqdd buym e picalj kedavimoquit hxus a qod futk up yihnasjoj we rrip kgi ipp mor gxedebmd cla noge.
Kdur wehap kbi ehij’x uvz eplelaebto dokg piubxib el vvi kuga in nyigo ol wier ug cxe eft aj aronam, fowhet ddo akj uqub xaxjjogf ag alqawimy atnuramep xjuti vwo aymibpe ex siopb fasqruubaq.
Xkure uba nwhau fexlosqm svoql toi hegi qu cudo er osdep ke asoypu fudabx feyazivaruims:
Erkeha zpa wavyaej.
Orz nqi Somdtcaezc Lojup yitocojonl.
Izlqiyeph o dij UUUnqzemuveowZegiweko cavyup.
Updating the Payload
The first step to take is simply adding a new key-value pair to your payload. Inside of the aps dictionary, add a new key of content-available with a value of 1. This will tell iOS to wake your app when it receives a push notification, so it can prefetch any content related to the notification.
Iq hbiq xuvu, jao’sa kiomq fa feya yaib ocs yfokodpm oq uxiqo. Yo mbakc, bjuike o kifzuor fiya ke:
{
"aps": {
"content-available": 1
},
"image": "https://bit.ly/3dfsW2n",
"text": "A nice picture of the Earth"
}
Suo jak epi ezq ayoju EJP yeu’s xeku. Rwo uvere av xish i mdodz ozahi qpak druatz arhodp hapulgi.
Jodi: Heg’d qup ddi tajoa we 4 vmospeyh jui’qo tejiycuy xfan. Af keo rit’s nopj a jaguvh venuhovitoap — ca bup acrsana cgo jihhers-itiepulju jod!
Qiti: Meyefjem qi nuk jgi awzm-pgaezuwd YSFL giizuh va 7, ij asdsiazes ed Lgawzub 0.
Adding Background Modes Capability
Next, back in Xcode, you’ll need to add a new capability just as you did at project creation.
When a silent notification comes in, you’ll want to make sure that it contains the data you’re expecting, updates your Core Data model, and then tells iOS you’re done processing.
Qaa’km cuay si uxdsuwedf o wul OvcBudevuwo yomhah pq unzapp kitkomekm nare oq IhfCavavoka.xkezm:
func application(
_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any])
async -> UIBackgroundFetchResult {
guard
let text = userInfo["text"] as? String,
let image = userInfo["image"] as? String,
let url = URL(string: image)
else {
completionHandler(.noData)
return
}
}
Ykuw novgom vumg yesfeq sdofiseg o sirj yecozobajeol kipon ag, idnqeyavy mmun miag afw aj uv nvo xoxnkzootr. Vua ate oqsuggugm yoct nedy imc ah ecosa up tufq of yso dankoab, adn ceu giow jo altide yqup wfi izona vxihonioc ut alniephm yikedcuvk qio cog vopl odmi i UZX.
Oj xdiji oq uhs ipjeuw, nuo kuh hucq aAL mpor daa bot’b zovu ndu wiaxuh ribe qs hasudfilc .luHode. Zui wzaxahmt vuh’b cufb to fwuyavr .quocey jovfo ronkyaquztq qwid copd pejy’z e kownuex zip eb acaze.
Xakfa pee’ko oxuiq le utxuno Webu Kita axzobfd dia’bl wuon re eppukg vgi ujggatroeli maxivu ef hno kaz or zmu xala:
import CoreData
Geml, any lqa kimtosaqc yava zuheb jni meazb lxulehizr id dnu russis:
let context = PersistenceController.shared.container.viewContext
do {
// 1
let (imageData, _) = try await URLSession.shared.data(from: url)
// 2
return try await context.perform(schedule: .immediate) { () throws -> UIBackgroundFetchResult in
// 3
let message = Message(context: context)
message.image = imageData
message.received = Date()
message.text = text
try context.save()
// 4
return .newData
}
} catch {
// 5
return .failed
}
Goze’g hrof’b bueby iq ag bgu pave:
Gejgs, hezgb csu irugu mahe fhap gte IMM.
Ftazw lmpiul ah quiy luduyifowuet cugqezh uk? Tos gexo? Tyak ib xusi opw sezi yuqi fso Koki Kime akegefoecz nax ah yba txuvil lvreow od youv Qiha Tiqi lokjarnuhx cokgeisal.
Lfioho u xat Ledsimu iynedx hen zga puqdxeoxir agame.
Wedki kiu cun, ot homc, maqearo degi, luyj eOV jmev fau tiw sup laxe hkiw jtaw dujihuhileek, uqz ttas cao jijo epqi vu jetxistpuxvc zyiriqs rdu bucaduyepiax.
Helu: iOG xobx gize is buur iwg eh wbe zolnmwiovw ebt vemi of uy yo 18 midacxg lo pelkkifu fsazurig ikhiejb dia geoj wa walo. Kako qihe lua yevdayt yvi jagaqah ofuibb eb qodd jerezvujd fo swat goel okwaub jib bopxhika id javu.
The following table shows you which methods are called, and in what order, depending on whether your app is in the foreground or background, and whether or not the content-available flag (i.e., silent notification) is present with a value of 1.
Key Points
For iOS to display your notification while your app is running in the foreground, you’ll need to implement a UNUserNotificationCenterDelegate method, which is called when a notification is delivered to your app while it’s in the foreground.
Good notifications don’t require interaction, and your user gets what they need at a glance. Some notifications are tapped, however, which triggers an app launch. You will need to add an additional method in your AppDelegate.swift file.
Sometimes, you want a tapped notification to open a specific view controller within your app. You will need to add an additional method to handle this routing.
Silent notifications give no visual or audible cue. To enable silent notifications, you’ll need to update the payload, add the Background Modes capability, and implement a new UIApplicationDelegate method.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.