2012/02/26

uses-sdkタグを宣言する場所に注意


AndroidOSバージョンに対するアプリケーションの互換性を示すためにuses-sdkが使用さ
れます。uses-sdkはAndroidManifest.xml上で宣言されます。
参照:http://www.techdoctranslator.com/android/guide/manifest/uses-sdk-element

注意しないといけないのは、uses-sdkを記載する位置。
applicationタグよりも後で宣言すると予想外の動作になる場合があります。

NG:
<manifest>
  <application ...>
  </application>

  <uses-sdk ... /> <!-- applicationタグより後にuses-sdkを宣言 -->
</manifest>

OK:
<manifest>
  <uses-sdk ... /> <!-- applicationタグより前にuses-sdkを宣言 -->

  <application ...>
  </application>
</manifest>

Android4.0でハードウェアアクセラレータの使用ON/OFFを指定できるようになりました。
ハードウェアアクセラレータはデフォルトONですが、実装的に言えばtargetSdkのバージ
ョンがICS以上であればデフォルトONとなります。

注意が必要なのは、アプリケーション情報を記載したAndroidManifest.xmlのパース処理
は先頭からシーケンシャルに行われるということです。
つまり、uses-sdkより先にapplicationタグがある場合、uses-sdkの設定が読み込まれる
前にapplication情報が構築されてしまいます。

NGのパターンではハードウェアアクセラレータはデフォルトOFFになります。
原因となるロジックは下記です。

applicationタグが見つかった場合にコールされるPackageParser.parseApplicationメソッド
(PackageParserはAndroidManifest.xmlをパースし、アプリケーション情報を構築するクラス)

boolean hardwareAccelerated = sa.getBoolean(
    com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
    owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);

targetSdkVersionはuses-sdkタグが見つかった場合の下記ルートで処理されます。

PackageParser.parsePackage()
...
    } else if (tagName.equals("uses-sdk")) {
...

AndroidManifest.xmlのパースは先頭からシーケンシャルに行われますので、uses-sdkよ
り前にapplicationタグが見つかった場合、targetSdkVersionの値がまだ初期化されてい
ない状態となりますのでhardwareAcceleratedの値はfalseとなり、アプリケーションや
アクティビティに設定されるハードウェアアクセラレータ値はOFFとなります。

これらのことから、uses-sdkタグは必ずapplicationタグよりも前に定義するようにしましょう。

以上です。