The Ultimate Guide to flutter_background_service (with Android Native Walk-through)[2023]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi guys how's it going so in this video I wanted to take you guys through this package which is flutter background service so uh when I came across this package before and when I had to implement a background task for my use case I as a flutter developer I found it slightly difficult and cumbersome to firstly understand this package and use it properly because um when I came across this example here I saw that this example is really convoluted in the sense that they have added a lot of things that are not even directly related to the package such as this shared preferences thing here and even a local notification format and a little bit more so uh it was slightly tricky to understand in the beginning and also since I did not have much of an experience with Android native side right to understand and harness this package to the best of its ability was slightly tricky so in this video uh the point that I'll try to do is is that I will take you through the flutter implementation of this package first then I will also try to give you a overview on how the flutter side talks with the Android native side a side note here I will be using certain technicalities from the Android native site as well and I will make sure to link all of the sources from where I learned them on in the description so that you guys can just watch this video and then go into the description and then get a grip of how the native side is working a bit so that you can harness this package to the best of its ability okay so let's begin so firstly a quick intro on where this package is used so this package is generally used in examples where you would want to continue some kind of a functionality even when the user is not accessing the app or has even taken the app out of the task manager itself so a simple example for this can be when you are making a music playing app and even if the user quits your application and takes it out of the task manager the music should not stop playing so in those kind of use cases you can use this package right so in Android it implements something known as Android services and that's how it operates and implements this functionality in the backend so let's begin with the flutter side and then we will go on to see how uh in this diagram how side by side the Android functionality also gets involved so when you start with this package the first step that you do is that you configure it so you configure the package and when you configure the package you basically initialize all the parameters so there will be certain set of parameters such as do you want it to be a foreground service do you want it to be a background Service uh do you want to attach a custom notification channel to it and whatnot so this you can think of this as a initialization step right then you will go ahead and you will start the service so when you start the service here on the Android side it will this is the time where it actually invokes the service and creates another foreground or background service which ends up implementing that whole scenario in which even if you take out the app from the task manager that service will still be alive okay so and then after uh starting the service out you basically have certain listeners here on the flutter side which you can use to configure the service right so basically I will spawn listeners such as uh set as foreground set as background and stop source so what this would be doing is is that once the service starts right these listeners will come into play and now I can through these listeners talk to the service and Implement these scenarios so these scenarios are as simple as it sounds basically status foreground will change the background service to a foreground service set as background will change the background to the foreground to the background sorry and stop service will basically call stealth self stop on itself and stop that service that is running so this is as simple as it is on the flutter side uh now on the Android side what happens is that they are using something known as method channels to talk back and forth between the flutter and Android side okay so when you configure the package using the method channels what Android does is that it uses shared preferences to set these configuration details right so this is what happens on the native side of things and when you start the service sorry when you start the service it uses the same channels to invoke a method which can now go ahead and start either a foreground service or a background service based on what whatever parameter you suggested in the shared preferences in this step right so now uh it will start this service and it will also bind this service to the main plugin okay so the services will be bound in nature but they will not be strictly bounded service Services they will be foreground and background services but also bounded to the main UI right and then for The Listener side you would see a similar implementation using I feel it's a broadcast receiver so there would be receivers I'm sorry I'll use this color uh there would be a broadcast receiver and some listeners set here which would basically be doing this back and forth communication and notifying each other that uh about the functionality such as whether you want to stop the service or you want to change this service type and whatnot another small side note is that they have also implemented a watchdog receiver here which basically its job is that every five seconds it just checks whether this service is still alive or not uh there I feel they have done this because there might be a chance that the OS might just take out your service some in some cases when it's running in the background and the main UI is not active and if that happens at any point of time uh the Watchdog receiver using the alarm task manager uh will restart the service and it would it would look to the user that the service is constantly running no matter what so this is what primarily is the whole flow of this package all right so let's jump into the code from now so I've set up this new project uh to implement this background service and to start off with of course we need to add this dependency here in our pubspect.yaml file uh you can copy paste this directly from that documentation page once you have done this run pub.get to make sure that the package is there I've already run it so I'll do that again and now you'll be able to see that I have a very simplistic setup so there's a main file and I have shifted the UI element into a different page because we don't necessarily need to look into the UI and break our heads on this right when there will be certain elements that we need to discuss about I'll just pick them up and discuss them separately but for now let's just completely focus on how to set up the background service and the the topics that are related to that so let's start from here so as I mentioned in My Graph before the first step would be the configuration so for that firstly we'll have to create a main service so I'll make this async since we'll be dealing with Futures and I'll just make sure that all the flutter bindings have been initialized it's just best practice and now we'll go on with the configuration so I'll create a function which would be initialize service and after I have done this initialization of the service this will basically take care and spawn the take care of everything and basically spawn the service and after that I will use run app to render the UI that I had created using that stateful widget over here so you can see that the name of this app is Maya and basically what this will do is that it'll initialize our service and then it will just start that my widget so that we can talk back and forth with the background service so now let's implement this initialized service so to implement this initialized service [Music] it will return a future [Music] right so now in this in this part we will first be configuring the service as I mentioned in the graph before and then we will start the service right so to do all of that firstly we will create an instance of the flutter background service here so let's store it in this variable in a service and now we will call service dot configure right so now as you can see by the way this configure function Returns the future and that is why I added the await tag and it returns a Bool here so okay so now since I will be focusing on the Android side of things I'll just make a dummy initialization for the iOS configuration and leave it as it is and I'll dive into the Android side of things so let's Implement that Okay so over here you can see that there are two required parameters one is onstart and one is is foreground mode so is foreground mode basically uh is a parameter that is asking on whether do you want the service to be a foreground service when you started or do you want it to be a background service so I'll just say true here because I wanted to be a foreground service right and I'll come back to this Android configuration in a while let's just start the service and complete this function so I'll just in the end say service don't I'm sorry I was not at the right place this is service dot start and this also creates a future so I can avoid this as well all right so this function in a nutshell has configured the service and has started it right so now let's just dig dive uh into what the configurations are so let me start with these so these are pretty self-explanatory these two parameters will uh basically allow you to either start the service right on configuring itself or you can also initialize this to make sure that every time the phone boots that is restarts the service will be initialized again so these are pretty helpful configurations is foreground mode we already talked about and now these configurations are related to what kind of notification do you want the app to show so when you have a foreground service there will be a notification that would be displayed on the app right so these parameters will determine what the content is and also which channel ID are you trying to focus on if you make a custom one you can insert and insert your own channel IDs here and then customize it to your own use case but we won't be using this so we'll just keep it to the default value now let's come to the best part this is the onstart now onstart as you can see is a reference to a function which takes service instance as its parameter right so now this is tightly coupled to how this package has been implemented so in short what it's expecting you to do is is that it's expecting you to give a function reference which takes that service instance as a parameter and in that function you can implement the meat of your logic so everything that you want the service to do as soon as it has been started that would be defined inside that onstart function now how is it invoked we'll get to that a little later when I'll be going into the native side but let's just implement this onstart function here so to implement this OnStar function I'll just go into the documentation and I'll just copy paste the way they have implemented it right so it looks something like this so it's a simple void onstart async type of function which takes the service instance as its parameter and they have marked it as a VM entry point right so now we can go ahead and implement this onstart so in our use case as I had mentioned in the graph before we will be setting up the listeners over here we will be setting up listeners so that we can talk uh we can talk with the listener and change this background service to a foreground Service as foreground service to a background service or even stop the service overall and as an additional uh functionality what I would also do is that I'll add a timer uh within this logic and it's it's a use case would be to update the notification that is being displayed by the foreground service so if we have a foreground service in our example there will be a notification corresponding to that and that timer bit calls will constantly update the content of that notification so we will be sure that our service is running even when we take it out of the task manager and whatnot right so let's Implement that part so I'll go into the documentation again and I'll copy paste this part so yeah this code is pretty self-explanatory it's firstly determining whether it's an Android service instance and if so it is setting up these two listeners so the on command returns a stream here uh and it's basically listening for this method and if it gets that it basically invokes set as foreground service on the service instance so if at any point of time it comes across these two methods it will perform these tasks uh one simple question that you guys can have is where is this string coming from and where is this value coming from so now this is inherently uh how the package has been implemented so as we'll see in the native side of things as well these are the same strings that have on the native side as well so that is how they are communicating with each other so it will be clearer when I go into that uh side of the code later on but for now let's move on and let's implement the service on stock as well so I'll copy paste that code from their documentation it's this is also fairly easy to understand uh basically if at any point of time we receive this kind of a method Channel invoke it will Implement service or stop self right so these are the listeners that have been put into this function and now let's implement the timer functionality that I was talking about so for that I can just use timer.periodic I can set a duration of let's say two seconds uh and I can make this a const and now I can implement the time over here right so to implement the timer I'll go back into their code and I'll just copy paste the part that updates the notification Channel so this is the side and indent it properly okay so here you can see that they are again confirming whether it's an Android service they are also making a check to confirm that a foreground service is running in the background because only in that case there will be a notification and if that is so it goes ahead and Updates this so let's just change this to some custom name so that we know that it's working uh and so I change the title and updated at the date time dot now will constantly keep changing because it will be the current tape you can see there's an error being thrown on a weight here so I feel if I can make this async it should fix it yeah good so this part is done and this is more or less it so if we can implement this part of the onstart function it will take care of all the things that I talked about that is setting up the listeners and also updating the notification Channel periodically all right all right so since we have set up the service properly and we have made sure that it started let's go into the UI to check how can we talk to the service right so the UI is pretty simple here you can see that it only has three buttons in a column and all of the on pressed uh functions here are invoking the flutter background service on the same string that we set the listeners on so this is this is it basically if you just do this it will set the background to foreground foreground to background or in this case it will either stop the service or it will start the service so pretty self-explanatory and the flutter side of things looks very easy so let's just run the app and make sure that everything is running fine I just installed this application in my VM here and you can see there are three buttons here as we had discussed before right so once I start the service I had actually stopped the service before while testing it out so if I start the service now you can see that there's a background service which is running and if I go into the logs you'll be able to see there is a service which has been attached and this background service logs are coming here right now if I go ahead and make it foreground you'll see that a notification comes up here and when I go into the notification you'll see that the notification content is as we had configured before and the time is also being updated every two seconds right so I can switch back and forth between the foreground and background you can see that now the notification is not there now the notification come up and if I want to stop the service I can just stop the service from here right and it got stopped let's say start the service back again and just to confirm that it's working well I'll remove the app from the task manager and you'll still see that this notification is still here right and you can see that it has it is getting updated even now even though the app is not there in the task manager so this is basically how this package works and um from now what we'll do is is that we'll go through the code that we have written before and we'll go step by step as to how it is being initialized from the Java native side as well and I'll kind of take you through a walk through so that you will be able to understand how the message passing is happening between the flutter and the native side and if you have a use case where you want to extend that first functionality a little bit more you can take it from there okay so uh to start off with how to understand how the Android side of the code has been implemented right uh one starting point for you can be that you can just go into this Android folder here and over here if you go into app Source Main Java and and then within this i o flutter plugins you'll see this registrant and I had already opened this file here so you can see that this is kind of the entry point uh for the plugin background service plugin and it injects itself over here right and if you want to find further implemented files you'll have to go into external libraries here you'll have to go into flutter plugins and then over here you'll be able to see the implementations for Android iOS and the main plugin so if I go into Android I'll be able to see further files which would help me understanding what the package does right so uh now this can be one way of analyzing the packages but I would suggest that you just go ahead and open this Android folder from file and open so if you just click on Android here and open this folder you will get a far better and a more simplified view so this is what it will look like you'll have the main app and you'll have the flutter background service so each plugin that you add the plugins code will be available here directly so you can just go in here and you'll see the same files that we saw there but this is just far easier to access so sure so now if you go into that main plugin register and file that I showed you here you can see that it is trying to use this Class 2 inject itself right so it's using flutter background service plugin and over here as well we can see that there is a service plugin here right the same class so let's start from here cool so this is the class that kind of starts at all and you can see that it's implementing flutter plugin method called Handler and service aware so since it has a method con Handler it will be listening to certain methods and let's just dive back into the flutter code and see where is it being invoked from exactly so let's go into the main file that we just implemented right so here we are initializing the service and now we configure the service so this should be the first entry point there right so if we go into configure here you'll be able to see that the configure call is basically uh making a call on this platform instance and if you go in here this will be an interface implementation of it yeah so over here what happens in the background is that it uses this Android flutter service background flutter background service Android class and it injects itself into that platform instance so over here you can see that there is a flutter background service Android class and over here and using this register with it kind of sets it as that platform instance back there into the interface and so uh if you want to look at any method uh we'll look at that method's implementation in this class all right so now that we were looking at configure we'll go into this class and we'll see that there will be a configure enabled somewhere okay so here it is so over here we can analyze this code and try to understand how is it basically talking to that class that we just saw in the native side so here you can see that it is setting a method Channel firstly and that method channel will have this ID here so it is ID flutter background service Android right so using this ID it is setting the channel now it is also taking a callback handle for the onstart method that we had provided uh just a quick refresher the onstart method was this method that we wanted to be invoked as soon as the service is started so what it's doing is that while configuring it is setting the method Channel it is getting the Callback handle and then it is using this channel to invoke a method known as configure right and it is passing all of those references here so uh not just the background handle but all the Android configuration references that we had added right so somehow it is basically invoking the channel and now it is whatever result it is getting it returns true or false based on whether it was able to get a result or not right so if you remember uh when we try to implement configure it returns a future of Bool you can see there right so okay so now it's using this channel to hit this method right so if we go back into the Java code you'll be able to see since it implements this method call Handler there will be a on receive method somewhere here so if we go down yeah so basically not on receive but on method call and on method coil will basically expect it will basically listen to certain methods that are being invoked and you can see here the first one itself is configure which was called from the flutter side as well so if this method is invoked what it does is it takes all the arguments in sets them into the configuration of a variable here and then if auto start is enabled it starts it or it just returns this value right so another quick uh details on this config variable that is here right so if you go into this config variable you can see that it's part of this config class it has been set up here and what config does is is that it is basically a shared preferences implementation so shared preferences in a nutshell is basically some key value pairs that you can set within the Android phone and it is not restricted to the apps lifecycle so it will stay there no matter what and you can generally use it to access user preferences or those kind of small values that you need to store so that your app whenever it's reloaded it reloads with those user preferences Etc so it's using config here to set those parameters in when whenever you are setting whenever you're calling config configure from flutter and that's it so it basically uh takes the parameters and sets them within the shared preferences right so let's go back into the flutter code now and in the flutter code you will see after configuring we are starting the service so what does start service do you can say start service again is the interface implementation so to look at the correct full implementation of it we'll go back to this class and we would expect a start method there it is and over here you can see that it's invoking a method known as start so if I go back into the Java code here you'll see start is the next implementation and over here it is just calling the start and returning result.success so if I go into start I can see that it is using this Watchdog receiver number one to enqueue a context and then it is checking whether it's a foreground service or not and this is the generic code to start the service so if it is a foreground service it starts a foreground or it just simply calls start service using this class so this class has to implement service right so if you go into this class you can see yes it extends service and now it is also binding this service using a service connection here and this service connection would have been implemented on the top of this class itself so you can go and have a look here and I have mentioned certain resources in the description so if you want to learn a bit more of how how things these things work you can have a look at those resources so anyways coming back what we can understand is that it is using a watchdog receiver it is implementing the services starting them off and then binding itself to the service and having a link here right what is the version of receiver now so if I go into the Watchdog receiver which has been implemented here it's basically a broadcast receiver and when I went into the code I basically realized that it its sole use case is to have an alarm manager configured so that it basically checks for the background service every five seconds and if at every five seconds if the service has been stopped to some God for second reason it will restart it given you have not manually stopped it of course so it is basically a fail check in which if at any point of time if your service gets wiped off from the processor it this alarm check will be alarm manager will basically restart the service so that's the use case of this Watchdog receiver that they have added so anyways so now since we started the service and it called the start method year uh now we can go into this background service to see what does it do when the service gets started right so now I can go into the background service here and uh since I know about Services a bit I know that oncreate gets started first and you can have a look at this method here so now I'll just give you a brief of this method what this method is doing is that if it's a foreground service it is enabling and configuring the notifications that needs to be shown in the UI right and this part is setting another um it is basically initializing the shared preferences configure and setting up a main Handler right now this is simply what happens in oncreate now there should be a method known as onstart command which is a year and this would happen every time the service has been called so here it has it is setting this config to false obviously it is enqueuing it again and then in run service now this is where the actual uh meet of the logic for the service lies so now here what it does is that it firstly gets certain logs for multi-threading purposes updates the notification Channel again and from here on what it does is is that it creates a flutter loader and then a background engine a flutter engine basically and then within that flutter engine it tries to execute this dot entry point so if I go into the configuration of this dot entry point you can see that a package name has been mentioned here right and just keep this package name in mind and you can see that the function name is entry point right so what it's doing is is that once the service gets started it's initializing a flutter engine it is initializing a dart entry point and then it is taking out the background handle from the shared preferences and executing that entry point which was basically this function within the new flutter engine right and at the same time it is also setting up a new method Channel which is by the name of and background service Android PG right I believe in the previous uh method Channel this BG part was not there so so the BG part is basically the new service and just the Android part was the previous main plugin that we had so uh just to recap this again what they're doing is as soon as you start the service they are basically creating a flutter engine defining an entry point which is that function and that package exactly getting the background handle the background handle in this case is the onstart function reference that we had provided before and now it is executing that dot uh entry point right so if I go into this implementation here on the flutter side I'll be able to see that so this is the class that they had invoked right and they were looking for a function known as entry point and you can see the entry point has been defined over here and they have denoted it with another entry point uh pragma so over here since it's a new isolate they are initializing the flutter binding again they are setting up an Android instance in this case and now they are fetching that same onstart method uh reference that we had provided here which they had shared into the put into the shared preferences now they got it back from here using the list box and now they are calling our onstart method within this new isolate with this service instance inside so now things might be getting a little bit more clearer on as to why the implementation was like this before right it was we had to Define like an onstart method which takes a service instance as a parameter now we know where it is being injected from so so this is how it's happening right and now from now on what happens is that this service instance has this on method here which as we can already assume must be listening to some kind of a method Channel again to talk back and forth with that service and make some initializations right so let's go into how it is listening okay so if you want to understand how this listening is happening exactly let's just have a look at what the UI was doing so when we were clicking on the buttons the UI was invoking these methods right and it was invoking either set as foreground set as background and then over here as well we had a listener setup which was effectively listening to whether you had ever called this message and then it was using the service instance to make this uh Final Call that is to either change it to a foreground or stop the service or whatnot so there was a two-way communication that was going on there right so firstly it was being invoked using the buttons and then somehow it was being listened on this side and then the invocation was happening so to understand how this is exactly happening if you have a look at the invoke method here this is actually talking to the flutter plugin that was the first method channel that we had discovered in this case right using the first method channel so and and you can already see that that method channel has been binded with the other service right so that is how the communication is happening so if I go into the Android code and I go here or before that let's just see what that invoke method does exactly so if you go to invoke method here no sorry not here uh over here you can see that it is invoking uh oh sorry this is the interface implementation yeah so in this class uh you'll have to see invoke over here so it's using the send data message channel uh basically a string on the on the method channel right and now if you go and see the send data implementation within the service plugin which is this one uh over here if you go and check so configure start send data here you can see that it's it is using the service binder and it is invoking certain methods using the service binder and if I go into the service binder and I see the service connection that they have made where they have initialized everything I can see that they are calling receive data here right and this received data basically uses a channel and invokes a method on receive data again which has been which is the same channel as the one as the main plugin one right this one so it calls the on receive data from here right and if I go back into the flutter code you will be able to see that over here uh within this one they have on receive data configured here right and it basically broadcasts a message using the controller uh and adds it to the controller so since this controller is of a broadcast type it broadcasts that message right and once it broadcasts this message what will happen is is that it gets uh your on the main side the service dot on will be able to listen to it right and now we get the control over here which effectively calls service dot instance set as foreground service now the service dot instance is connected to this method Channel which was within the service right so when you called set as foreground service for example it invoked that channel and then this message so I'll go into Android and I'll go into the service and here in the on method call I will be able to see set as foreground yes right here right and you can see that when as soon as the code comes here it basically uses the background engine and brings it to the foreground or it brings it to the background similarly in the stop case it just calls cell stop here and removes itself from the Watchdog queue right so I know that this has been a slightly complicated workflow and that was the exact reason why I made this video right because when I came across this package for my use case when I did not know the exact flow from the Java to the flutter side it was really difficult to determine whether this package could actually solve my use case or not and if yes how would I be able to optimize it to the best extent so I hope it helped you guys understand this package and that's it for the video if you like the video please drop a like and if you have any feedback for me please let me know in the comments below and see you next time
Info
Channel: WeWorkout Devs
Views: 9,382
Rating: undefined out of 5
Keywords: Flutter, Background Services, Android, App Development, Native Code, flutter tutorial, flutter background service
Id: GwnJ21LlXl0
Channel Id: undefined
Length: 36min 13sec (2173 seconds)
Published: Sat Feb 25 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.