Android

minSdkVersionとtargetSdkVersionの関係

More than 3 years have passed since last update.

Androidでアプリ開発をする際に、minSdkVersionとtargetSdkVersionの関係性がいまいち理解できていなかったので、

実際にコード書いて検証してみた話。


まとめ


  • 下位互換性を保証するためにminSdkVersionを指定する場合は、minSdkVersion以降で追加されたAPIはそのまま使ってはならない

  • minSdkVersionを指定しつつも、より最新の機種では新しいAPIを使いたい場合は、実行時のAPIレベルを見て処理を分ける

  • (Support Libraryが使えそうであれば使う)


準備


build.gradle


  • コンパイルはAPIレベル22で行う

  • 最低動作保証APIレベルは15とする


build.gradle

minSdkVersion 15

targetSdkVersion 22


検証コード

以下のようなNotificationを実装する。


MainActivity.java

Notification notification = new Notification.Builder(context)

.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("test title")
.setContentText("test content")
.setContentIntent(pendingIntent)
.setColor(Color.RED) // API level 21 から追加されたAPI
.build(); // API level 16 から追加されたAPI


Androidエミュレータ

以下のバージョンを準備。


  • Android 4.0.3 (API level 15)

  • Android 5.1 (API level 22)


1.検証


1) まずは何も考えずに実装してみる

最低動作保証APIレベルを15と指定しているのにもかかわらず、

APIレベル16以降で追加されたメソッドを実行しようとしているので、

APIレベル16以降から追加されたメソッド部分で警告が出る。

ただしコンパイルはAPIレベル22で行われるので、apk自体は作成できる。

01.png

このコードは、Android 4.0.3のエミュレータでは動かない。

(当該APIが存在しないため)

android4.0.3.png

08-08 10:29:09.807    1558-1558/org.tksmaru.sandbox.android.sdkversion E/AndroidRuntime﹕ FATAL EXCEPTION: main

java.lang.NoSuchMethodError: android.app.Notification$Builder.setColor
at org.tksmaru.sandbox.android.sdkversion.MainActivity$1.onClick(MainActivity.java:38)
at android.view.View.performClick(View.java:4084)
at android.view.View$PerformClick.run(View.java:16966)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)

Android 5.1では動く。

android5.1.png


2) 動作保証したい全てバージョンで動かすには


minSdkVersion以降で追加されたAPIは使わない


MainActivity.java

Notification notification = new Notification.Builder(context)

.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("test title")
.setContentText("test content")
.setContentIntent(pendingIntent)
.getNotification(); // API level 16 以降はdeprecatedだが、22時点では動く


実行時のAPIレベルごとに処理を分ける

特定の実行時APIレベル以上のときだけ新規追加されたAPIを利用できるようにする。

このように条件分岐すると、コンパイル時の警告も出なくなる。

ただし、コードが特定のAPIレベルに依存することになるので、メンテナンス性が良いとは言いづらい。


MainActivity.java

Notification notification;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// API level 21 以上
notification = new Notification.Builder(context)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("test title")
.setContentText("content is this")
.setContentIntent(pendingIntent)
.setColor(Color.RED) // API level 21 から追加
.build(); // API level 16 から追加
} else {
// API level 20 以下
notification = new Notification.Builder(context)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("test title")
.setContentText("content is this")
.setContentIntent(pendingIntent)
.getNotification();
}



Support Libraryを使う

(まだ調べてない)


まとめ


  • 下位互換性を保証するためにminSdkVersionを指定する場合は、minSdkVersion以降で追加されたAPIはそのまま使ってはならない

  • minSdkVersionを指定しつつも、より最新の機種では新しいAPIを使いたい場合は、実行時のAPIレベルを見て処理を分ける

  • (Support Libraryが使えそうであれば使う)


参考

https://github.com/tksmaru/SdkVersion