Five ways to maximise Android device compatibility
Don’t just be satisfied with a working Android app. Learn five essential development techniques to maximise application compatibility across Android’s massive range of devices…
This tag has two important attributes: the minSdkVersion attribute and the targetSdkVersion attribute. The minSdkVersion attribute specifies the lowest API Level that the application supports. The targetSdkVersion attribute specifies the API Level that the application ideally uses (where it was tested thoroughly etc). In order to support the greatest range of devices, you’ll want to set your minSdkVersion to the lowest API Level you can, even if it does not match your targetSdkVersion. For example, the following manifest tag specifies that the application supports Android platforms as old as Android 1.1 (API Level 2), while targeting Android 2.2 (API Level 8), and should be forwards compatible (no maxSdkVersion attribute is set):
[sourcecode language=”java”]<uses-sdk android:minSdkVersion=”2” android:targetSdkVersion=”8”></uses-sdk>
When you want to modify application behaviour based upon the Android platform version, you need to be able to detect the platform version (in the form of the API Level) programmatically at runtime. You can detect the Android version of the device as follows:
[sourcecode language=”java”]// This will work on all Android platforms, but is a cumbersome string (deprecated)
String strAndroidVersion = android.os.Build.VERSION.SDK;
Log.i(DEBUG_TAG, “The current Android version string is “ + strAndroidVersion);
// This will work on Android API 4 (Android 1.6) and higher
int iAndroidVersion = android.os.Build.VERSION.SDK_INT;
Log.i(DEBUG_TAG, “The current Android version number is “ + iAndroidVersion);</pre>
There may be times when you want your application to support older platforms, and optionally load classes only for newer platforms or optional add-ons. This can be achieved using Java Reflection. The general idea is to identify the functionality necessary for the application and create a wrapper class to expose that functionality for all platforms generically. Internally, that class can then use various Java language features to detect the presence of new classes or new methods within existing classes.
In brief, the detection of a specific new method within an existing class can be achieved by calling getMethod() on a class object and storing the result as a Method object or setting a flag that what you’re looking for doesn’t exist. You could then call a wrapper method that either uses the invoke() method, passing in the Method object, or provides alternate functionality, either disabling a feature or implementing similar behaviour in a different way.
The detection of a class involves slightly more work.
First, you create a wrapper class exposing an identical interface to the class you want to be able to use. Then, each of your wrapper class methods makes a direct call to the underlying class. However, the trick is in using a static initialiser to determine if the underlying class exists. If it does not, your wrapper class can throw an exception. Your application will need to handle the exception and provide alternative behaviour.
While it’s generally considered preferable to support as many devices as possible with a single application package, there are times when you really do want to limit the devices on which your application will be loaded. There’s nothing worse than to be receiving complaints and negative app reviews from users who had no business trying to run your application in the first place.
So if your application’s sole purpose is to allow the user to scan barcodes with the camera, you want to ensure that your application is only deployed to Android devices with camera hardware, right? Luckily, you can use the <uses-feature> manifest tag that can help you with achieve this goal.
The <uses-feature> tag can be used to identify used or required hardware features the application relies upon. For example, adding the following tag to your application manifest informs interested parties that the application requires multi-touch functionality to operate properly.
[sourcecode language="java"]<uses-feature android:name=”android.hardware.touchscreen.multitouch” android:required=”true” />[/sourcecode]
Applications can use the <uses-feature> manifest tag to identify application prerequisites such as: camera features, sensors, live wallpaper support and telephony support. Using this tag doesn’t completely eliminate compatibility concerns, since the Android operating system does not enforce this manifest tag. However, popular marketplaces like the Android Market will filter your application and make it available only to users with the appropriate hardware configurations.
However, if you are using other delivery mechanisms, such as self-publication, then this method won’t help you. Perhaps in the future, the Android platform will at least warn the user if an application’s hardware requirements do not match the device’s hardware configuration. You can, however, use the PackageManager.hasSystemFeature() method to determine this information at runtime within your application.
At this point, you may be thinking that trying to cram all functionality into a single Android application package isn’t worth the effort. You’ve got to be careful not to over-customise your application for specific devices. While it’s true that sometimes it just doesn’t make sense to bother, you can, through judicious use of the techniques we’ve discussed, drastically simplify the development required to support a wide range of devices.
Is this or that Android SDK feature supported?
When developing applications for multiple target platforms, Android developers need to pay special attention to the API Level associated with a given package, class, method or constant in the Android SDK. The API Level in which a given class, interface or method was introduced is always listed in the SDK documentation. For packages, classes and interfaces, the API Level is shown in the top right-hand corner of the Java documentation, whereas you will find the API Level for a specific method to the right of the method name. How to determine the API Level in which an Android SDK class and its methods were introduced is illustrated in Fig 3.
The techniques discussed here also scale well and can be used to support the subset of device differentiators important to your particular project, whether they be different platform versions, screen types, languages or some other combination of device features.