I am trying to run a piece of dart code when the android device boots up. Ideally, the code should run immediately or with a small delay (1-2 minutes at most). I don't want the app to start up, just a headless piece of code to run.
My Use Case:
I am working on an alarm clock application, and I want to handle the alarms that go off when the device is turned off, like disabling one-time alarms, and scheduling the next alarm if it's a repeat alarm. I can't afford to wait for long to handle these cases in case a repeat alarm was scheduled to ring shortly after the user boots up the device.
What I Have Tried:
I have tried doing it with flutter_background_fetch, with headless: true and startOnBoot: true. But it runs the code at 15 minutes intervals, which is too long for my use case, as explained above.
So I finally figured it out. I first found this great article, Initiating calls to Dart from the native side in the background, detailing how to call dart code from native side while the app was in the background. This was only one piece of the puzzle though, as I had to figure out how to do so from a BroadcastReceiver. Luckily, I realized that android_alarm_manager_plus did something similar. So using code from those two resources, I managed to get it working.
The code is available at flutter_boot_receiver along with the instructions on how to use it.
Details on how it works
Sends a dart callback handle to the native side, where it gets stored in the SharedPreferences.
Specifies a BootReceiver, which listens for the BOOT_COMPLETED event. This event is fired by the android system whenever the device boots.
When the BootReceiver receives the event, it starts a JobIntentService.
The service creates a background FlutterEngine and a method channel to communicate with the dart code.
It then retrieves the dart callback handle from the SharedPreferences and sends it to the dart side via the method channel.
The dart side then retrieves the callback from the handle and then calls it.
Notes
The callback runs in an isolate, so can't access data initialized in your main dart isolate. You can use dart packages/plugins though. Just be sure to initialize them in the isolate if necessary.
Some device might not receive the BOOT_COMPLETED event. You can find more info here. Consider creating an issue in the repo if that is the case.
Related
I am working on an Android application that most it logic is done in background and basically analyzing the user activities (walking, running, in_vehicle etc)..
The ui has only 2 screens for basic setup and for giving permissions.
In the Application class onCreate (not Activity) the app register to ActivityRecognition api and gets the ActivityDetected events in a broadcast receiver which process the DetectedActivity and so on.
The app has also a boot complete receiver, after device boot, the receiver onReceive invoked.. This, causing the Application class to start, onCreate is invoke, the ActivityRecognition begins as described. This works perfectly!
So actually, the process starts in boot complete and nothing stops it..
Additionally, in the Application onCreate I send a firebase analytics Event (like AppStarted)
Also, when ActivityRecognition registration done I send another event (like ActivityDetectSuccsesfullySrarted)
Now here is the thing, in firebase I see that these events are sent about 20 times a day!!
Is there explanation for this?
This means that something, kills and recreate the process? Why?
Android terminates unused processes to free up system memory.
If you want a process to run for a long time on an off-the-shelf Android device, you will need to use a foreground service. If you are working with your own custom firmware, you could take other steps to try to keep your process around.
We need to add functionality in Android app (Api 26+) that every X hours (doesn't have to be precise) will fire some task which will read local database and then display Notification (by click on Notification some Activity should be shown).
Problem is, this should happen no matter if app is in background or not. I've been reading about Android lifecycle and limitations put on recent android versions and I was wondering what would be best solution, using WorkManager or AlarmManager then scheduling job?
Is it even possible to run Activity on Notification tap, when app has been killed or is in background and not whitelisted?
First Question:
WorkManager is the best solution for this. Behind the scene, workmanager is also using job scheduler ,job dispatchers, GCM Network Manager,Alarm Manager and Broadcast receivers, depending upon the operating system with handling of backward compatibilities.
It has alot of functions which will make its implementation clean and easy.Also we don't need to restart it after device reboot like service, it will start itself.
Second Question:
Yes, we can open application by taping on notification even if app is killed.
You can check this.
I have an android/winphone application. Small part of app (background broadcastreceiver/task) from time to time (approx 10-15 minutes) checks local file with timestamps and if difference between one of timestamps and current time becomes more than - say - 30 minutes, it shows a notification to a user.
In Android I use AlarmManager.setRepeating(...) to setup periodic check, and to run this setup code I register a BroadcastReceiver on action "android.intent.action.BOOT_COMPLETED" in Manifest. Or call AlarmManager.cancel(...) and AlarmManager.setRepeating(...) on every launch. This way I may ber sure my timers work.
In Windows Universal I use triggers and background tasks. This works the same way with some limitations.
Now I'm porting my app to iOS, and quick look doesn't give me a way to register a function or class to perform quick checks (mostly less than a second) every 10 minutes while the app itself is not launched, and also I would like to register a function on device boot event. Is it possible?
Or should I keep my app running in background? I'd prefer not to do so, as my checks are lightweight and rare.
You can use background fetch for quick executions.
But there are several disadvantages:
Doesn't work in sleep mode.
You cannot catch device-launch event.
It will be dropped in 30 seconds.
I think in common case this is not analog for AlarmManager. Forget about it.
https://www.raywenderlich.com/92428/background-modes-ios-swift-tutorial
https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
Push notification can be used as a trigger. But, nevertheless, this is a server-side implementation.
In the guide above:
Check the box Background fetch in the Background Modes of your app’s Capabilities.
Use setMinimumBackgroundFetchInterval(_:) to set a time interval appropriate for your app.
Implement application(_:performFetchWithCompletionHandler:) in your app delegate to handle the background fetch.
Your callback event is performFetchWithCompletionHandler
I am developing an app that connects to and modifies data in a database by executing php files.
If I need to make changes to the database or php files, this may cause old versions of the app to behave unexpectedly and crash. For this reason, I want to force users to update the app when such changes are made.
Right now, I have a method that connects to the database and compares the apps version to the databases version. This works fine but I call it every time I access the database (very often) which significantly slows down the usage of the app. Is there a better way to do this? I have read that I could use an AlarmManager or BroadcastReceiver to check for updates every X amount of hours. But what if the user closes and doesn't use the app for a few days. Will these timers get called as soon as the user starts the app and thus be able to force an update?
The Android AlarmManager is an API that let you communicate and program alarm with the Android Alarm Service. Think of it as similar to a Linux Cron job. As soon as the alarm is programmed, then it'll be triggered even if your app isn't running, because the alarm is triggered by the alarm service and not by your app. For instance, the only thing you need to do is to program your alarm. It's important to note that when you restart your device then your alarms are cleared, so you need to reprogram then in every reboot. You can do this by capturing the BOOT_COMPLETED broadcast, so you can reprogram your alarm every time the device boots up. Check out the definition of the Android AlarmManager. A common pattern to do what you want is to program an alarm that sends a broadcast or starts a service, then in that service you can query your server. You need to consider that when the device is sleeping then the alarms couldn't be sent, so you need to work with wakelocks. This class will help you with that, check it out.
I have Android service to run and send email every 9 mins but after some cycles it quits. this app is also installed in my Android froyo but it works good for more than 2months now.. I can see the logs in logcat that the service quits but my problem is I cannot understand what does it mean.. Can someone help me with this? Thanks!! any help would be appreciated...
here is my source code:
https://gist.github.com/77a40ac93cd311acb56c
Logcat logs:
https://gist.github.com/dd3ab385d79253fac632
The point behind using AlarmManager is so that your service only needs to be in memory when it is doing actual work, and can go away in between AlarmManager events. You have managed to not do that, and therefore your code will not work reliably.
If you want to "send email every 9 mins", you should:
Move the BroadcastReceiver to be a public Java class, registered in the manifest via a <receiver> element, and remove the registerReceiver()/unregisterReceiver() stuff.
Switch your service to be an IntentService, so you get a background thread (which you need for your work, but your current code lacks) and so the service can automatically shut down when there is no more work to be done.
Add in the logic for the WakeLock that you will need since you are using a _WAKEUP-style alarm. You could combine this and the previous steps by switching to my WakefulIntentService, if you wish.
Deal with the case where the user reboots the device, if you want your alarms to continue after the reboot, such as by scheduling them again via an ACTION_BOOT_COMPLETED BroadcastReceiver.