compileSdkVersion 和 minSdkVersion 都很是好理解,前者表示编译的 SDK 版本,后者表示应用兼容的最低 SDK 版本。可是对于 targetSdkVersion 其实很难一句话解析清楚,Google 官方发布的文章用了“万能”的词 —— interesting 来描述。html
Google 官方发布的文章是这么说的:java
targetSdkVersion is the main way Android provides forward compatibilityandroid
targetSdkVersion 是 Android 系统提供前向兼容的主要手段。这是什么意思呢?随着 Android 系统的升级,某个系统的 API 或者模块的行为可能会发生改变,可是为了保证老 APK 的行为仍是和之前兼容。只要 APK 的 targetSdkVersion 不变,即便这个 APK 安装在新 Android 系统上,其行为仍是保持老的系统上的行为,这样就保证了系统对老应用的前向兼容性。app
这里仍是用原文的例子,在 Android 4.4 (API 19)之后,AlarmManager 的 set()
和 setRepeat()
这两个 API 的行为发生了变化。在 Android 4.4 之前,这两个 API 设置的都是精确的时间,系统能保证在 API 设置的时间点上唤醒 Alarm。由于省电缘由 Android 4.4 系统实现了 AlarmManager 的对齐唤醒,这两个 API 设置唤醒的时间,系统都对待成不精确的时间,系统只能保证在你设置的时间点以后某个时间唤醒。ide
这时,虽然 API 没有任何变化,可是实际上 API 的行为却发生了变化,若是老的 APK 中使用了此 API,而且在应用中的行为很是依赖 AlarmManager 在精确的时间唤醒,例如闹钟应用。若是 Android 系统不能保证兼容,老的 APK 安装在新的系统上,就会出现问题。测试
Android 系统是怎么保证这种兼容性的呢?这时候 targetSdkVersion 就起做用了。APK 在调用系统 AlarmManager 的 set()
或者 setRepeat()
的时候,系统首先会查一下调用的 APK 的 targetSdkVersion 信息,若是小于 19,就仍是按照老的行为,即精确设置唤醒时间,否者执行新的行为。网站
咱们来看一下 Android 4.4 上 AlarmManger 的一部分源代码:ui
private final boolean mAlwaysExact; AlarmManager(IAlarmManager service, Context ctx) { mService = service; final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion; mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT); }
看到这里,首选获取应用的 targetSdkVersion,判断是不是小于 Build.VERSION_CODES.KITKAT (即 API Level 19),来设置 mAlwaysExact
变量,表示是否使用精确时间模式。rest
public static final long WINDOW_EXACT = 0; public static final long WINDOW_HEURISTIC = -1; private long legacyExactLength() { return (mAlwaysExact ? WINDOW_EXACT : WINDOW_HEURISTIC); } public void set(int type, long triggerAtMillis, PendingIntent operation) { setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation, null); }
这里看到,直接影响到 set() 方法给 setImpl()
传入不一样的参数,从而影响到了 set() 的执行行为。具体的实如今 AlarmManagerService.java
,这里就不往下深究了。code
看到这里,发现其实 Android 的 targetSdkVersion 并无什么特别的,系统使用它也很是直接,甚至很“粗糙”。仅仅是用过下面的 API 来获取 targetSdkVersion,来判断是否执行哪一种行为:
getApplicationInfo().targetSdkVersion;
因此,咱们能够猜想到,若是 Android 系统升级,发生这种兼容行为的变化时,通常都会在原来的保存新旧两种逻辑,并经过 if-else
方法来判断执行哪一种逻辑。果真,在源码中搜索,咱们会发现很多相似 getApplicationInfo().targetSdkVersion < Buid.XXXX
这样的代码,相对于浩瀚的 Android 源码量来讲,这些仍是相对较少了。其实原则上,这种会致使兼容性问题的修改仍是越少越好,因此每次发布新的 Android 版本的时候,Android 开发者网站都会列出作了哪些改变,在这里,开发者须要特别注意。
最后,咱们也能够理解原文中说的那句话的含义,明白了为何修改了 APK 的 targetSdkVersion 行为会发生变化,也明白了为何修改 targetSdkVersion 须要作完整的测试了。