Android targetSdkVersion 原理
前幾天 Google 官方釋出文章解析 compileSdkVersion、minSdkVersion 以及 targetSdkVersion 的含義,以及合理設定各個值的意義,原文 Picking your compileSdkVersion, minSdkVersion, and targetSdkVersion(後面簡稱 “原文”),還有翻譯版。
其中,compileSdkVersion 和 minSdkVersion 都非常好理解,前者表示編譯的 SDK 版本,後者表示應用相容的最低 SDK 版本。但是對於 targetSdkVersion 其實很難一句話解析清楚,原文用了“萬能”的詞 —— interesting 來描述。以前我也有一些迷糊,看到有些人和我有同樣的困惑,本文試圖徹底解決這個問題。
原文是這麼說的:
targetSdkVersion is the main way Android provides forward compatibility
targetSdkVersion 是 Android 系統提供前向相容的主要手段。這是什麼意思呢?隨著 Android 系統的升級,某個系統的 API 或者模組的行為可能會發生改變,但是為了保證老 APK 的行為還是和以前相容。只要 APK 的 targetSdkVersion 不變,即使這個 APK 安裝在新 Android 系統上,其行為還是保持老的系統上的行為,這樣就保證了系統對老應用的前向相容性。
這裡還是用原文的例子,在 Android 4.4 (API 19)以後,AlarmManager 的 set()
和 setRepeat()
這兩個 API 的行為發生了變化。在 Android 4.4 以前,這兩個 API 設定的都是精確的時間,系統能保證在 API 設定的時間點上喚醒 Alarm。因為省電原因 Android 4.4 系統實現了 AlarmManager 的對齊喚醒,這兩個 API 設定喚醒的時間,系統都對待成不精確的時間,系統只能保證在你設定的時間點之後某個時間喚醒。
這時,雖然 API 沒有任何變化,但是實際上 API 的行為卻發生了變化,如果老的 APK 中使用了此 API,並且在應用中的行為非常依賴 AlarmManager 在精確的時間喚醒,例如鬧鐘應用。如果 Android 系統不能保證相容,老的 APK 安裝在新的系統上,就會出現問題。
Android 系統是怎麼保證這種相容性的呢?這時候 targetSdkVersion 就起作用了。APK 在呼叫系統 AlarmManager 的 set()
或者 setRepeat()
的時候,系統首先會查一下呼叫的 APK 的 targetSdkVersion 資訊,如果小於 19,就還是按照老的行為,即精確設定喚醒時間,否者執行新的行為。
我們來看一下 Android 4.4 上 AlarmManger 的一部分原始碼:
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
變數,表示是否使用精確時間模式。
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
,這裡就不往下深究了。
看到這裡,發現其實 Android 的 targetSdkVersion 並沒有什麼特別的,系統使用它也非常直接,甚至很“粗糙”。僅僅是用過下面的 API 來獲取 targetSdkVersion,來判斷是否執行哪種行為:
getApplicationInfo().targetSdkVersion;
所以,我們可以猜測到,如果 Android 系統升級,發生這種相容行為的變化時,一般都會在原來的儲存新舊兩種邏輯,並通過 if-else
方法來判斷執行哪種邏輯。果然,在原始碼中搜尋,我們會發現不少類似 getApplicationInfo().targetSdkVersion < Buid.XXXX
這樣的程式碼,相對於浩瀚的 Android 原始碼量來說,這些還是相對較少了。其實原則上,這種會導致相容性問題的修改還是越少越好,所以每次釋出新的 Android 版本的時候,Android 開發者網站都會列出做了哪些改變,在這裡,開發者需要特別注意。
最後,我們也可以理解原文中說的那句話的含義,明白了為什麼修改了 APK 的 targetSdkVersion 行為會發生變化,也明白了為什麼修改 targetSdkVersion 需要做完整的測試了。
寫完這篇文章,再回頭去看一下原文的 targetSdkVersion 那一段,發現作者是說的多麼“滴水不漏”。
相關文章
- 再次理解Android targetSdkVersionAndroid
- Android targetSdkVersion 升級到 26 總結Android
- Android平臺targetSdkVersion設定及動態許可權Android
- 通知!TargetSdkVersion新規執行在即!
- Android Handler原理Android
- Android AIDL原理AndroidAI
- Android Messenger原理AndroidMessenger
- Android JNI原理分析Android
- Android Animation 執行原理Android
- Android熱修復原理Android
- Android View 的工作原理AndroidView
- Android之訊息推送原理Android
- Android 視訊直播原理探索Android
- Android Jetpack Architecture原理之ViewModelAndroidJetpackView
- Android LeakCanary的使用和原理Android
- Android View的工作原理(上)AndroidView
- Android之Context底層原理AndroidContext
- Android Protobuf應用及原理Android
- 【Android Jetpack教程】ViewModel原理分析AndroidJetpackView
- Android SharedPreferences 實現原理解析Android
- Android Handler與Looper原理簡析AndroidOOP
- Android UI繪製流程及原理AndroidUI
- Android深色模式適配原理分析Android模式
- 03.Android之View原理問題AndroidView
- Android元件化專題 - 路由框架原理Android元件化路由框架
- Android匿名共享記憶體(Ashmem)原理Android記憶體
- Android 常用換膚方式以及原理分析Android
- Android 元件化最佳實踐 ARetrofit 原理Android元件化
- Android中的LruCache的原理和使用Android
- Android UI 顯示原理分析小結AndroidUI
- Android程式間通訊,AIDL工作原理AndroidAI
- Android動畫實現繪製原理Android動畫
- Android ADB原理及常用命令Android
- 深入理解Android逆向除錯原理Android除錯
- Android RollBack機制實現原理剖析Android
- 使用weiXinRecorded不支援targetSdkVersion升級23及以上問題的解決方案
- Android內容服務ContentService原理淺析Android
- Android Hook框架Xposed原理與原始碼分析AndroidHook框架原始碼
- Android RecyclerView 區域性重新整理原理AndroidView