Some apps, especially those no longer maintained, severely misbehave when an android device with Marshmallow enters doze mode. Apps designed as alarm clock replacements or schedulers to perform certain tasks in the future no longer work reliably, completely defeating their purpose.
Workarounds are well known for developers, or when the affected apps are open-source, e.g. answered here and documented here.
But how can closed-source apps, whose authors no longer maintain them, be fixed?
Note that disabling battery optimization for an app will not help with doze mode as answered here.
This answer applies to apps that suffer from late wake-ups due to using AlarmManager
's set
and setExact
methods. These methods set alarms that are only delivered during doze "maintenance" windows or when the device wakes up due to user intervention or other circumstances.
The solution is to use setAndAllowWhileIdle
and setExactAndAllowWhileIdle
methods, respectively; but being able to modify and recompile apks is the trick.
apktool_2.1.1.jar
as of this writing.Assuming java binaries are in your path, and the apktool jar and the apk are in the current dir, disassemble the apk with apktool
:
$ java -jar apktool_2.1.1.jar d com.example.android-app.apk
The disassembled files (smali
format) will be under com.example.android-app/
in the current dir.
Replace all occurences of AlarmManager;->set/setExact
with AlarmManager;->setExactAndAllowWhileIdle
in all the disassembled smali
files. You can either do this manually, or automate it with find
and sed
:
$ find com.example.android-app -name *.smali -exec \
sed -i -e 's/AlarmManager;->set\(Exact\)\?(/AlarmManager;->setExactAndAllowWhileIdle(/g' {} +
This will replace both set
and setExact
with setExactAndAllowWhileIdle
.
Rebuild the apk:
$ java -jar apktool_2.1.1.jar b com.example.android-app
Note the b
for build, and the lack of .apk
to refer to the directory where the modified files are. The resulting apk is created as com.example.android-app/dist/com.example.android-app.apk
Sign the apk. This is the annoying part if you never signed a jar file before:
First create a keystore and a signing key in one step (official documentation):
$ keytool -genkeypair -validity 36500
Enter keystore password: android
Re-enter new password: android
What is your first and last name?
[Unknown]:
What is the name of your organizational unit?
[Unknown]:
What is the name of your organization?
[Unknown]:
What is the name of your City or Locality?
[Unknown]:
What is the name of your State or Province?
[Unknown]:
What is the two-letter country code for this unit?
[Unknown]:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
[no]: yes
Enter key password for <mykey>
(RETURN if same as keystore password):
This creates a keystore with password android
in the default location and a signing key named mykey
, also with password android
.
Now sign the rebuilt apk (official documentation):
$ jarsigner -tsa http://timestamp.digicert.com com.example.android-app/dist/com.example.android-app.apk mykey
Enter Passphrase for keystore: android
jar signed.
This signing procedure is essential, as your android phone will reject your apk if it is unsigned with a cryptic message like:
Parse error
There was a problem parsing the package.
Uninstall the original app from your phone. This is essential, as the new signing key is different from the original author's signing key, and android will refuse to update an app when the signing key changes. If you try to update the pak, the built-in package manager will simply tell you:
App not installed
You may wish to make a backup or save the configuration of the app, if necessary.
Get the rebuilt apk to your phone and install it. There are various ways to do this, but these two are the easiest:
enable USB debugging and then run:
$ adb install com.example.android-app/dist/com.example.android-app.apk
file:///sdcard/
in your phone's browser and clik on the apk to download it, then open it from the downloader to install it.The app should now work properly with doze mode, while your doze mode may be slightly less effective in conserving battery than before, depending on the amount of wake-ups the fixed app causes.