@Android之compileSdkVersion、minSdkVersion 以及 targetSdkVersion


參考:
Android targetSdkVersion 原理
如何選擇 compileSdkVersion, minSdkVersion 和 targetSdkVersion
Google 官方文章:Picking your compileSdkVersion, minSdkVersion, and targetSdkVersion
Android Develop

Google 官方發布文章解析 compileSdkVersion、minSdkVersion 以及 targetSdkVersion 的含義,以及合理設置各個值的意義,原文 Picking your compileSdkVersion, minSdkVersion, and targetSdkVersion

compileSdkVersion

compileSdkVersion 告訴 Gradle 用哪個 Android SDK 版本編譯你的應用。它純粹只是在編譯的時候使用。當你修改了 compileSdkVersion 的時候,可能會出現新的編譯警告、編譯錯誤等(你真的應該修復這些警告,他們的出現一定是有原因的)。需要強調的是修改 compileSdkVersion 不會改變運行時的行為,compileSdkVersion 並不會打包進APK里只是在編譯時使用

因此我們強烈推薦總是使用最新的 SDK 進行編譯。在自己的代碼上使用最新SDK的編譯檢查(lint?)可以獲得很多好處,可以避免使用最新棄用的 API ,並且為使用新的 API 做好准備。

注意,如果使用 Support Library ,那么使用最新發布的 Support Library 就需要使用最新的 SDK 編譯。通常,新版的 Support Library 隨着新的系統版本而發布,它為系統新增加的 API 和新特性提供兼容性支持。例如,要使用 23.1.1 版本的 Support Library ,compileSdkVersion 就必需至少是 23 (大版本號要一致!)。

minSdkVersion

minSdkVersion 是應用可以運行的最低版本要求。minSdkVersion 是 Google Play 商店用來判斷用戶設備是否可以安裝某個應用的標志之一。

在開發時 minSdkVersion 也起到一個重要角色:lint 默認會在項目中運行,它在你使用了高於 minSdkVersion 的 API 時會警告你,幫你避免調用不存在的 API 的運行時問題。如果只在較高版本的系統上才使用某些 API,通常使用運行時檢查系統版本的方式解決。

請記住,你所使用的庫可能有他們自己的 minSdkVersion 。你的應用設置的 minSdkVersion 必需大於等於這些庫的 minSdkVersion 。例如有三個庫,它們的 minSdkVersion 分別是 4, 7 和 9 ,那么你的 minSdkVersion 必需至少是 9 才能使用它們。在少數情況下,你仍然想用一個比你應用的 minSdkVersion 還高的庫(處理所有的邊緣情況,確保它只在較新的平台上使用),你可以使用 tools:overrideLibrary 標記,但請做徹底的測試!

targetSdkVersion

compileSdkVersion 和 minSdkVersion 都非常好理解,前者表示編譯的 SDK 版本,后者表示應用兼容的最低 SDK 版本。但是對於 targetSdkVersion 其實很難一句話解析清楚,原文:The most interesting of the three, however, is targetSdkVersion. 。以前我也有一些迷糊,看到有些人和我有同樣的困惑,本文試圖徹底解決這個問題。

原文: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 需要做完整的測試了。

Gradle和SDK版本

所以設置正確的 compileSdkVersion, minSdkVersion 和 targetSdkVersion 很重要。

 
build.gradle設置

所以編譯時用到的 compileSdkVersion 是和其他構建設置放在一起的(如上圖的: buildToolsVersion)作為Android 的設置。其他兩個稍有不同,他們在構建變體(build variant)的那里聲明。defaultConfig 是所有構建變體的基礎,也是設置這些默認值的地方。
你可以想象在一個更復雜的系統中,應用的某些版本可能會有不同的 minSdkVersion 。
minSdkVersion 和 targetSdkVersion 會被打包進最終的 APK 文件中,如果你查看生成的 AndroidManifest.xml 文件,你會看到類似下面這樣的標簽:

<uses-sdk android:targetSdkVersion="23" android:minSdkVersion="7" /> 

如果你在 manifest 文件中手工設置,你會發現 Gradle 在構建時會忽略它們(盡管其它構建系統如eclipse、ant可能會依賴它們)。

綜合來看如果你按照上面示例那樣配置,你會發現這三個值的關系是:

minSdkVersion <= targetSdkVersion <= compileSdkVersion

理想上,在穩定狀態下三者的關系應該更像這樣:

minSdkVersion (lowest possible) <= targetSdkVersion == compileSdkVersion (latest SDK)

用較低的 minSdkVersion 來覆蓋最大的人群,用最新的 SDK 設置 target 和 compile 來獲得最好的外觀和行為。

附:部分英文原文

compileSdkVersion

compileSdkVersion is your way to tell Gradle what version of the Android SDK to compile your app with. Using the new Android SDK is a requirement to use any of the new APIs added in that level.
It should be emphasized that changing your compileSdkVersion does not change runtime behavior. While new compiler warnings/errors may be present when changing your compileSdkVersion, your compileSdkVersion is not included in your APK: it is purely used at compile time. (You should really fix those warnings though — they were added for a reason!)
Therefore it is strongly recommended that you always compile with the latest SDK. You’ll get all the benefits of new compilation checks on existing code, avoid newly deprecated APIs, and be ready to use new APIs.
Note that if you use the Support Library, compiling with the latest SDK is a requirement for using the latest Support Library releases. For example, to use the 23.1.1 Support Library, you must have a compileSdkVersion of at least 23 (those first numbers need to match!). In general, a new version of the Support Library is released alongside a new platform version, providing compatibility shims to newly added APIs as well as new features.

minSdkVersion

If compileSdkVersion sets the newest APIs available to you, minSdkVersion is the lower bound for your app. The minSdkVersion is one of the signals the Google Play Store uses to determine which of a user’s devices an app can be installed on.
It also plays an important role during development: by default lint runs against your project, warning you when you use any APIs above your minSdkVersion, helping you avoid the runtime issue of attempting to call an API that doesn’t exist. Checking the system version at runtime is a common technique when using APIs only on newer platform versions.
Keep in mind that libraries you use, such as any of the Support Libraries or Google Play services, may have their own minSdkVersion — your app’s minSdkVersion must be at least as high as your dependencies’ minSdkVersion — if you have libraries that require 4, 7, and 9, your minSdkVersion must be at least 9. In rare cases where you want to continue to use a library with a higher minSdkVersion than your app (and deal with all edge cases/ensure the library is only used on newer platform versions), you can use the tools:overrideLibrary marker, but make sure to test thoroughly!
When deciding on a minSdkVersion, you should consider the stats on theDashboards, which give you a global look on all devices that visited the Google Play Store in the prior 7 days — that’s your potential audience when putting an app on Google Play. It is ultimately a business decision on whether supporting an additional 3% of devices is worth the development and testing time required to ensure the best experience.
Of course, if a new API is key to your entire app, then that makes the minSdkVersion discussion quite a bit easier. Just remember that even 0.7% of 1.4 billion devices is a lot of devices.

targetSdkVersion

The most interesting of the three, however, is targetSdkVersion. targetSdkVersion is the main way Android provides forward compatibility by not applying behavior changes unless the targetSdkVersion is updated. This allows you to use new APIs (as you did update your compileSdkVersion right?) prior to working through the behavior changes.
Much of the behavior changes that targetSdkVersion implies are documented directly in the VERSION_CODES, but all of the gory details are also listed on the each releases’ platform highlights, nicely linked in the API Levels table.
For example, the Android 6.0 changes talk through how targeting API 23 transitions your app to the runtime permissions model and the Android 4.4 behavior changes detail how targeting API 19 or higher changes how alarms set with set() and setRepeating() work.
With some of the behavior changes being very visible to users (the deprecation of the menu button, runtime permissions, etc), updating to target the latest SDK should be a high priority for every app. That doesn’t mean you have to use every new feature introduced nor should you blindly update your targetSdkVersion without testing — please, please test before updating your targetSdkVersion! Your users will thank you.



作者:蒸汽飛船
鏈接:https://www.jianshu.com/p/dc56f7bd65c3
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM