Minggu, 29 Januari 2012

Pin It

Five ways to maximise Android device compatibility

Share on :


Five ways to maximise Android device compatibility
by Shane Conder & Lauren Darcie

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 article originally appeared in issue 91 of Linux User & Developer magazine.Five ways to maximise Android device compatibility Subscribe and save more than 30% and receive our exclusive money back guarantee – click here to find out more.

Android market share has been growing rapidly. With almost two dozen manufacturers developing Android devices, we’ve seen an explosion of different models – each with its own market differentiators and unique characteristics. Users now have choices, but these choices come at a cost. This proliferation of devices has led to what some developers call fragmentation and others call compatibility issues.

Terminology aside, it has become a challenging task to develop Android applications that support a broad range of devices. Developers must contend with different platform versions (Fig 1), devices with and without optional hardware like cameras and keyboards, and variations in screen sizes and resolutions (Fig 2). The list of device differentiators is lengthy, and grows with each new device.

While fragmentation makes the Android app developer’s life more complicated, it’s still possible to develop for and support a variety of devices – even all devices – within a single application. You just need the tools and the know-how to go about it.

This tutorial provides five techniques to help developers iron out compatibility wrinkles, including:
1. Providing alternate resources for different device configurations.
2. Specifying which platforms your application targets and supports.
3. How to change application behaviour based upon the platform version.
4. How to use optional load classes using Java Reflection.
5. Using Market filters to limit which devices use your applications.

Resources:
Eclipse or suitable development environment
Android SDK
ADT plug-in for Eclipse

While this tutorial won’t directly leverage any specific development tools, you will need a functioning Android development environment to develop applications. You may find it helpful to follow along through this tutorial using an existing Android application for reference. Feel free to use your own applications or one of the sample applications provided with the Android SDK for this tutorial.

Let’s begin with the most important thing you need to know about maximising application compatibility. It involves making assumptions, and you know what they say about making assumptions… In terms of designing for device compatibility, our best advice to you is: don’t make assumptions about the device your application is running on.

Don’t assume your users are all running the latest hardware and software (they’re not). Don’t assume they perform regular software and firmware updates (they don’t). Don’t assume that if you design for a specific device, users won’t install it on other devices (they will). Don’t assume that users will avoid application features that clearly aren’t supported by their device (they won’t, but they will tell you all about what happens when they try it).

Don’t even assume that the device is a phone (not all Android devices are). When you make assumptions about the environment in which your application will run in, you are simply introducing prerequisites to your application that require enforcement, limiting your user audience, and creating potential problem areas within your application.

So, just in case it was unclear, don’t make assumptions about your devices or your users. Now, we know what you’re thinking. If you don’t make assumptions, you have to handle every possible case, right? You have to settle for developing mediocre apps that suit everyone, using only core APIs, instead of developing awesome apps that take advantage of this optional feature or that kind of screen. Not so! And we’ll get to the ‘how’ in a moment.


Android App compatibility FIG 1



Android App compatibility FIG 2



Android App Compatibility FIG 3

Android App Compatibility FIG 4

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…

While you won’t always be able to completely avoid making assumptions, you need to minimise the ones you do make and understand the trade-offs of making them. Certainly there are times when you’ll want (or need) to make strategic decisions to limit your application in certain ways, but the less you do this, the more users you’ll be able to cater to.

You do, however, need to consider which differentiators apply to your project. As part of the design process, you should determine which application features are most likely to encounter differentiators in order to support them. For example, you need to be (at least somewhat) aware of the various screen sizes and resolutions available on Android devices. Sometimes, a good graphic designer can craft an Android user interface that looks great across all screen resolutions, aspect ratios and orientations (this, however, is a discussion for another day). Other times, they’ll simply want to make subtle adjustments based on specific criteria, which brings us to our first technique for supporting different device configurations.

Android applications can include alternative resources to load only when the device environment matches a set of criteria, including screen specs, input methods, language settings and device state. Layouts, graphics, strings and dimension values are common resource types to tweak based upon device settings.

An application might include alternative string resources that load only if the device is running in a foreign language. Similarly, developers might include alternative layout resources to load depending on whether the device is in portrait versus landscape mode, or different graphics to load based upon the screen size, aspect ratio or pixel density of the device. The Compatible project includes a number of alternative resources (Fig 4).

The application includes:
1. Different icon graphics for low, medium and high density screens.
2. A default layout and an alternative layout file for portrait-mode orientation.
3. Default strings (English, perhaps) as well as French string resources.
4. Dimension resources for small and large screens as well as default dimension values.

Alternative resources are stored in the resource hierarchy using special directory name qualifiers. The Android operating system does the rest, loading the appropriate resources based upon the device settings and state. For a complete list of qualifiers, see the Android Dev Guide on Providing Alternative Resources. Ideally, you design your application to use the use the smallest number of resources possible to keep the application package footprint reasonable and for maintenance purposes.

The Android SDK has been updated more than half a dozen times in the past two years. Exciting new APIs have been added, others have been deprecated. Classes have been renamed, functionality has changed. While it’s great that the Android development team is on top of things, this also means that users are running different versions of the platform. Some are stuck on older versions due to hardware limitations, while others are on the bleeding edge with their hot, new devices. Unfortunately, if a developer chooses only to support one group of users, they’re cutting out potentially 50% or more of the market – not good.

This means that developers routinely have to build applications that support multiple versions of the Android SDK, either simultaneously or by developing separate applications for each version. We tend to shy away from the whole idea of developing different versions of the same application for subtly different devices because this causes all sorts of maintenance and support headaches.

Since we refuse to bow to the whims of a specific device differentiator, instead we do our best to incorporate its quirks into our application designs. So let’s look at three ways in which developers can stick to a single codebase and support device differences simultaneously…

The manifest file is used to define the configuration details of an Android application. It can also be used to specify any system requirements necessary for the application to run properly. Developers can specify which versions of the Android platform an application supports within its Android manifest file using the tag. The manifest tag is enforced by the Android operating system. It is also used by the Android Market to filter applications to the appropriate devices.

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):
1.<uses-sdk android:minSdkVersion=”2” android:targetSdkVersion=”8”></uses-sdk&gt

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:
1.// This will work on all Android platforms, but is a cumbersome string (deprecated)
2.String strAndroidVersion = android.os.Build.VERSION.SDK;
3.Log.i(DEBUG_TAG, “The current Android version string is “ + strAndroidVersion);
4.// This will work on Android API 4 (Android 1.6) and higher
5.int iAndroidVersion = android.os.Build.VERSION.SDK_INT;
6.Log.i(DEBUG_TAG, “The current Android version number is “ + iAndroidVersion);
7.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.

9.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.
10.The detection of a class involves slightly more work.

12.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.

14.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.

16.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.

18.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.
19.1<uses-feature android:name=”android.hardware.touchscreen.multitouch” android:required=”true” />

// 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);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.
1<uses-feature android:name=”android.hardware.touchscreen.multitouch” android:required=”true” />

// 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);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.
1<uses-feature android:name=”android.hardware.touchscreen.multitouch” android:required=”true” />

Applications can use the 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.


Tidak ada komentar:

Posting Komentar