Search code examples
androidbackwards-compatibility

Android backward compatibility but still utilise latest API features


I have noted in the Android Market that many popular applications have backward compatibility to much earlier versions of Android. E.g.

Evernote - 1.6
Faceobook Messenger - 2.2

These applications look and work great but how can they do this and support much older API levels? Are they only using API features that exist in the lowest supported OS version, hardly? I'm assuming they must be using some features of the later API levels to provide a great UI and featurelist.

I can see two possible solutions:

Use Min/Target API levels in build. Then through code you check the OS version and implement the features using a supported method and degrade gracefully. This seems like a lot of work.

Have multiple app versions targeting various OS versions. E.g. A release for 2.2 and another for 4.0. Is this possible?

The reason for asking is I am planning a new app that should support 2.2 but I fear I may require API features that are only available in later releases? Should I just target 2.2?

EDIT: Also, what role do Compatibility Libraries play? Is this the key?

Thanks.


Solution

  • We (Evernote) do extra work to support 1.6 and use as many new API's as we can. The main problem with supporting 1.6 is that Dalvik does a greedy search on your classes. This makes it impossible to use code like

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
        prefEditor.apply();
    } else {
        prefEditor.commit();
    }
    

    Because it would throw a class verification error. This is caused when dalvik sees your method and tries to access it at runtime.

    Instead you need to use a helper class to instantiate the appropriate class for the SDK. Yes this is much more work

    public abstract class SharedPreferenceEditor {
    
      private static SharedPreferenceEditor sInstance;
    
      public static SharedPreferenceEditor getInstance() {
        if (sInstance == null) {
    
          /*
          * Check the version of the SDK we are running on. Choose an
          * implementation class designed for that version of the SDK.
          */
          @SuppressWarnings("deprecation")
          int sdkVersion = Build.VERSION.SDK_INT;
          if(Evernote.DEBUG)Log.d("SharedPreferenceEditor", "sdkVersion=" + sdkVersion);
          if (sdkVersion < Build.VERSION_CODES.GINGERBREAD) {
            sInstance = new CommitSharedPreferenceEditor();
          } else  {
            sInstance = new ApplySharedPreferenceEditor();
          }
        }
        return sInstance;
      }
    
      public abstract void save(SharedPreferences.Editor editor);
    }
    

    Then you have one for the gingerbread + api level

    public class ApplySharedPreferenceEditor extends SharedPreferenceEditor {
      public void save(SharedPreferences.Editor editor) {
        editor.apply();
      }
    }
    

    and one for the < gingerbread level

    public class CommitSharedPreferenceEditor extends SharedPreferenceEditor{
      public void save(SharedPreferences.Editor editor) {
        editor.commit();
      }
    }
    

    I'd recommend supporting 2.1 and up so than you can take advantage of the improvements to Dalvik and use the first example I listed.