Android之compileSdkVersion炕泳、minSdkVersion 以及 targetSdkVersion

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

Google 官方發(fā)布文章解析 compileSdkVersion纵诞、minSdkVersion 以及 targetSdkVersion 的含義,以及合理設(shè)置各個值的意義培遵,原文 Picking your compileSdkVersion, minSdkVersion, and targetSdkVersion

compileSdkVersion

compileSdkVersion 告訴 Gradle 用哪個 Android SDK 版本編譯你的應(yīng)用浙芙。它純粹只是在編譯的時候使用。當你修改了 compileSdkVersion 的時候籽腕,可能會出現(xiàn)新的編譯警告嗡呼、編譯錯誤等(你真的應(yīng)該修復這些警告,他們的出現(xiàn)一定是有原因的)皇耗。需要強調(diào)的是修改 compileSdkVersion 不會改變運行時的行為南窗,compileSdkVersion 并不會打包進APK里只是在編譯時使用

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

注意敌买,如果使用 Support Library ,那么使用最新發(fā)布的 Support Library 就需要使用最新的 SDK 編譯阶界。通常虹钮,新版的 Support Library 隨著新的系統(tǒng)版本而發(fā)布,它為系統(tǒng)新增加的 API 和新特性提供兼容性支持荐操。例如芜抒,要使用 23.1.1 版本的 Support Library 珍策,compileSdkVersion 就必需至少是 23 (大版本號要一致M衅簟)。

minSdkVersion

minSdkVersion 是應(yīng)用可以運行的最低版本要求攘宙。minSdkVersion 是 Google Play 商店用來判斷用戶設(shè)備是否可以安裝某個應(yīng)用的標志之一屯耸。

在開發(fā)時 minSdkVersion 也起到一個重要角色:lint 默認會在項目中運行,它在你使用了高于 minSdkVersion 的 API 時會警告你蹭劈,幫你避免調(diào)用不存在的 API 的運行時問題疗绣。如果只在較高版本的系統(tǒng)上才使用某些 API,通常使用運行時檢查系統(tǒng)版本的方式解決铺韧。

請記住多矮,你所使用的庫可能有他們自己的 minSdkVersion 。你的應(yīng)用設(shè)置的 minSdkVersion 必需大于等于這些庫的 minSdkVersion 。例如有三個庫塔逃,它們的 minSdkVersion 分別是 4, 7 和 9 讯壶,那么你的 minSdkVersion 必需至少是 9 才能使用它們。在少數(shù)情況下湾盗,你仍然想用一個比你應(yīng)用的 minSdkVersion 還高的庫(處理所有的邊緣情況伏蚊,確保它只在較新的平臺上使用),你可以使用 tools:overrideLibrary 標記格粪,但請做徹底的測試躏吊!

targetSdkVersion

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

原文:targetSdkVersion is the main way Android provides forward compatibility

targetSdkVersion 是 Android 系統(tǒng)提供前向兼容的主要手段肤舞。這是什么意思呢?隨著 Android 系統(tǒng)的升級均蜜,某個 API 或者模塊的行為可能會發(fā)生改變李剖,但是為了保證APK 的行為還是和以前一致。只要 APK 的 targetSdkVersion 不變囤耳,即使這個 APK 安裝在新 Android 系統(tǒng)上篙顺,其行為還是保持老的系統(tǒng)上的行為,這樣就保證了系統(tǒng)對老應(yīng)用的前向兼容性充择。

這里還是用原文的例子德玫,在 Android 4.4 (API 19)以后,AlarmManager 的 set()setRepeat() 這兩個 API 的行為發(fā)生了變化椎麦。在 Android 4.4 以前宰僧,這兩個 API 設(shè)置的都是精確的時間,系統(tǒng)能保證在 API 設(shè)置的時間點上喚醒 Alarm观挎。因為省電原因 Android 4.4 系統(tǒng)實現(xiàn)了 AlarmManager 的對齊喚醒琴儿,這兩個 API 設(shè)置喚醒的時間,系統(tǒng)都對待成不精確的時間嘁捷,系統(tǒng)只能保證在你設(shè)置的時間點之后某個時間喚醒造成。

這時,雖然 API 沒有任何變化雄嚣,但是實際上 API 的行為卻發(fā)生了變化晒屎,如果 APK 中使用了此 API,并且在應(yīng)用中的行為非常依賴 AlarmManager 在精確的時間喚醒,例如鬧鐘應(yīng)用鼓鲁。如果 Android 系統(tǒng)不能保證兼容履肃,老的 APK 安裝在新系統(tǒng)手機上,就會出現(xiàn)問題坐桩。

Android 系統(tǒng)是怎么保證這種兼容性的呢尺棋?這時候 targetSdkVersion 就起作用了。APK 在調(diào)用系統(tǒng) AlarmManager 的 set() 或者 setRepeat() 的時候绵跷,系統(tǒng)首先會查一下調(diào)用的 APK 的 targetSdkVersion 信息膘螟,如果小于 19,就還是按照老的行為碾局,即精確設(shè)置喚醒時間荆残,否者執(zhí)行新的行為。
我們來看一下 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);
}

看到這里净当,首選獲取應(yīng)用的 targetSdkVersion内斯,判斷是否是小于 Build.VERSION_CODES.KITKAT (即 API Level 19),來設(shè)置 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() 傳入不同的參數(shù)忽冻,從而影響到了 set() 的執(zhí)行行為真朗。具體的實現(xiàn)在 AlarmManagerService.java,這里就不往下深究了僧诚。
看到這里遮婶,發(fā)現(xiàn)其實 Android 的 targetSdkVersion 并沒有什么特別的,系統(tǒng)使用它也非常直接湖笨,甚至很“粗糙”旗扑。僅僅是用過下面的 API 來獲取 targetSdkVersion,來判斷是否執(zhí)行哪種行為:getApplicationInfo().targetSdkVersion;

所以慈省,我們可以猜測到臀防,如果 Android 系統(tǒng)升級,發(fā)生這種兼容行為的變化時辫呻,一般都會保存新舊兩種邏輯清钥,并通過 if-else 方法來判斷執(zhí)行哪種邏輯。果然放闺,在源碼中搜索,我們會發(fā)現(xiàn)不少類似 getApplicationInfo().targetSdkVersion < Buid.XXXX 這樣的代碼缕坎,相對于浩瀚的 Android 源碼量來說怖侦,這些還是相對較少了。其實原則上,這種會導致兼容性問題的修改還是越少越好匾寝,所以每次發(fā)布新的 Android 版本的時候搬葬,Android 開發(fā)者網(wǎng)站都會列出做了哪些改變,在這里艳悔,開發(fā)者需要特別注意急凰。

最后,我們也可以理解原文中說的那句話的含義猜年,明白了為什么修改了 APK 的 targetSdkVersion 行為會發(fā)生變化抡锈,也明白了為什么修改 targetSdkVersion 需要做完整的測試了。

Gradle和SDK版本

所以設(shè)置正確的 compileSdkVersion, minSdkVersion 和 targetSdkVersion 很重要乔外。

build.gradle設(shè)置

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

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

如果你在 manifest 文件中手工設(shè)置莲组,你會發(fā)現(xiàn) Gradle 在構(gòu)建時會忽略它們(盡管其它構(gòu)建系統(tǒng)如eclipse、ant可能會依賴它們)暖夭。

綜合來看如果你按照上面示例那樣配置锹杈,你會發(fā)現(xiàn)這三個值的關(guān)系是:

minSdkVersion <= targetSdkVersion <= compileSdkVersion

理想上,在穩(wěn)定狀態(tài)下三者的關(guān)系應(yīng)該更像這樣:

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

用較低的 minSdkVersion 來覆蓋最大的人群迈着,用最新的 SDK 設(shè)置 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.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市裕菠,隨后出現(xiàn)的幾起案子咬清,更是在濱河造成了極大的恐慌,老刑警劉巖奴潘,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旧烧,死亡現(xiàn)場離奇詭異,居然都是意外死亡画髓,警方通過查閱死者的電腦和手機掘剪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奈虾,“玉大人夺谁,你說我怎么就攤上這事廉赔。” “怎么了匾鸥?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵蜡塌,是天一觀的道長。 經(jīng)常有香客問我勿负,道長馏艾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任奴愉,我火速辦了婚禮琅摩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘躁劣。我一直安慰自己迫吐,他們只是感情好,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布账忘。 她就那樣靜靜地躺著志膀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鳖擒。 梳的紋絲不亂的頭發(fā)上溉浙,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音蒋荚,去河邊找鬼戳稽。 笑死,一個胖子當著我的面吹牛期升,可吹牛的內(nèi)容都是我干的惊奇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼播赁,長吁一口氣:“原來是場噩夢啊……” “哼颂郎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起容为,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤乓序,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后坎背,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體替劈,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年得滤,在試婚紗的時候發(fā)現(xiàn)自己被綠了陨献。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡耿戚,死狀恐怖湿故,靈堂內(nèi)的尸體忽然破棺而出阿趁,到底是詐尸還是另有隱情膜蛔,我是刑警寧澤坛猪,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站皂股,受9級特大地震影響墅茉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜呜呐,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一就斤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蘑辑,春花似錦洋机、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至副砍,卻和暖如春衔肢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背豁翎。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工角骤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人心剥。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓邦尊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親优烧。 傳聞我的和親對象是個殘疾皇子蝉揍,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容