I currently use the Firebase JobDipatcher to perform a periodic task in the background. The problem is the background service only gets executed when battery optimization is disabled and standby state of the app is manually set to ACTIVE under developer options. Is there a way to do the background task without manually changing all this, because i cannot ask every user of the app to do so. And saw many posts that google will suspend the app if the power management permissions are requested within the app. Any help would be much appreciated.
In one word answer is BIG NO
As developers remains unhappy with such small answers, so i am starting the HUGE theory, here we go -
STRATEGY NO - 1 :
Use AlarmManager
All alarms are forgotten by the android on Reboot, so keep all alarms in app Sqlite database, implement BOOT_COMPLETED broadcastreceiver, which is still allowed to define statically & re-schedule all alarms by taking from apps database.
All your project & hard work will work as per your plan, but only on emulators
Because in real world, 99% devices are with chinese ROMs like MIUI, OxygenOs, ColorOs, FunTouchOs, .. which never triggers your apps BOOT_COMPLETED broadcastreceiver.
Because they all are ahead in saving battery life, by stopping all apps background services..!!
Nice question,:- Then why whatsapp, facebook, tiktok, twitter processes are getting executed normally...?? And why not mine...??
Nice answer,:- If Chinese ROMs disallowed above apps background services then no one will buy their devices..!! And lets do not talk about your application as it does not affect the world in any way, your app is useless ( as per chinese ROMs ) , so they disallows all other packages background tasks..!!
All Chinese ROMs never triggers AlarmManagers if the app is not in foreground. Never triggers if app is removed from recents
In short & sweet treat Alarmmanager as depriciated.
STRATEGY NO - 2 :
Use FirebaseJobScedular as you stated
If user updates Google Play Services , then system forgets all jobs..!!
Again FirebaseJobScedular was developed to run all jobs on every device in market, but as chinese ROMs never allows any processes / classes / Jobs from their own wishlist, this makes no sense again.
This library is depriciated by google now.
STRATEGY NO - 3 :
Use WorkManager, the new library which is taking place over the FireBaseJobScedular officially.
Again the same thing, WorkManager is still in development, you can use it, but the case is same that many chinese ROMs discard this libraries jobs too..!!
STRATEGY NO - 4 :
Run all time foreground service.
BOOT_COMPLETED from your broadcastreceiver start it again.
But even if you use START_STICKY, many chinese ROMs used to suspend its tasks, you can see it in foreground, but works gets suspended.
STRATEGY NO - 5 :
Use WakeLocks
But as the android version changes, it has changed to the newer newer implementational strategies in every versions
STRATEGY NO - 6 :
Programatically make battery optimisation off for your app, but google discontinues your app from app store in such case
Navigate user to battery optimisation settings intent, by opening it programatically & let him choose battery optimisations on his own, is allowed by google
But as no user is in market, who knows it, as even many developers dont know this yet, how end users can understand it..??
Again if power saving mode ( it is different than battery optimisation okay ) is made ON by user then, no way your battery optimisations is never considered.
What the ***** should i do then ...?
Nothing as developer.
Train your support / sales team to "LOCK" your app in the recents of every phone, after which, users are unable to swipe it away from the recents, even if it is swiped away, your all above strategies will work & your jobs / alarms / tasks will be executed, as it happens on your android emulator or as on stock android
Train your support / sales team how to make battery optimisations to "Do not optimise for this app" too..
It is so out of the box solution..??
Yes, it is. As in the market you will notice 1% stock android devices and 99% chinese modified ROMs
This all knowledge came to me after i lost last 9 to 10 years resolving the same problem, Hussshhhh
Related
I've been using WorkManager to create notifications for my app. For my purposes I figured PeriodicWorkRequest is the most fitting, but after a bit of testing and reading online it's seems extremely unreliable. Using the minimal interval (15 minutes), and the app being closed, the worker woke up 5-6 times and then seems to be killed.
So how does one go about creating background work that wakes up in reasonable time intervals? What is the best approach for creating event-based notification? My idea was checking for the event (for example, checking for something new in the database) in small time intervals (with 15 minutes also being less than ideal), but seeing as it doesn't work well with PeriodicWorkRequest and is also the recommended approach as per the documentation, what exactly are my options?
Basically, the idea of Android is for you not to be able to do what you want to do because we as developers try to kill the battery.
You need to see how the evolution of the restrictions goes:
Version 6 - Doze:
https://developer.android.com/training/monitoring-device-state/doze-standby
https://developer.android.com/about/versions/marshmallow/android-6.0-changes#behavior-power
Version 7 Another state of Doze with even more restrictions:
https://developer.android.com/about/versions/nougat/android-7.0-changes#perf
Broadcast Restrictions:
https://developer.android.com/guide/components/broadcasts
https://developer.android.com/about/versions/nougat/android-7.0-changes#bg-opt
Version 8.0 Background execution limits:
https://developer.android.com/about/versions/oreo/background#services
Version 9 StandBy Buckets - where depending on how the app is used you have different resources to use - like time to wake up the app, time to use the Network, etc
https://developer.android.com/about/versions/pie/power#buckets
https://developer.android.com/about/versions/12/behavior-changes-all#restrictive-app-standby-bucket
https://developer.android.com/topic/performance/appstandby
Battery Save improvements:
https://developer.android.com/about/versions/pie/power#battery-saver
Power Management Restrictions - really important.
https://developer.android.com/topic/performance/power/power-details
Version 11 and 12 App hibernation
https://developer.android.com/topic/performance/app-hibernation
Long story short - you need to prevent all these restrictions to harm your work. But you need to comply because it is better for the user.
But there is no API that will just say - "f**k all these restrictions and do whatever the dev wants to do."
If you need exact timing - you need AlarmManager.
If you do not know when you need to do your work and depend on the outside - Push Notifications which then can transfer the work to the WorkManager.
If you need periodic work that is not time-critical - you might not use the AlarmMangaer and be sure that the work is finished, but you can't be sure when, because there are many restrictions and the priority will be saving the resources.
Also, you can ask the user to be exempted from Battery Optimization:
https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases
If you want to know why exactly the work is not executed you need to check the JS dump and see what restriction is not satisfied:
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/debugging#use-alb-shell0dumpsys-jobscheduler
I have an app that generates data that needs to be sent to my server eventually (several hours of delay are no problem at all). I would like to do this with minimal impact to the user, which means to me:
Minimal battery use
No extra permissions, especially not "sketchy" ones
No other strange changes to the system (see example later)
So far I've found three approaches, that all have some serious problems:
Using a SyncAdapter triggered by a network message:
Technically, this sounded like the perfect answer to the problem: Have the system call a service in my app whenever it's doing something on the network anyways. That way, the network is guaranteed to be available, there's barely any extra battery use, since the radio is already on, and the whole thing happens in the background...
And then I tried actually implementing it...
Unfortunately, this approach requires some weird modifications to the system: My app needs to create a new dummy account for the sync-process, even if my app doesn't otherwise use any accounts. And unfortunately, this account cannot be hidden from the user, so now my app is listed when the user clicks "Add Account" in the System Settings, but inside the app, there is no indication of user accounts anywhere... Also, I need to request all sorts of strange permissions, like "Create accounts and set passwords", "Toggle sync on and off", and "Read sync settings". Why would an app that doesn't even provide me with a user account require a permission to set passwords on my device??? Not cool... Delete!!!
Using a BroadcastReceiver and checking for connectivity when it fires:
This requires permission to "view network connections" and possibly even "view information about Wi-Fi networking, such as whether Wi-Fi is enabled and names of connected Wi-Fi devices" ... Why would this app care about my wi-fi or network neighborhood? Creepy... Not getting installed on my device...
The nice thing about this approach is that a network connectivity change likely only happens while the radios are turned on (at least a change to the "available" state). So, if I use this event to trigger an upload (attempt), the battery-impact will be minimal as I won't cause the radio to turn on just for the upload. Unfortunately, this event will probably not be called very often. And to make matters worse, from the docs it sounds like the BroadcastReceiver will only be called while my app is in the resumed-state. So, I won't even be able to make use of events while my app is paused... I.e. using these broadcast events will only be slightly better than option 3:
Just blindly initiating the upload at regular intervals and, if it fails, retrying it again later:
This approach doesn't require any strange permissions and doesn't mess with any system settings. But, clearly, it is the worst I can do for battery use. So, while it's workable, I'd rather find a smarter alternative...
Is there a way to fix the issues of one of the first two approaches? The optimal solution would be a SyncAdapter without a dummy user-account, or, at least, with a hidden one, or one that already exists in the system... But many hours of searching didn't yield any usable answers...
Or is there another better way altogether?
#CommonsWare pointed out two further approaches:
Using JobScheduler:
This allows scheduling jobs for future execution that depend on certain network connectivity or even a certain charging status of the device. It says that it tries to batch job executions for all applications on the system, which may save battery by avoiding additional radio activation, if other apps also have jobs executing that access the network. But if my app is the only one needing to do a network request, I don't think the JobScheduler provides quite the same amount of battery-saving as a network-tickle-driven SyncAdapter would. This is just a guess based on my current understanding, though.
The big issue with using the JobScheduler is that it requires API level 21, i.e. Android 5.0+. For some apps, this might be acceptable, but for me it's not...
Using Google Play Services' Cloud Messenger API, specifically GcmNetworkManager:
This seems to provide pretty much identically the same functionality (except for controlling the retry-backoff-strategy) that the JobScheduler does, except it is available on all devices that have Google Play Services v7.5 or higher installed. Google Play Services is available for devices as far back as Android 2.3, but v7.5 was only released end of May 2015. So, while v7.5 is also available for Android 2.3, it is not guaranteed that it is installed.
To use it, the (supposedly very lightweight) Google Play Services API library needs to be added to the app, which provides the method GoogleApiAvailability.isGooglePlayServicesAvailable(...) that can check if Google Play Services is indeed installed and updated to the version required by the API library. To maximize the chances that this is the case, the API library v7.5 can be added to the app (see here and here for how to get it). If the check fails due to a user-resolvable problem, the library even provides the required dialog to prompt the user to fix the issue (e.g. run an update, ...).
The major advantage of this approach is that it does not require any extra permissions for the app and it doesn't rely on any other changes to the system (mock user accounts, ...). So, it is entirely transparent to the user.
I also found one additional approach, somewhat related to point 3 above:
Using AlarmManager.setInexactRepeating(...):
The AlarmManager also tries to batch callbacks together, just like the JobScheduler and GcmNetworkManager do. In fact, looking at LogCat that sometimes reads "AlarmManager: Checking for alarms... com.google.android.gms", it seems that GCM, and probably also JobScheduler, use the AlarmManager to trigger their execution. The features missing from the AlarmManager are: Suppressing a callback based on network connectivity or battery charging status, and automatic retries of failed executions with a back-off schedule. Technically, one can easily add these features, but some of them, like checking for network connectivity, might require additional permissions.The major advantage of this approach is: It's available on almost all devices (starting API level 3).
Currently I have the GcmNetworkManager approach implemented (point 5) and it works as expected.
But I'm actually considering moving to AlarmManager.setInexactRepeating(...) (point 6) to maximize compatibility. Checking for the device charging state seems to be possible without extra permissions and rather than checking for network connectivity, I can just fire off the http request and check whether it failed... The only feature I would be missing is determining whether the user is on a metered connection or not. And, of course, it will be a bit of work to implement retries, back-offs, ...
Update:
It seems like JobScheduler actually does detect existing network activity (see this JobScheduler introduction), which might make it superior to just using the AlarmManager, and pretty much as good or better than SyncAdapters... The GCM documentation also claims callback optimization based on current network activity (not just availability)... So, I guess the optimal solution would be to use the JobScheduler where available and fall back to GCM where it's not and to the AlarmManager where GCM isn't available either... Yuck...
I have an application that i have developed for ios, android and windows phone 8. The client now requires that the application checks if there is any data to be uploaded to the server every 15-30 minutes and if so, upload it. This is needed because the application is used in areas where there will not be an internet connection. The user adds data into the application and that data needs to be uploaded to the server once an internet connection is available
I have implemented this on android using the AlarmManager to schedule the application to check if there is any data and upload it, and on windows phone i used a PeriodicTask.
Is there such functionality in iOS? When i try googling this, i get many different things appear like NSURLSession, Background Transfer Service and others that say it ain't possible.
So, it is possible and what classes do i need to look into to get this working? If i have to aim at a particular iOS version then that is fine.
You can use NSTimer:
[NSTimer scheduledTimerWithTimeInterval: 1800.0 target:self selector:#selector(yourselector) userInfo:nil repeats: YES];
Apple documentation
No, this is not possible, well may be. Since only specific apps can run in the background like: AudioStreamer, VOIP, Accessory companion or location tracking.
These apps can't really schedule a task. Also it would be really bad for the battery to check some server every 15-30 min.
You can use NSURLSessions to create an uploading task that will run on the background.
You will have to setup the session correctly with all the delegate methods implemented: Background Transfer Considerations.
There are mainly 3 things to consider:
1.) Will the app remain active (visible on the device screen) for 15-20 mins. I suppose that won't be the case.
2.) When the app enters background state (not visible on the app screen, but is in the background), you can perform/schedule tasks for a maximum of 3 minutes.
3.) If the user kills the app (the app is not in background mode) then you cannot do anything.
NSTimer *yourTimer = [NSTimer scheduledTimerWithTimeInterval: 1800.0 target:self selector:#selector(YourMethod) userInfo:nil repeats: YES];
please try this ... this will work...
The upload task supports background operations by default (refer : https://developer.apple.com/reference/foundation/urlsessionuploadtask).
But that is limited to as long as the app is in memory. This is to ensure no app consumes battery without absolute NEED.
What you can do is upload in the background mode and check for pending upload data every time you launch your app.
Some background on my application: I am developing an app that will be used by a small user study group. They are to go through two separate short questionnaires throughout a day. Within a day I schedule seven notifications to fire. If a user clicks on a notification they are taking to complete one of the two survey types. Each notification will be cancelled within 3 minutes of it triggering. If a user does not access the notification within that time, then the app records that a notification has been missed. There is also bedtime function (user receives no notifications) and a delay notification function for notifications that are currently triggered.
I add local notifications with this plugin:
https://github.com/katzer/cordova-plugin-local-notifications
So on to the weird issues... I have been debugging my PhoneGap application religiously for the past two weeks and everything seems to be working perfectly when I debug the application in Eclipse with my phone. A member of my research group says that he sees certain GLARING bugs in the application when he runs my release, but I have could not reproduce them while debugging in Eclipse. I figure he is using an old APK and doesn't know what he is talking about, as I had already fixed the issues he was mentioning...
Then I unplug my phone and carry it around with me for a day and all is well until the next morning when an alarm is scheduled to go off and wake me up. I hear nothing, so I continue sleeping. When I eventually wake up I see that I have a stack of 3 notifications in my status bar, all of which cancel at the same time about three minutes after I wake my phone up... I should mention that for the sake of debugging, I increased the number of surveys a day to 50, explaining the quick succession of notifications.
Now I've recently come to the conclusion that this is an issue with how Android conducts memory management-- Android will kill low priority tasks, such as the javascript timeout functions that I have running via a background-mode plugin
background mode plugin I use: https://github.com/katzer/cordova-plugin-background-mode
It turns out that , for Android, this plugin only enables/disables a flag that tells Android not to kill the process... however for the sake of memory management, this flag is overridden and the js functions running in the background of my application are killed... this explains the previous strange behavior.
However, there a couple other odd things that only happen to my app when running it in release... If I delay a notification (cancels current notification and adds another one ten minutes from now), sometimes the login process screws up, requiring me to login twice at a minimum. Sometimes the login procedure just repeats itself over and over again, taking the user to the main menu then sending them back to the login screen. Other times I cannot log in at all... However, if I keep trying to log in, it will eventually give way and I can get in, but only after quite a few tries...
I have been through my code very thoroughly and there is no way that my code would result in this sort of behavior... What I am wondering is if this memory management issue mentioned above is contributing to these strange states of the application? Why does this not occur when I debug within Eclipse (This has never happened when debugging)?
I have no experience debugging issues with memory, but this is the only explanation as to why my code is acting so strangely...
I can post code, but I don't know how much use it will be... Really I just want to know if this sounds familiar to anyone who has experienced issues with Android managing its memory.
I've been in contact with PhoneGap Support and they have this to say,
"I talked to our lead Android developer on our team and he had this to say:
"Yeah, this guy is going to get garbage collected if he leaves his Cordova app running for a long period of time. We allow apps to run in the background for short periods by default since this is what people expect with the Android life cycle, but anything not on top of the stack is low priority, and you will need to implement a background service to do what he's wanting.
As far as running on Eclipse, anything with a debugger attached will be kept alive, because the debugger is a system process and has higher priority."
Al"
I am a complete Android programming newbie.
I have completed some tutorial examples like HelloAndroid and the HelloViews/Layouts, but that is about the extent of my Android programming abilities.
I am not the programmer on this project, I am the tester(QA) for a company that is developing an Android application that will track company owned devices every 1 minute, and send the positions back once 5 or so are stored.(Limiting mobile network usage, to conserve battery.) My company bought and pays for the android devices, and the employees are aware they are being tracked, both for safety purposes of the employees as well as accountability. Behind making phone calls and some mild emailing, this is one of the most important functions/uses of our devices.
Our biggest problem is that our application can be killed at any time by the Android OS, for any number of reasons(device resources, etc.) Right now, we have an Android service that checks if our app is running every so often and if not, it starts it back up. Once our app is running it can be in the background and request positions using a service in the app itself, then send them to our server for processing and storage.
From everything I have read about Android Development practices, this does not seem to be the most Android "appropriate" way to do this. From what I can gather, and this is fairly limited, we should have an Android service that runs in the background and requests then sends positions, but even this can be killed without notice from the OS, right?
Any advice or suggestions anyone could provide that would point me in the right direction?
It might be worth mentioning that this will kill everyones battery extremely fast... but you pretty much have it right as far as the best way to do it. If the OS does kill your app in the background, your service can just restart it.
What are your concerns, that the OS will repeatedly kill it and not allow it to do its job?
Or that the GPS locations wont be accurate? Location.getAccuracy() could help you figure out if the location is worth saving
http://developer.android.com/reference/android/location/Location.html