Push Notifications have always been a big subject. You can find countless threads on StackOverflow, videos on YouTube, and even entire books on them.

To keep the scope of this article centric around a specific problem, we need to make assumptions. For the sake of this article, I will assume that you have a solid understanding of Swift, you understand the theory of how Push Notifications work, and how Firebase works in general.

Recently, my mentee was struggling with her application and the desire to set up remote notifications. Since her application uses Firebase as a backend, I helped her implement notifications. This article will walk you through the process.

The Scope

What we're trying to accomplish is the following: We have a to-do app and we want to send every user a notification reminding them of their open to-do tasks, every morning.

  1. We want localized notifications for English and Spanish speaking users.
  2. We need to prepare the iOS application to receive notifications.
  3. Firebase Cloud Functions will be used to create the payloads.
  4. Google Cloud Scheduler will be used to set up daily CRON jobs.

1. Localization

Generally speaking, localization provides us with the opportunity to dynamically define text content, matching the user's language settings. For Spanish speaking users, the app could appear in Spanish.

Push Notifications should also be localized. We're able to accomplish this in two different ways:

  1. The backend defines the localization for each user
  2. The iOS application makes this decision

One of the advantages of the first approach is: we don't have to ship an update of our app every time we want to change the notification title/body.

This article will nevertheless cover the second approach, simply because it requires much less work and "localization" is not the core subject of this article.

Please find Paul Hudson's article on how to set up localization if you're unfamiliar.

Initial localization for English and Spanish

In the English version, you might want to add key/value pairs like the following:

"OPEN_TASKS_HEADER" = "Your tasks are waiting";
"OPEN_TASKS_BODY" = "You have %@ task/s pending";
Localizable.strings (English)
"OPEN_TASKS_HEADER" = "Tus tareas estan esperandog";
"OPEN_TASKS_BODY" = "Tienes %@ tareas pendientes";
Localizable.strings (Spanish (Latin America))

%@ is a String format specifier. We're going to replace it with an integer specifying how many tasks are pending.

Please hire a translator or ask a native speaking friend to translate for you. Nothing can ruin an application experience faster than poor Google translations

2. Preparing the application

To prepare, please follow the basic setup guide provided by Firebase. You need to set your bundle ID, upload your APN key and turn on the Push Notification Capability of your app.

To promote a clean app architecture and to separate the differentiation of concerns, we're going to wrap everything related to notifications into a wrapper class.

To hook the wrapper, all we need to do is the following:

3. Firebase Cloud Functions

We'll be utilizing Firebase Cloud Functions to calculate the payload and to send the messages. Please follow the Getting Started guide to create your environment. If you're new to Firebase Functions, you can find more tutorials on YouTube than you'll ever be able to watch.

The Functions are developed using a programming language called TypeScript, that is remarkably similar to Swift. Even with no JavaScript experience, you should be able to follow the code based on my extensive comments.

First we create a function to download all tasks.

The database structure in this example is as follows. All tasks, regardless to whom they belong, are all in a huge collection. Look at it as a huge Array of Tasks. When downloading all tasks, we now need to split the Array in groups, using each item's userID key.

For this task, we're utilizing an npm package called Lodash. This library provides the function groupBy, that takes an Array and a key, and returns a dictionary, with  each key as (you guessed it) key, and in groups separated each key's Array elements.

Before and after using Lodash's groupBy method.

Now that we know how many open tasks each user has, it's time to implement the function that sends the messages using Firebase's Cloud Messaging service.

Now that we have added the ability to send Push Notifications, we need to create the API function, which we can call from outside the code environment to trigger everything above.

An API is a way of communication. We're communicating to our cloud server that we want to send the Push Notifications.

4. Google Cloud Scheduler

Once we deploy the setNotificationsTrigger function, we can use any kind of tool– including the browser's address bar–to perform a GET request that sends out notifications to all users who have chosen to accept Push Notifications.

To call the API on a fixed interval we'll be utilizing the Cloud Scheduler.

The following shows the body I used to create a daily trigger at 8AM. The hardest part here is the Frequency as it's using the CRON format.

With our Scheduler in place we're done and our users will receive a notification every morning, reminding them of their unresolved tasks.

To improve, the next step should implement proper paging when downloading the tasks in the cloud functions as described in the code snippets.

It is okay to test without implementing a scalable solution if your application is still in the proof of concept stage. However, as soon as the application undergoes heavy usage, the function to send out the Notifications will simply fail. The tasks will exceed the allocated memory.