The Muzei Plugin API and Android’s Evolution
When Muzei was originally released by Roman Nurik, Android 4.4 KitKat had just come out. With a plugin architecture that allowed other apps to build their own wallpaper source, quite a few apps came out that took advantage of that flexibility.
While there’s been a number of additions to the API such as the ability to access the current wallpaper information, the wallpaper source API hasn’t seen any significant changes: it is still based on started Services and
That’d be great (stable APIs!), except for the fact that Android has evolved considerably since Android 4.4.
Not your traditional Android app
From the beginning, it was clear that Muzei was not your traditional Android app. Muzei itself is a live wallpaper — instead of being a static image, Muzei is responsible for drawing a dynamic background and is able to respond to interactions like double tapping to temporarily unblur the image.
But where Muzei really differs from most apps is in the plugin infrastructure. As Muzei is the ‘front-end’ of the system, many of the plugins don’t have any launcher activity at all — some don’t even have a settings activity, relying on good defaults and Muzei’s built in controls.
This means that Muzei plugins aren’t often explicitly launched by the user. This comes into play particularly when it comes to App Standby.
What is App Standby?
App Standby was introduced in Android 6.0 as a way to reduce the battery impact for apps that are not being actively used. These ‘idle’ apps are unable to access the network and their pending jobs and syncs are held. Of course, since these restrictions are for saving battery, they are temporarily released when the device is charging as well as at least once a day.
Obviously, the best case scenario is your app never being marked as idle. Unfortunately, the primary method of not being marked as idle is to have the user launch your app. As Muzei is designed to run continuously in the background as your wallpaper, the chances of a Muzei plugin to be actually launched by the user (say, loading up the plugin’s settings activity) before the ~3 day time period before being marked as idle is very low.
Muzei itself avoids App Standby while active by virtue of the second way to avoid being marked as idle: by being a foreground process (something automatically granted to the current live wallpaper app). However, you can also be a foreground process by running a Service in the foreground or if the system determines that another foreground process has a direct dependency on your process (this is the case when using a bound Service or a Content Provider). Apps that generate a notification seen by the user are another way to denote an app as active.
The first step in solving a problem is recognizing there is one
So it turns out that the vast majority of Muzei plugins are marked as idle a few days after working perfectly. I know because I see the negative reviews for Muzei and have read through the negative reviews for a number of plugins.
Muzei plugins have limited tools available to them, none of them offering a particularly good user experience. Using
startForeground when loading your artwork forces you to create a notification for something that should be seamlessly done in the background. Asking the user to opt you out of battery optimizations is an extremely heavy hammer that affects your entire app and reduces the effectiveness of Doze as well (which actually doesn’t pose any concern to Muzei since Doze is only on when the screen is off).
Note: if you’re a user just trying to get things working on the current version of Muzei, disabling battery optimizations for your plugin of choice is the best way to get things working in the short term.
Moving away from the local maxima
In so many ways, the current API is amazing. It handles so much for you that it is incredibly easy to build a plugin with just a single
Service. However, that provided structure now serves as a ‘local maxima’ where any change that would allow it to adapt to Android 6.0’s App Standby, Android 7.0’s restrictions on
CONNECTIVITY_ACTION, and the upcoming Android O's background service limitations will change the API so much as to render it quite significantly different and entirely backward incompatible ways.
But you know what? I’m up for it. Let’s make it so that if you hit the ‘Next Artwork’ button, it actually works every time. Let’s make it so that users aren’t surprised by large amounts of data usage coming from Muzei or its plugins. Let’s make it so that Muzei and its plugins are well set up to be good Android citizens and provide the best experience without affecting the overall system health or battery life.
I’ve been prototyping updates to the API that have been extremely promising. When they’re in a working state (or perhaps even a bit before that), I’ll be talking about them here on Medium as well as in the Muzei Google+ Community, which I’d strongly recommend you join.
A few quick FAQs:
- Yes, there will be a considerable overlap in time when both the current and new APIs are supported.
- Yes, there will be public betas that allow you to test your new plugin without negatively affecting users running the production version of Muzei (your app will be able to support both sets of APIs and versions of Muzei simultaneously)
The goal is for the new API to be public and in a production version of Muzei before the end of 2017.
If you’re a plugin developer, I’d love to look through your current plugin code and understand how you are currently using the APIs to ensure that the new API covers your use cases well. If it is already open source, please send a link to your project to firstname.lastname@example.org and if it isn’t open source, feel free to send what code you can to the same email address.