How to Send macOS Notifications From a React Native App
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the Building React Native Apps for Mac course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Building React Native Apps for Mac, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
[00:00 - 00:06] On this lesson, we will be adding notifications to our application. It's one of the most common features nowadays.
[00:07 - 00:23] And unlike on mobile, the only way to send notification on the Mac is by doing it from an open application. You probably realize this if you use the macOS Mail client, you only get notifications when the client is open.
[00:24 - 00:37] But the process is fairly simple, so let's just jump into it. First, we will start by adding a bridge method, so we can call it from our application.
[00:38 - 01:02] I will call this send notification. And it's going to take a string, which will be the title and a payload, which in this case I have chosen to use a string as the payload, but you could send some other flag if you want to.
[01:03 - 01:11] Then I'm also going to add an extra parameter, which is URL. We will talk about it in a little bit.
[01:12 - 01:18] Great. So now I can move into my Swift file and implement this.
[01:19 - 01:28] I'm just going to take the code from the lesson because it's a little longer to type. And let's just walk over it.
[01:29 - 01:46] So my header, exposing the function to Objective-C, my function itself, which takes the title, the payload and a URL, which for now it's also a string. So the object that I'm looking for is the NS user notification.
[01:47 - 01:54] I'm going to create an instance of the notification. I am going to give it an identifier.
[01:55 - 02:02] I'm just creating a UUID. This comes as part of the Swift library, so I don't need to import anything.
[02:03 - 02:11] Then I'm going to place the subtitle. I'm going to put my payload as the subtitle, my title as the title.
[02:12 - 02:22] And here you will see I'm using two different things I'm casting, then NSString into a string. So this one is the Swift class for a string.
[02:23 - 02:31] And all the stuff that we have been using so far, it has this NS prefix. This is next step.
[02:32 - 02:41] This comes from the very old system, the very first macOS operating system. This is just internal conversion.
[02:42 - 02:47] You can kind of use them in any way you want. You can convert NSString to a string.
[02:48 - 02:56] You can convert, I don't know, there's a bunch of classes, but they're more or less mapped into their Swift counterpart. So you can just cast them.
[02:57 - 03:12] Now, this notification object has a user info property, which is a map. So unlike on JavaScript, where we use curly brackets on Swift, we use square brackets.
[03:13 - 03:26] And in this user info object, I'm inserting our URL that we pass into this function. So this is basically how we're going to communicate at some point.
[03:27 - 03:41] If we want to, let's say, do some special action, right, I can just insert more properties into this user info map. So in this use case, what I thought about is we're just going to add the URL.
[03:42 - 04:00] And then at some point, you know, when the user clicks a notification, what we want to do is we want to open this URL. Then I mean, if you have any other data, what you could do is just pass it to your application, pass it back to your JavaScript code so you can display something to the user.
[04:01 - 04:04] It doesn't matter. We're going to wait to attach more information.
[04:05 - 04:14] And we're also going to give it a sound name, which is just a default for my Quest. Just so that when the notification plays, the user can hear it.
[04:15 - 04:23] Finally, I reach into the NS user notification center. I get the default.
[04:24 - 04:29] So this is another pattern that you will see in some of the classes on my Quest . This is a class.
[04:30 - 04:37] You could theoretically instantiate a new instance of the notification center. But sometimes you will see this default.
[04:38 - 04:49] And this is just an instance that has already been created for you, which is the running instance of my Quest. So here I have my notification center.
[04:50 - 04:55] So I'm just kind of reaching into that. And I'm telling it to deliver my notification.
[04:56 - 05:04] Great. So now that we have that, I'm just going to recompile the app, make sure that it runs.
[05:05 - 05:12] Great. I have it in there.
[05:13 - 05:22] So I'm going to go back into VS code. Sorry, I must have closed it.
[05:23 - 05:32] And I'm going to go into my building apps native and I'm just going to add it in there. So again, it takes a title.
[05:33 - 05:41] It takes a payload and it takes a URL. It returns void here.
[05:42 - 05:50] My notification is bound to my native module. Sent notification.
[05:51 - 06:00] And finally, I just need to call it somewhere. So I'm going to go once again into my books container.
[06:01 - 06:09] I'm going to add one more button. This is going to be a notification.
[06:10 - 06:14] Sent notification. And I'm just going to pass some test values.
[06:15 - 06:31] So this test title, test payload and my URL is empty for now since I'm not going to use it. If I click on this, you will see the first time my demo course is going to ask for permission to the user.
[06:32 - 06:54] It needs to load, but then if I click on it again and this is small detail because our app is running directly from Xcode, it might not show, it might not want to show the notifications directly. If you open the control center, they have already been kind of queued up in here.
[06:55 - 07:09] So you want to test this once you have packaged your application. On the previous lesson, we already mentioned to you if you want to package your application, you need to go into product archive and you need to export an instance.
[07:10 - 07:25] But after you export the instance and it's running on its own and you send a notification, then they should properly pop up. I think I also have do not disturb right now because I was shooting this video.
[07:26 - 07:35] So let's try one more time. Let me just clear the notifications and yeah, there you go.
[07:36 - 07:48] So there are small things, like I said, when you run your application directly from Xcode it might not behave the same way as when the application is released. Great.
[07:49 - 08:01] So now let's do one more thing. Like I said, the idea would be that once the user clicks on the notification, we do something with it.
[08:02 - 08:13] Sometimes it could be open in the URL, it could be just showing the app because right now if I click on it, nothing happens. So in order to do this, I'm going to go into the app delegate file.
[08:14 - 08:24] And in here, I'm going to modify my base class. So right now the app delegate extends NS object and NS application delegate.
[08:25 - 08:43] So now I'm going to add one more delegate into this class, the user notification center delegate. And with that, after I have done all the initialization of my windows and react native, here I'm going to insert one more line.
[08:44 - 08:58] And I'm going to say NS user notification center, the default instance one more time. And the delegate is going to be this instance, this class.
[08:59 - 09:24] It's going to take care of whatever event it might come up. Then after my open desktop window function that we created on the previous lesson, I'm going to add one more function, which is the func user notification center, did activate and the user notification.
[09:25 - 09:34] Right. Whatever the deactivate dictates that whenever the user has clicked on the notification, we need to respond to it somehow.
[09:35 - 09:51] So let us do, I'm going to extract my URL, just the notification, the user info . And since I know that it's going to be there, I'm just going to cast.
[09:52 - 10:01] I'm going to tell the compiler, don't worry about it. I know that this is a map and it has dynamic properties, but I know that my URL is in there.
[10:02 - 10:06] So don't worry. I know it's going to be there.
[10:07 - 10:13] Nothing is going to crash. Then I'm going to take this.
[10:14 - 10:33] And because it might be an empty string, I still need to do some checks in here . So first, I'm going to check if it's not empty, then what I'm going to do, let me just copy this code, is I'm going to create a URL object.
[10:34 - 10:43] Right. So this is one of the things on the native side, the URLs need to have their own specialized instance of a URL object.
[10:44 - 10:53] So I'm just going to pass that URL string into this object. And then this is how you open URLs from your application, right?
[10:54 - 11:02] Like Mac OS is going to take care. If you have a URL register to any application, it takes care on its own to open the proper application.
[11:03 - 11:08] And if there's no application, then it's probably going to open Safari, right? And it's going to open your URL.
[11:09 - 11:16] So you can redirect your user to your main website. You can redirect your user to any other application.
[11:17 - 11:38] And on the else case, what I'm going to do is I'm going to toggle or status bar item. So let me recompile.
[11:39 - 11:41] And let us. Okay.
[11:42 - 11:53] One second, let me try from here. Yeah, you can see sometimes it acts funny, but I'm just going to click on it.
[11:54 - 11:56] And there you go. The application has been opened.
[11:57 - 12:19] [ Silence ]