How to Implement Firebase Push Notifications on Android (FCM + Backend)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys and welcome back to a new video in this video we will talk about push notifications and how we can Implement these into our Android apps with fcm that stands for Firebase Cloud messaging so we are going to use Google solution for implementing these push notifications in the past I've already done a video about that that has been quite some time ago and things changed so you can't follow that video from the past anymore because this fcm API is now updated to the so-called HTP V1 API I which is just a bit more secure so we have different type of authenticating in this case with access tokens so they are just shortlived access tokens which we need to refresh frequently and that has the advantage that if a token gets lost or maybe gets leaked to the public then it might only be valid for an hour or so but not for the whole lifetime or whatever so if an attacker gets that token then they can only do something for a very limited amount of time with it and there are some more advantages which you can also find here in this Firebase Docks but I first first of all want to show you what we will build um so this will be a rather minimal setup to implement push notifications including the server setup so we do need a server that's why it's called push notifications because a server pushes these to our device and they are not triggered locally on our device when the app is offline for example but the app will look like this I open this on three devices here we have a text field to enter a token so each device will have its own unique token which you can use with fcm to send push notifications directly to a specific device and we can then for example copy this token here uh then we copied it to our clipboard we can then paste it here in our other device so on this device we want to send push notifications to this device so we paste the token of this device here on the left device let's paste it here let's copy this token as well paste it on the right device and I also want to paste a token here on my real device like this and if we then click submit on all all of these uh devices then we can enter a message so let's minimize these two devices here for example that we can actually receive notifications if we now enter a message here and say hello world and we click Send then you will notice that this device receives this notification so you can see new message hello world this device didn't receive that notification because we pasted the token from the right device on the left device and if we just normally send a message here then the push notification will only be delivered to the right device that's of course something that makes sense if you build something like a chat application where only the recipient of your message should actually be notified with a push notification however sometimes you want to notify multiple devices with a push notification so you might want to broadcast a specific message to multiple devices let's say you have some kind of game app and you want to offer a limited discount for some kind of inner purchases then you want to send that discount push notifications of course to multiple devices that's something I will also show you how to do so we can also enter a broadcast message here and if we then click on this little broadcast icon then this should be delivered to both our devices here so there is our broadcast message but also here on my device you can see new message broadcast that is what we will build as I said we will need a server setup for that which we are going to use Kor for but I will say right away this will be a very minimal setup so we will Implement everything server side that it works that we can send these notifications but we won't include any user authentication for example here where we also need to persist the token of each device which would be necessary if you were to build a real chat app real social media app or so but I think that will be way too much that is not directly related to a push notifications I might use that in a future course however but for now let's get started with the video and the first thing we want to do is we want to connect our Android Studio project uh with Firebase so obviously you need a Firebase account here so in case you're new to to Firebase that is just a cloud service from Google which offers you easy implementation for databases for storage but also for push notifications and since Android is from Google they also need to have their own kind of mechanism for push notifications and no matter what kind of push notification provider you use so there are multiple not only fcm for example maybe you've heard of something like one signal that all exists and they these providers um might make things a bit easier but they all build on top of fcm so that is really important to understand that you can build your own kind of push notification framework without using fcm because in the end these push notifications should also be delivered when the device is idle when your app is not actually opened and for that there needs to be some kind of system service on Android which is always alive but we as developers can do something like that with our app um except maybe with a foreground service but that's not ideal and doesn't work for uh for all use cases so you need to understand that there's always kind of a system service running that listens for these push notifications and that system service uses fcm so we want to go to our Google um Firebase console where we have our project and we want to then add a new project here so let's click that we can choose a name for that project if you already have an existing Firebase project you can also link your app to that project you can link multiple apps to one project but I will create a new one here which I'll call Firebase push notifications we can to click continue next we are asked to enable fire r so Google analytics for our five Bas project which in Project absolutely makes sense um so we just get some extra analytics for everything we do so on the one hand something like crash lytics where you get crash reports Cloud messaging so here fcm in app Messaging and so on um so in real app I would definitely enable that since it gives you a lot of essential information about your user base in this case I will not enable that because you will need to also create an analytics account for that link link it to that um that is not the the core of this video so let's disable able that and click create project then that will take a moment and after that I will see you back there we go our new project is ready you want to click continue and there we already see get started by adding Firebase to your app we of course have an Android app here let's click on Android and then we need to register our app here with our package name so if we go into Android Studio we can copy this package name here copy paste it here we can also give it a nickname which is optional so I'm not going to do that if you use something like here Dynamic links Google sign in and so on you also need to add this S1 hash which I will also skip since it's not needed for push notifications so let's click Register App next we need to download this Google service Json file which is just a file from Firebase which tells our app all the information it needs to talk to our Firebase servers so want to download that and then you can see we need to paste this Google service adjacent file into our project app folder so once you open Android Studio switch to the project view minimize that open that open our app folder where the Firebase file needs to be positioned and then here want to paste this um actually need to remove this three so just Google services Json and there we go okay we can close this and go back to Google Chrome so we can click next here we've added that next is we need to add the Firebase SDK to our project so that is pretty much just the library that we can use Firebase functions in our code we want to select cotland DL that is the Great version we use then we first of all need to add this plugins line in our build. grad project file so let's copy that go to endro Studio open our build. grad at the project level and simply paste this here then we go back to Chrome take a look what else we need to add we need to add the Plugin or apply it here in our app level Gradle file so we want to copy this go to n Studio go to the app level Gradle file and paste it here and then last last but not least we need to add this Firebase B so that's pretty much just a a file or um a reference to the latest Firebase version so there are tons of Firebase dependencies there is for Cloud messaging there is for realtime database there is for fire store and all of these might have different versions and this B uh dependency just declares the latest dependencies that actually work together for your project so I want to copy that go to Andro Studio scroll down and want to add that here apart from that the only thing we now need to add is the specific dependencies we want to use from Firebase so I will simply paste this here um actually without this B so on the one hand we have Firebase messaging and notice how we don't specify a version here because that is done by this Firebase BM um since it will use the latest stable version for that and I also added retrofit because that is what we will need to later talk to our backend server or k server that we will um build here so we can click synchronize now and go back to Chrome where we can then click next you can see we're all set we can continue to console and that is how we now add our app to our Firebase console okay back in Android and we can now get started coding we can first of all close our Gradle files the first thing we need to do is we need to create a push notification service so that is just a background service that comes directly from the Firebase dependency which will be used by Android to just listen to to incoming push notifications and we need to just create a service reference for that that will be very simple just open our let's switch to the Android view let just open our project and in here I will create a new class called push notification service like this that will inherit from fcm is it Firebase messaging service yes that's how it's called and we also need to add that service to our manifest so that it's actually used by our app so open our manifest and below this activ ity we can declare a service oops service and it already suggests our push notification service for the service we actually want to declare a body and specifically we want an intent filter here so with an intent filter we can filter the incoming intent that we say those service should only listen to a specific type of messages in this case that message is incoming the push notification so we can say we specify an action here where the name of the action is com. gooogle oops google. Firebase do messaging event doesn't S suggest that but believe me that will be correct so this service will only listen to incoming messaging events that is how fire calls these and we also want to set exported to false um so that will mean that only our app can actually talk to the service and not external apps if we then go back to our push notification service we will notice we get a little warning and that's as apps that use Firebase Cloud messaging should Implement on new token in order to observe token changes so as I've mentioned before the way authentication works with this um Firebase Cloud messaging so just to make sure that no attackers or so could send push notifications to your app so we need to kind of authenticate and to make sure that this uh works firebat now uses so-called refresh tokens so just a token long screen that frequently changes and when that changes this service will call the on new token function giving you the new token and if you were to build a real app here where you need to send push notifications over a longer period of time to a specific device let's assume WhatsApp you need to save the chat history of someone on your servers but also need to be able to keep on sending push notifications to a specific person when a new chat message arrives then you also always need a reference to the current token of that app of that recipient so in this case when you get a new token from Firebase which you need for authentication you would need to take this token push it to your server and save it in the database for that corresponding user account in this case we're not going to use this since we always get the most upto-date token when we launch our app and as I said we will have a very simple setup here without any remote database but just that you know what you would need to do if you would build this on a larger scale but I think this would be way too much for a simple YouTube tutorial what you can also do here in this service is you can override on uh on message received which will be triggered when a push notification will be received so if you need to respond to that somehow then you can do it in this function we won't need to implement this here because um we can already set the title the body of the push notification and Firebase itself knows how to display a push notification with the with the default Fields but if you want very custom push notification Behavior then you can also pass in your very own parameters which you can then receive here in this on message receive function interpret that and show it on your own with the notification manager API so here we could respond to received messages if we would want that and here we should update our server okay but that's already it for this servers next up we need to Define our state for our screen so if we think back to our app if I relaunch that very quickly not that one but this one if we think back and actually not launch this one but the old version of the app one second then we see something like this so if we think about what kind of state what kind of changing elements we have in our UI on one hand we of course have this remote user token text that is a text that can change that needs to be part of our state our state also needs to contain some kind of information whether we are currently at that entry enter token section of our UI or if we are already in the um enter message section where we can enter a push notification text and we need that text itself self for the push notification text so we have three parts in our state which we can create here in our root package call that Chat State or whatever you like make it a data class and here we on the one end have a Val is entering token which is a Boolean false by default no actually true because we start with this token text we then have our remote token text that's a string which is empty by default and we have our message text which is the string come on uh which is the string that we can enter when we want to just uh send that body as a push notification to another device and if we now think what we actually need to do in order to send a push notification so how that whole mechanism works and why we need a backend in the first place because just in theory we could Implement push notifications and sending these just clients out just from our Android app but that will be terrible security wise because we need to keep our secret Firebase key that allows us to send notifications we haven't used that yet but we will later in this tutorial we have to use that Cent side in order to authenticate sending these notifications and if you keep such super sensitive secret client side then it just takes one attacker who reverse Engineers your app and gets access to that and then they can send push notifications in your name that is of course terrible and that's why we use a back end here and especially with this new http1 API from fcm it's almost impossible to implement that client s side so the way this will work however is our client will make an HTTP request to our server when it wants to send a push notification and it will just include all the information we need for that so the title of the notification the body and potentially more if we want that so of course also the um recipient so it will also attach the token of um the app we want to send this to but that is all the information our client will send to our server via an HTP request and the server will then interpret that and uh will send or will actually trigger the the real push notification because the server of course has this secret from Firebase which authenticates the server to send that notification and since we completely own the source code of the server we don't distribute that to our users that's a much safer place to keep such very sensitive secrets so the next part is we need to create kind of a body and adjacent body which we want to send to our server and if we use retrofit for HP calls we just do that as Scotland data classes so new class here called send message dto dto because it's called a data transfer object it's just a cotton representation of adjacent body we send over the network so data class Val 2 that will be the token so to which app we want to send this will be a nullable token um so if this is null we will instead broadcast the message and we want to have a notification here which will be of type notification body this is a class to create here here the data class notification body which will contain a title and a body so that is the minimal fields we actually need to display a push notification of course you can display much more you can pass multiple strings for multiple languages here so they are properly interpreted um but all that is explained in the Firebase docs um as I said I want to show a minimal example here if we cover the the whole docks and all of is written in there then this video will probably be 10 hours long but I might use that in a premium course later on in a real project so you can also learn how to implement this in a real project so now that we have these two data classes which represent adjacent body we want to next Implement our actual fcm API so a retrofit API where we Define what kind of HTP requests we want to make from our app to our own backend server so we call that fcm API will be an interface and in here we Define these functions so those will be suspend functions using col cortines call that send message and here we attach a body which will be our send message dto this will be a post request and the route for that uh that is something we Define our own backend later will just be slent it doesn't need to return anything and we will just trigger sending a notification with that and another function we need is broadcast and here we also attach this body so since in either case we just send such a notification body we can uh make the signature of these functions the same except for the name and here we also post something to/ broadcast next up before we get to implementing our actual UI we want to implement our chat view model that is where the magic will happen where we will um receive actions from the UI so button clicks when we send an out ification and where we will then take that and Trigger our retrofit API so we make that HTP call let's go in here have that chat view model which is a view model like that and then here we can get started first of all I would like to create a retrofit API in here that is something I also wouldn't do in a real project in a real project I would use something like dependency injection to actually rather inject the API here so API fcm API but with view models there's always a pain in the butt if you don't use a dependency injection framework um which would also be too much for this video um so let's just keep this simple and create the API directly in our review model here so API that is an fcm API and that's equal to retrofit Builder and we first of all pass a base URL so which API which um URL we talk to in this case that's HTTP um we're not going to use htps here that requires you to get an SSL certificate and we say um 10.0.2 do2 I will talk about why this specific URL in the moment um but the port is 8080 so that is what we use server side why do we use this specific URL that is actually the Local Host URL if you are on an emulator because if you just use something like Local Host then this refers to the emulator itself if we run this app on an emulator and since the server doesn't run on the emulator this request will go to nowhere so instead we can use this specific IP address um that allows us to still refer to Local Host but the local host of our computer because we will be running our backend here just locally we won't deploy this anywhere here in this tutorial and otherwise this won't work an alternative way to achieve this is you could use the actual IP address of your Wi-Fi router then this would also work with uh your real device so if you use your real device then using this approach with this IP address won't work because your real device doesn't know anything about your local machine but the emulators do but that local IP address on the other hand can change here and there if you maybe restart some um local devices in your local network so I will just use this here and only use emulators here to uh send actual notifications and I will use my real device to only receive such notifications since that doesn't need to talk to our own back end then we want to add a converter Factory which is a mushy converter factory. create so that will just Auto automatically pars our Json responses to our cutland data classes and we then want to also call build and create like at this and there we go we have our API ready then above that we want to have a VAR for our screen state so our state by mutable State off and we pass an empty Chat State reference I'll enter to inut that I'll enter again make that a private set so only the view model can mutate that state and then we can go below here and we're going to have a function on remote token change so here we have our new token which we're going to trigger when we just read in the token um so when we just paste another device's token in our own text field in the app we would just update our state state state. copy and the remote token in this case would be the new token then we next want to have another function to submit the token so let's call it on submit remote token to like this and here we say state is equal to state. copy is entering token is false so then we just want to switch to our chat view of our UI and last but not least let's copy this make a function for on message change so when we type a message then we get our message here and we say okay our message text is our new message so much about the State updates one more function we need is of course to trigger sending a push notification that is where the magic happens so let's have a function send message and here want to pass a Boolean whether that is a broadcast or not so depending on which icon button we uh click on right here so the left one is sending a message to a specific recipient and the right one is just broadcasting it to all known devices so here we're going to now execute our API calls with retrofit we do that in view model scope in a COR routine and we first of all need to construct our message dto and again I won't apply any um real architecture I would use in a bigger scaling project here um where you wouldn't use these dto directly in the v model but for the sake of Simplicity uh let's do that here and this is actually absolutely fine in a smaller project so you don't need to over complicate such things with clean architecture in a project or you just send a few messages to each other's device but if you want to build something at scale then uh I wouldn't do it like this just as a disclaimer because people would come Philip you shouldn't do this um it depends on the project so we will construct our send message dto two will be whether we're going to broadcast or not so if we're broadcasting then there should be null so then we don't want to send our notification to a specific device but to all of them and else if we specify a specific recipient then we are going to use our state remote token and the actual notification will be a notification body the title um I will just hard code here to New message of course you could also make that flexible depending on some kind of state but the body will be flexible here depending on our message text now that we have this message dto we can check if we are broadcasting if so we trigger our api. broadcast we pass our message dto and else if we send this to a specific device then we just call api. send message with our message dto and just in case something goes wrong we should surround this with try and catch on the one hand HTP exceptions or we just print stack tray and we would like to catch IO exceptions for example if the device is offline and the API request fails because of that so let's move this in here in the tri block and last but not least we want to update our state or let's actually only update that if our request succeeds so state is state that copy and the message text is just an empty text again so we just clear our text and that is it for the view model we can then use this in our UI which we going to build right now and I would like to start with our enter token dialogue so right here this is actually a dialog not sure why it shows as a blank white screen on this device but if we use the different device and relaunch this you will notice that it's actually a dialogue right here um and that that's what we're going to build go in here called enter token dialogue make that a file and here we have our composable enter token dialogue what does the dialogue need on the one hand the token that is entered in the text field of course it needs an on token change Lambda which gives us the new token when it changed and it takes an onsubmit Lambda which is triggered when we click on the submit button okay so how does this UI look like first of we need a reference to our clipboard manager because um we have this button which we can click to copy the token to the clipboard and for that we need the clipboard manager so we can refer to local clipboard manager. current to get that we will later on need a context reference which can also get from local context. current and we need a Curtin scope reference which we can get with remember Curtin scope so we can execute asynchronous stuff here in our dialogue and then we're going to Define that dialog composable it has an on dismiss request so that is fired when we uh click outside the dialog for example or we just kind of just want to hide it but in our case we don't want to hide our dialog so we want to for show it uh Force show that in all cases until we click submit so we can't click outside here to actually close this because we definitely need that token in order to use the app that is why we also need to Define these properties dialog properties where we can say Okay um dismiss on back press no we don't want to dismiss the dialogue when we press the back button since we want to fores show it and we also don't want to dismiss it when we click outside so that's also false because otherwise this on dismiss request Lambda would be called when we click back when we click outside but we don't want that okay then inside of this dialogue body we will just Define a column the first element of the column will be our text field and then the second element will be a row that consists of these two buttons so column that needs some kind of modifiers um not the Java modifier this one here uh let's give it some padding only horizontal one though so 16 DP I'll enter to import DP we then fill the max withth considering that padding we then want to clip it to a rounded Corner shape of 5p rounded Corners we give the background color of material theme. color scheme. surface and we then apply padding to the actual content of our dialog and that will be applied to all sides so this first padding refers to um this side here that we at least have a minimum padding of 16 DP here and then we fill the max with considering that first padding and this padding in the end um which is applied after applying our background will then push our um our content in the middle of our Box by 6 indp so then let's have an outline text field in here the value is just our token on token change well actually on value change should be our on token change Lambda modifier is just modifier fil Max width so we fill the whole width of our dialogue we have a placeholder text which is a text composable and the text is remote user token we also want to set the Max L to one so we're text field will always have one line and doesn't expand when the token is very long and it seems like we need to add this experimental API here this anotation um so opt into that and then we get rid of the warning next up we need a spacer we want to have a spacer um that is 6p high and then as I said we need a row which includes our two buttons so this row will have a modifier of modifier. filmax with and we want these buttons to stick to the end of the row so arrangement. end okay inside here we're going to have a button actually an outline button first outline the button and when we click that button we want to um in this case uh copy the local token to our clipboard so this is now this copy token button um we could also propagate this to the view model um but there we don't have access to the local clipboard manager which we do have here so let's just copy the token here directly when we click this button create this Lambda and create the uh button body um the text will be copy token and when we click here we first need to read the current token from Firebase which is an asynchronous operation that is why we need this ctin scope so we launch a new ctin here and the token will be equal to Firebase this KTX dependency apppp dot no actually not apppp messaging. token and you can see that returns a task so a task is always something um that executes in the background that is asynchronous if we want to get the result of that directly here we can call that a wait so um this this will suspend the cortine we launch here until we retrieve the token from our Firebase SDK now that we have this token we can put this in our clipboard so clipboard manager set text that only takes an annotated string not a normal string so we need to create that annotated string and pass in our token and then we can just show toast or so that the token was properly copied here we can pass the context we created previously the text will be copied local token and toast. length long. show something like this works very fine and here uh the name is shad out because we already have a token reference just to not confuse you let's call that local token like this that is our first button the second button will be the submit button which will be easier there will be a normal fil button and we click that we trigger our unsubmit Lambda to send that message and the text will be submit and we might also put a modifier um I mean a spacer in between with a modifier of width 16p so we have a bit of spacing here between our buttons but that should be it for our enter token dialogue next up we need to create thei for sending a message um let's do that here call that I don't know chat screen for example chat screen make it a file composable chat screen this takes in our message text it takes an on message change LDA which gives us the new message when we type it it takes an on message send Lambda when we click the icon button to send it to a specific device and likewise it also needs an on message broadcast Lambda like this and the way this screen will look like is yeah very similar to the previous dialogue actually same structure we have our text field here fills the whole with and then our two icon buttons which are right aligned so again we're going to use a color we'll have a modifier compos one of course which will fill the max size of our screen and the vertical Arrangement is arrangement. Center so we Center the content vertically as well as horizontally so alignment um is it horizontal alignment alignment do Center horizontally this one then we again have an outline text field just as for the dialog loog the value is our message text on value change so when the text changes is our on message change lamba so we propagate that new string up to our activity level the placeholder will again be a text to uh enter a message and we need a modifier to have some padding horizontally of 16 indp and then we again fill the max with so that we have some padding here on the left and the right side again I'll enter on outline text field to opt into this experimental API and then we just need our row we should actually be able to copy this from here from our dialogue scroll down copyed with a spacer um together with these two buttons like here paste this here there we go um so here's our row we're want to say fil mix with um apply some pading actually let's also apply that before horizontal 160p the horizontal Arrangement is and that works in here we don't have outline buttons but rather icon buttons and did I do that wrong because that's not inside the row let's take a look here oh yeah these two of course need to be one level above in our actual row so good that I copied that let's just put the space in our row and remove this button or let's let's copy it and rename it to an icon button oh no we actually need an icon for that ignore what I just said let's have an icon button in here on click will be on message sent so that would be the left icon button and in here we're going to have an icon with an image Vector of icons default. send content description is send we then copy this put it below this one will have a share icon which I think is the closest to broadcasting a message in the default icon set and call that broadcast this should trigger on message broadcast and then we're done with our chat screen so last but not least for our app at least we want to open our main activity and include our UI here so let's get a reference to our view model private valve VI model that's a chat view model by view models like this and in here in our UI we have a surface this surface will have a background it's actually a color I think color of material theme. color scheme. background and a modifier of modifier for Max size in here we're going to then get a reference to our state which we get from The View model we observe that here then check if our state is entering token so if we are currently at the um enter token dialogue then we show that enter token dialogue to token is state. remote token the on token change LDA will be delegated to our view model on remote token change and on submit as well on submit remote token else so if we are at the messaging screen of at the chat screen we want to also show that of course the message text will be state. message text the on message sent Lambda will be view model um actually here we need a real Lambda since that has a parameter so view model send message is broadcast is in this case false since we want to send that to a specific device and on message broadcast will be the same just that is broadcast is true in this case and we need the on message change Lambda which you also just delegate to the view model like this that is it for main activity no not yet one more thing we need in order to show uh notifications is of course we need notification permissions that is something yeah fairly new that Google introduced for that let's go to manifest scroll up users permission called post notifications that's actually only um necessary for some kind of API level I think 31 or so but we still need to request that and one more thing we need since we are talking to our own back end and we're not using secure traffic here which you should absolutely do for a real backend but if you talk to your local backend and you don't have htps you need to set the users clear text traffic to true so um you just declare that in your network security policy hey I'm aware that this is a danger but uh I really know what I'm doing and uh in this case I I need my app to send data unencrypted to our own back end of course only do that when you're actually testing locally or in an environment where nobody else knows you backend so let's go back to our activity and request that here main activity and on crate we can then have a function request modification permissions or permission Alt Enter create function there we go and if our build this one here version SDK in is actually larger than built. version codes. terisu it is that is from which API level we need to request that permission only then we want to request that so we need to say has permission first of we check if we have that use the context compat for that check self permission context is just this and the permission comes from the Android manifest permission post notifications and if that is equal to package manager that permission granted we know we do have permission otherwise we don't we can then use that to check if we don't have permission in that case I want to use the activity compet to request that permission so request permissions the activity is this um the permissions we want to request is an array in this case we only want to request one manifest. permission. post notifications and request code is zero we are not going to respond to what the user enters here or whether they declined or approved that permission that's also not the topic of this video and would be way too much but I think that is it for the app what we now want to do is we want to take this launch this on all of our devices on this one on this one and I will also launch it on my pixel device because we can already test this so there we go we first of all of course need to allow these permissions on all of our devices allow allow allow and yes that is looking pretty much uh just like I showed before the first thing we need is we need to click on copy token of each of these devices once because that will tell Firebase hey I am a device I have a token and I want to register for receiving push notifications I'm at least a device that can receive push notifications from fcm we can't yet send these push notifications from one device to another because for that we obviously need our backend but we can use the Firebase console to test these so we can send these directly from the console let's minimize our apps here and let's actually make sure that we have a specific token um oh do I get my recently used apps here let's make sure we have this token on our clipboard go to our Firebase console click on engage and go to messaging I think that is where we can trigger these test notifications so here we first of all need to click on create your first campaign so campaign is pretty much just a push notification but really everything that belongs to push notification on which devices it was delivered um here we are asked to check what kind of notification we have um in our case we have a Firebase notification we don't have an in message that's something different well that's a message that shows directly in your app as kind of a dialogue as you can see but we want to push notification let's click create then we are prompted to enter a title for notification we can also use hello world or so for that the notification text is blah blah blah or so and we can I think somewhere we could also pass the target yes so we could click we could uh click send test message here and yes here we can add an fcm registration token so there's a text field want to paste our token that we just copied from our device Dev click on this add symbol and that should now hopefully show up in our app if we click test go up here and yes there it is here's our notification one thing that is very important to um to actually make this notification show up be logged in to your Google account on your emulators that is of course not the case by default because otherwise it can really happen that notifications don't show up so just make sure to log in go to your settings accounts and then add your Google account of course if you're testing this on your real device and that uh doesn't happen because there you are always logged into your Google account but you can see that is very well working let's also quickly test this on our other emulator where we can go to our app copy this token of course always minimize the app otherwise it won't show up um because notifications only show up when the the when your app is actually not in the foreground we could also test this if we actually turn off our screen actually let's let's try something else to show you that's really a push notification let's close this app so the app is closed there's nothing really running from that app minimize make the screen off and then we click test message add another token so the one we just copied click add and now we want to send the notification here click test and there something happening here I at least heard a sound if we now turn the screen on again there we go here is our notification uh on this device as well so so that is working perfectly fine one more thing that isn't working yet in regards to our app is broadcasting messages and receiving broadcast so how does our app know that we really want to that it should receive a specific message in um that was broadcasted for that we want to go back to Andro Studio it's really just a little addition go to our view model and here we want to add an init block which is fired when the view model is initialized we want to launch a ctin here in view model scope and all we need to do for that is we need to refer to Firebase messaging and want to call subscribe to topic now so that is how it works to broadcast messages to multiple devices and Firebase works with these topics where we can define specific topics which um refer to a group of devices which subscribe to that topic and then we can send a notification to that topic so that whole group of devices that subscribe to that will also receive the push notification so let's say you have some kind of news app and that news app really bundles all kinds of different news maybe the weather maybe business news maybe stock market news and all of these different news types could have their own topic so in the app you could subscribe to maybe business news and uh that way you would also subscribe to push notification topic business news and you would only receive push notifications for business news but obviously there could be multiple devices all subscribing to that topic of business news that is how these topics work in our case we'll just have one topic which we hard could here um to chat and we call wait and that will then um yeah make sure that we subscribe to that topic and receive notifications um for yeah the whatever we broadcasted okay next up we are now actually done with our app so next up we want to build our back end we want to build something that receives these two HTTP requests takes these interprets these so reads in the Json body whatever app wants to send and then our back end will make the HTTP call to the Firebase back endend to actually trigger sending that notification and as I mentioned we want to use Kor here for that since I I really like Kor as a backend service especially for Android developers since it's completely based on cotland and yeah that's just a language we know a language we're familiar with a language we love and to create a Kor project we want to go to start.or doio if you have intell ultimate that is the IDE we will use to build a Kor project then you can also have an integrated K project wizard uh but since that is that costs quite some money um I will show you that how you can create K project for free and also use that in the normal free intell version so that is done by using this website Kor project generator call this Kor push notifications FTM or so and then we can add plugins so in Kor a plugin is just um some kind of feature we would like to use a backend like feature like authentication to use JWT authentication or whatever you want in this case we don't need that but what we do need is we want to have routing so we want to be able to Define HTTP routes then if we scroll down we want what do we want we want call logging so that we automatically get logs when incoming um HTP requests are received we want content negotiation and Cent serialization so that we are able to par incoming Json content and I think that should be it um let's click on minimize here um oh no what did I do now um let's go to the very top somewhere we need to configure our project yes on settings I I forgot something we want to adjust the project settings just to make sure we have um a real package name here choose gr cotlin the Kor version is 3.0.0 beta I would like to use that one um because I want to minimize the risk that a CW update deprecates this tutorial very early so I want to use the latest possible version here then the engine is nety so just what uh drives our backend server and the configuration will be in a hocon file so that's just a a configuration file for our server what the IP address is what the port is and so on let's add some sample code go to add plugins um oh no we need to add these again that is bad okay routing we we need call logging and coton serialization and then we can click generate project and it will download your project as a zip file which you can now easily open in intellig so I will open that extract it and open the project so the the extracted folder in intellig and I'll see you back in there there we go in intellig I've opened the project syncing was successful and the first thing we want to do is want to open our project hury open our build grad kts file and add a dependency so right here here this dependency is called the Firebase admin SDK so um that's pretty much the Firebase SDK as well but for server side and that includes everything we need in order to send and Trigger push notifications from our server now where we have that secure environment which we don't have on client side we can then click on this little icon in the top right to synchronize these Gradle changes and let's first of all take a little look in kour in case you're new to that how such a product looks like we also have a main cotton package and here we have we have a plugins package which was already generated by the project generator monitoring just defines some basic call logging logic so with install we can just tell our backend hey we want to use this feature of call logging of automatically logging these calls we can add filters and all that stuff we have routing um so here we Define all of our routes um that we want to expose to the public so our HTTP routes to in this case receive the Json body from our app and then forward this to the fcm API we can also remove this here since we're going to Define our on routs of course calization specifies how to use here content negotiation so um in this case Json and automatically paring that we also want to remove this routing block since that is already contained in our routing plugin and last but not least here an application all these functions from the plugins package are configured and called and here we can then and also do some further setup and what is that further setup first of all we need to link our back end to our Firebase console and that works with a so-called service account key so that's a Json file which just contains all the relevant information the Firebase admin SDK needs to authenticate and authorize with fcm and we get that by going to our Firebase console going to our project overview this little settings icon project settings here we have a service accounts section which want to click which is as you can see for the Firebase admin SDK and we want to take a look for Java yes we basically just need to refer with a stream to this service account key Json so I want to click generate new private key again it's private this should only be on your back end now you can see it also tells you that again generate key and then it will download that Json file which we now want to open copy go to our intell J IDE go to our resources package and paste it here I'm going to call this service account key Jon hit enter and there we go our file opens again this content is no secret so let's close this again and just read in that service account key with an input stream and if we want to refer to file from our resources then that's a kind of a weird way to refer to that but it's how it works we have our refresh token stream let's call it um service account stream and that is equal to this double colon class. java. class loader and that has this get Resource as stream function which um just refers to our resources package we can't just refer to the path of our resources folder here because later on when we deploy this and everything is packaged into a jar file and then this folder doesn't exist anymore um so we need to refer to this function to actually read in the resources that are packaged directly into the jar file the name is just service account key. Json like this then we need to Define Firebase options which are Firebase options. Builder and here we need to pass in that service account stream so we set the credentials and the credentials are Google credentials from stream we pass in our service account stream and then we call that build and last but not least we can call Firebase app to initialize the app with our options so we properly authenticate here for the Firebase admin SDK next up we just need to Define exactly the same dto objects we also defined client side so we could just copy paste these let's open Android Studio send message dto copy these two classes go back to intellig J and paste these here then I would like to define a little mapper which Maps a send message dto to F Firebase me message so a message that Firebase can interpret that we can send to the fcm API which is a message here from Firebase messaging and here we can then return a message. builder we're going to set the notification so definitely don't say uh set put data here I mean that is something I did wrong in the past that can be used if you have custom fields and you want to have your custom um interpretation of the notification so you can pass any type of key here ABC and a value so hello or so and that will also be contained in this message bundle which you can then receive client side in this on message receive function which I've showed you before in the Firebase servers but that will not automatically show the notification so if we just want the default notification body and interpreting it in the default way then um we don't need any setup for that because Firebase also already creates a notification channel for us pretty pretty handy in order to do that we just need this set notification function here we construct this notification. Builder can set the title to our um body or is it called notification. title set the body to notification. body and then we call that build we also want to set the token so um that fase knows which device we want to send that notification to or we only want to set that if the Tok is actually assigned so if it's null we want to broadcast it instead so instead we use apply here and check if two so the recipient token is actually equal to null then that means we want to broadcast that message so instead of setting the token to set the topic as I mentioned and the topic is chat so all devices that subscribe to this chat topic will receive this notification um else we simply want to set the token to two and then we can call that build on this so that's just how we transform the send me message GTO into a Firebase message which we can then send in our routes that is the last thing we need to do so here in our package let's have send message routes that's just a normal file here in Kor and the way we Define these routes here that's simply an extension function of route and first of all that's send message well let's just bundle these here in one function we have a sent notification route and in here we then Define that we have a route we specify the path of it so the HTP URL we need to send something to in this case it's SL send what we also defined in our retrofit API interface and in here we then define whether that's a get request post request put request and so on this case it's post um just like this here we get a routing context which we can then use to also get the incoming data the incoming adjacent body so Val body is equal to call do receive nullable it should be a send message dto so to received that send message dto uh if such body wasn't attached then it will be null instead and I think I imported the wrong receive nullable let's take a look again this one here need it needs to be so without this type info send message GTO and then if that's null we have a run block where we say call that respond with bad request I'm actually how's it called oh also wrong import call that respond want this HTP status code overload so here we say bad request that is the status code for want to return in this case if um the if there is no Json body attached then we want to tell the client hey that's a bad request you didn't attach data that you were supposed to attach we also want to return of this function return it post and then we know that at this point if we reach this part in the code uh this body is definitely not null we can then use Firebase messaging to get the instance so get the single turn and then send the message which in this case is just body to message so here this takes in a Firebase message and since we created that function to convert our send message dto to a Firebase message we can very easily do this here and that is it how we trigger such a push notification server side so once you have all that set up it's it's super easy it's just a function call but here we also want to return okay so we tell the client hey everything was fine we sent the request to Firebase and yeah then we can just go ahead def find its route below as well for broadcasting weam this to a broadcast which is a different route we again want to receive the same type of send message G and we again want to send the message here the message itself already contains that we want to send this to a topic in this case so we don't need to change anything here really just copy paste and changing the route here you can see the function is currently unused so u k doesn't really know that this exists we need to now take this go to our routing file and put this in here to Define that we want to have this sent notification routes and I think that is it for our back end so you can see this was a lot easier than client side of course as I said if you do this in a real project then you need need to have some kind of database where you make sure that you save all these tokens of every single device if you want to be able to always send notifications at any time to a specific device just one thing I want to check is if we go to application. conon yes the port is actually 080 that is what we Define client side as well I would say let's launch this mag end in application we can click the little play symbol next to our main function run application KT and we should hopefully not get any issues there we go Application started um and okay address already used that is because my other instance is running so the IP address is already in use I just quit that I'll relaunch it it can still happen that this um will show up for you so that just means that there's another program currently using that Port then you need to switch the port to something like 8081 or so uh and also change that client side of course and then it should work but now you can see we are responding at exactly that IP address and we can now try that out client side one thing I forgot actually an internet permission otherwise we can't talk to our back end let's quickly change that um duplicate that change it to internet and then relaunch this on all of our devices and see if we can actually send notifications from one device to another that would be awesome there we go so let's first of all take this token copy it paste it here here copy this token and paste it here can then click submit submit here as well let's ignore my real device for now we just want to uh see if it works to send a notification from this device to this device for example if you have a chat app we want to close this app here or minimize it at least and then we want to enter something here like Hello World click Send and does it show up no it does not show up um let's take a look if our back and receive that okay there seems to be some kind of issue we have unhandled post so our post end point through an exception and it failed to convert the request body to send message dto okay I think I see why that is happening um because there's no serializer for our dto found because we use Cartland serialization here we need to annotate these classes with serializable that is how this works so this one here serializable and this one as well relaunch our back end and then try this again click Send and yes now we received the notification so now that seems to be working let's also try it the other way around if we go in this inside of this app I mean and say hello YouTube then click Send then that gets sent to this device again of course you need to make sure that you're actually logged into your Google account that's very important but if we now go to our real device and just make sure we copy the token but we we just want to test receiving notifications here if we broadcast that um so we minimize that we even close it then we go inside here also make sure we may be close this app remove this existing notification also maybe turn off the screen and now broadcastter message say broadcast click on this broadcast icon then do we get something no there was an issue as well it seems field 2 is required for such type but it was missing did I switch something there so in send message route actually no in where is it in send message dto if two is null then we want to send it to the topic if it's non null then we want to set the token okay that seems correct if we take a look in our app in the chat view model and take a look here if it's broadcasting we want to broadcast this the message dto otherwise want to send it if we are broadcasting we attach null otherwise the remote token so that seems correct I'm not sure why that is is happening so our two field is definitely null right here I think it might be because coton serialization um ignores nullable fields and doesn't include these automatically in the request so I will take a look in that and then get back to you okay I still don't fully understand what's wrong here but I feel like it has to do with codin a serialization because we get a warning here that the compiler plugin is not applied to the module but it is actually applied so if we take a look in our Gradle file you can see uh the plugin is applied nevertheless let's just switch the serialization library here um which makes this a bit easier to uh Jon actually so let's remove this plugin and let's also remove this cotton axx Json jvm and instead add this line here which I've already done so Jon jvm then yes synchronize this in the top right again we can then get rid of these annotations in our send message dto these are not needed anymore and we can can then go to serialization here this won't be recognized anymore and instead we want to refer to Jon to set that up for serialization remove the unused import or the wrong import and then we can relaunch the server and hopefully see a working broadcast mechanism like here so I still have the app open we say broadcast click broadcast and this time yes we do get the message here on my device new message broadcast and here on the device with screen turn off we also got this message here so that's now working perfectly fine we can still send messages to a specific device then it will only appear here and not on the other device as you can see right here so here we only have the broadcast one but not this one so I hope that gave you a good impression of how you can Implement push notifications in your project as well as implementing the minimal setup for the back end if you want me to make a bigger course we push notifications are part of it where we maybe Implement that in a project with a larger scale with multiple features with multimodule architecture then let me know that down below and down below in the description of this video you will also find some more advanced Android premium courses so feel free to look around there and get whatever interests you thanks for watching have an amazing rest of your week and I will see you back in the next video bye-bye
Info
Channel: Philipp Lackner
Views: 23,746
Rating: undefined out of 5
Keywords:
Id: q6TL2RyysV4
Channel Id: undefined
Length: 66min 31sec (3991 seconds)
Published: Wed Jan 24 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.