When building a new Android application, we are always aiming to support most of the OS versions currently in use in the Android’s fragmented ecosystem. This range of OS versions is defined by three numbers: minSdkVersion, targetSdkVersion and compileSdkVersion, and they greatly influence the way we develop. The minSdkVersion is the lowest version of the OS we prepare our application to run successfully for. The target version is the one the application was meant to run on. And lastly the compile version is what would be used to compile/build the application from source code. Usually compile and target versions are set to match.
All versions before the latest we support are going to lack newer APIs, and we can either restrict functionality based on the OS the application is running on or provide the so-called forward compatibility. The latter can be achieved by using the platform’s support libraries, which allows us to include newer features and concepts introduced in later OS versions for devices running older versions.
However, there is one more kind of compatibilty between versions we need to have in mind – the backward compatibility. This is how new versions of the platform impact code written for older versions. The Android platform’s evolution tends to consider this and tries to minimize the effects on older versions and so developers are encouraged to always set the tartgetSdkVersion to the latest available. When you have targetSdkVersion that is lower you are even presented with a warning:
So one can be tempted to just increase this number as soon as possible, expecting the application to keep working as before. But there is a trick – this can actually make your app not behave as expected or even break it. Here is my list of the side effects that can be caused when increasing targetSdkVersion.
1. Runtime permissions – Android Marshmallow
This is probably the best known change. Before Android 6.0 (Marshmallow) applications requested permissions on installation. These permissions used to only be declared in the Manifest file. In 6.0 or later this behavior changed for some of the permissions – it does not suffice to just declare them and they have to be requested explicitly from the user at runtime. If you had an application using any of these permissions and targeting below 6.0 then your application runs the same as before even on Marshmallow devices. However, if you just go and change the target version to Marshmallow you get an application crash when the permission was needed for certain functionality. The implicit expectation is that if you target 6.0 you would know to change your approach to permissions.
2. HTTP communication – Android P
Android P has just been announced and this change is still subject to interpretation and speculation, but it seems like starting from Android P applications will need to explicitly opt in to using unencrypted web communication protocol (pure HTTP). This has the potential to affect a huge portion of the Android applications.
3. File system permissions – Android Nougat
Applications targeting Nougat and above can not make files in the application’s private storage world-accessible (meaning accessible to other applications). This is security-driven restriction and sounds quite sensible. Yup, but actually by the time Nougat was released there were still many tutorials in the web advising towards sharing content between applications exactly via temporarily changing access permissions of the needed files. Thus, this change had significant impact for many.
4. Push notifications – Android Oreo
If you switch your targetVersion to 8.0 then you need to change the way you register to push notifications in order to receive them. You need to implement the newly introduced notification channels (read more here). This is done so users of Oreo+ devices can unsubscribe from particular notification channels of an app, but if you do not make any channel implementation, no notification will ever be delivered. If you do not know about this change it is very easy to overlook it and thus your Oreo users will never hear a single sound from you.
5. No implicit manifest broadcast receivers – Android Oreo
It used to be quite easy – just declare your broadcast receiver in the manifest – the broadcasts it subscribes to and the class that will handle them. With Android Oreo and above the application can not register to any implicit broadcasts. Of course, as a big fan of CommonsWare, I would recommend his article on the topic.
Android team has been listing the changes related to every platform update on dedicated pages e.g. Marshmallow, Nougat, Oreo. In Oreo they also provided a migration guide, which, I think, is a good idea. This, however, introduced two sources of truth which allows for mistakes (a mistake actually did happen, as notifications are not mentioned at all in the change list).
The above list is a selected extract of all the issues one might run into when updating targetVersion. There, of course, are even more and it might sound reasonable to not update the targetVersion at all. This, of course, is not the way to go either:
- Using this approach one will not be able to make use of the new features introduced in Android.
- Starting with Android P the market will not accept new applications or updates that are tergeting too old SDK versions (see initial announcement here).
The take away from all this is that progressively updating your targetVersion is a must, but it needs to be done cautiously and with awareness for possible regressions.