星の数ほどあるAndroid端末の全てに対応するのは非現実的だとしても、アプリはできるだけ多くの端末で動作させたいところです。
レイアウトの工夫やSupport Libraryを利用することである程度カバーできますが、どうしてもOSバージョンごとに処理を振り分けなければいけないケースもでてきます。
その方法をまとめます。
リソース類(レイアウト、画像など)
各リソースのフォルダ名に -v{バージョン番号}
を付加します。
バージョン番号(APIレベル): wikipedia
Build.VERSION_CODES: Android Developers
例.
下記のようにフォルダを用意してそれぞれに専用のレイアウトファイルを入れておくと、端末のバージョンに応じて、使用するレイアウトファイルが 自動的に割り振られます。
フォルダ名 | 適用されるOS(※) |
---|---|
layout | Android 1.0〜2.0.1 |
layout-v7 | 2.1〜2.3.7 |
layout-v11 | 3.0〜 |
(※)AndroidManifest.xml(AndroidStudioを使用しているときはbuild.gradle)で、指定した minSdkVersion
より低いバージョンの端末にはそもそもインストールできません。
drawableなど、layout以外のリソースも同じ方法で振り分けられます。
ソースコード(.java)
参考: Android ビルドバージョンで処理を分岐する
ソースコード中で処理を分岐させたいときは、Build
クラスをのSDK_INT, VERSION_CODEを使用します。
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
// ここはGINGERBREAD(Android 2.3)以降で実行される。
}
Build.VERSION.SDK_INT >= 11
などと書いているサンプルも見かけますが、まあお好みで。(コードネームのほうがわかりづらいという意見もあると思いますが私はVERSION_CODE派です。あ、でもリソースフォルダはバージョン番号なので、そちらとの統一を考えると数字の方がいいかも知れませんね。)
NewApiチェックによるエラーの回避
このようにバージョンごとに分岐させることで、古いバージョンに対応していないクラスやメソッドを新しいバージョンのみで使うことができますが、EclipseやAndroidStudioでエラーが発生するケースがあります。
AndroidManifest.xml の minSdkVersion = 7
で
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
getActionBar().setDisplayShowHomeEnabled(true);
}
とすると、Android 7〜10ではActionBarが使えないためIDE上でエラーとなるのです。実際にはif文の分岐により実行されませんが。
そこで、以下のように書き換えることで「この処理は11以降専用なんですよー」とコンパイラ(というか静的解析ツール Lint)に伝え、エラーを抑制します。
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setShowHomeEnable();
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void setShowHomeEnable() {
getActionBar().setDisplayShowHomeEnabled(true);
}
注意が必要なのは、TargeApiアノテーションはあくまでチェックツールLintのエラーを抑制しているだけで、 アプリ実行時に11未満での実行を回避してくれるわけではないということです。
なので、if文による場合分けは外せません。場合分けしないと11未満でも実行されてExceptionが発生します。
冗長な書き方で嫌なんですけどね...これくらいよきに計らってくれよと言いたいです(^_^;)
以上