What API level should I target?

There’s a lot of confusion in this area. A common misconception is that if you want your app to run on everything from 2.1 to 4.0, you have to target 2.1. That’s wrong.

This post will cover most of what you need to know to get started on making apps that not only supports an old API level, but also take advantage of what the new API level have to offer.


You’re most likely familiar with the <uses-sdk /> tag in your manifest. But that understanding does often not go further than the android:minSdkVersion attribute. First, a brief explanation of the attributes supported by uses-sdk.

Like the name suggests, defines the minimum API level your application works on. This is used by Play Store to detect if the application is compatible with the users device. So, if your minSdkVersion is 7, Play Storewill show the application to devices from API level 7 (2.1) and up. This attribute should be set by all apps!

This defines the maximum API level your application works on. Again, Play Store uses this to detect if an application is compatible with a device. Please note, that there in most cases is no reason to use this! it is perfectly possible to create a single APK which works on every API level from your minSdkVersion and up!

Unlike the other two attributes, this is used by the Android platform itself. This attribute should be set to the maximum API level you tested your application on. If not set, this will default to your minSdkVersion.

Not many new users know about this attribute, but it’s rather important.

As the Android platform evolves, features are added and even removed. To remain backwards compatible, the system needs to apply certain compatibility behaviors. A recent example of this is the menu button. With ICS, this was removed. If the system was not able to apply compatibility behaviors, this would render every app built before ICS useless, since there was no way of getting to settings, or whatever feature is available in the menu. Instead, it can look at the targetSdkVersion and see that the app is tested against e.g. 2.3, in which case it needs to offer an alternative way on ICS devices for accessing the menu. On the Galaxy Nexus, it does this by drawing a menu button next to the regular onscreen buttons.

Compatibility is also applied when it comes to themes. HoneyComb introduced a new set of themes called “Holo”. If these were simply applied to older apps (in case these apps did not manually define a theme in the manifest), it could break their functionality, e.g. draw black text on a black background. Instead, it checks the targetSdkVersion and decides which theme to apply.

Yet another example, and a very good reason to set this attribute, is the move to sd functionality. This was added in API level 8 (2.2). If your android:minSdkVersion is set to API level 7, and android:targetSdkVersion is not defined, devices which run API level 8 and up would not be able to use this function.

Setting android:targetSdkVersion higher than android:minSdkVersion does not break the app on your minimum API level. It will still work perfectly fine.

Build target

Build target is the API level Eclipse/IntelliJ/whatever IDE you’re using is building against. This is simply used by the IDE/build system to know which APIs to offer you. If you build against API level 14, the application will still be able to run on API level 7, providing you don’t call any APIs that are not available on API level 7.

I mostly set the build target to the same as android:targetSdkVersion, though this is not required.

How to take advantage of new APIs, and still remain compatible with older API levels

Any modern app will most certainly want to do this. Technically, there’s no reason to limit yourself just to the APIs available in your android:minSdkVersion.

As a simple example, let’s take a look at the Editor class. In API level 9, a new method named Apply was introduced. The old Commit method synchronously wrote the changes to the internal storage before returning, which could possibly take a while. apply() will commit its changes to memory, and asynchronously write the changes to the internal stroage. This will speed it up a bit.

When deciding which of the two methods to call, we have to check the API level of the device. Luckily, Android offers a simple way to do this. The Build class has everything we need.

First there’s Build.VERSION.SDK_INT. This is simply an integer indicating the devices API level. If you’re running your app on API level 7, this will be 7.

Secondly, there’s Build.VERSION_CODES, which is just the API levels as ints. This makes it more readable.

What we’ll do is save the value “lol” to the key “cat”.

// Get our preferences
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
// Get an Editor object
Editor editor = settings.edit();
// Add our new value
editor.putString("cat", "lol");

// Check if we're running on GingerBread or above
  // If so, call apply()
// if not
} else {
  // Call commit()

What happens is, we check the current SDK_INT against the INT for Gingerbread, which is when the apply() method was introduced. If the SDK_INT is 9 (the value for Build.VERSION_CODES.GINGERBREAD) or above, call apply(). If not, call commit(). Even though Build.VERSION_CODES.GINGERBREAD was not added until API9, this will not crash on API7. This is because the value is static final, and will be inlined when you build your application.

It’s that simple.

This approach only works for Android 2.1 (API level 7) and above. If you support 1.6 (API level 4), the editor.apply() call will have to be wrapped in a static class. These days, very few apps have to support that old versions of Android, so I will not provide an example for this.

But wait! What if I forget to wrap a function call?

Well, first off, ADTr17 brought a new check that warns you if you are using APIs that were made available in a later version than your minSdkVersion. This should make it fairly obvious when errors occour.

Secondly, testing! If your android:minSdkVersion is 7, make sure to actually test it on API level 7. Likewise, if your android:targetSdkVersion is 14, make sure to actually test it on API level 14. Test on tablets, test on phones, test on as many configurations as you can.

It might seem like a hassle that there are so many versions of Android, and so many device configurations. But if done right, it should be pretty trivial.


Additional reading
Google posted a great article on how to use the Holo themes on HoneyComb and above, while staying compatible with pre-HoneyComb devices. You can find it here: Holo Everywhere