compileSdkVersion、minSdkVersion和targetSdkVersion的含義和區(qū)別

https://juejin.im/post/5aae7200f265da23a3350317
徹底弄清support支持庫,以及v4 v7重復(fù)依賴問題深究


一般在Android Studio的項目配置build.gradle里,有3個SDKversion,即:compileSdkVersion、minSdkVersion和targetSDKVersion,這些version指的并不是我們使用的SDK的版本,而是我們使用的Android平臺(Android Platform)的版本,即API Level,是一個整數(shù),指的是我們使用的框架(Framework)的版本,也就是SDK中platforms文件夾下各個level中的android.jar的版本,API Level就是android.jar(Framework開發(fā)包、一套接口)的代號。一般Android系統(tǒng)版本表示為Android2.3.3,在系統(tǒng)內(nèi)部會記錄它的API level,不同的Android系統(tǒng)版本對應(yīng)不同的API Level(最后有詳細(xì)介紹),但是有時候Android系統(tǒng)版本更新了,其對應(yīng)的API Level并不一定更新,所以他們是多對一的關(guān)系,Android系統(tǒng)版本是面向用戶,API Level是面向開發(fā)者。

compileSDKVersion

各個其中compileSDKVersion是AS編譯APK使用的API Level,一般修改了compileSDKVersion不會改變運行時的行為,可能會出現(xiàn)一些編譯的警告和錯誤, compileSDKVersion并不會被包含到apk中,它只是純粹在編譯時候使用。一般推薦使用最新的版本進(jìn)行編譯,避免使用廢棄的API,同時Support Library 也需要相應(yīng)的編譯SDK版本來支持,我們經(jīng)常使用的Support Library的依賴語句形式如下:compile 'com.android.support:support-v4:24.2.1,其格式是compile jar文件組(group/命名空間):jar文件名(name):jar文件版本(version),這里jar文件版本需要和compileSDKVersion保持一致。

關(guān)于Support Library參考:http://www.lxweimin.com/p/f5f9a4fd22e8
簡單總結(jié)一下:Support Library提供了一些低版本API Level中不存在的API接口,如App配置為minSdkVersion=9,targetSdkVersion=23,在程序里使用了android 3.0 (API level 11)提供的ActionBar類,使用compileSdkVersion=23成功編譯出apk,App在android 3.0以及以上的版本上正常運行,但在API 9的版本上回crash,因為找不到ActionBar類,因為舊版本上沒有新版本里新增的類。為了避免使用了最新功能開發(fā)的app只能在最新系統(tǒng)的設(shè)備上運行的尷尬,官方把新版系統(tǒng)framework中新增加的接口提出來放到了Android Support Library(支持包)中,開發(fā)者在遇到上面的情況時,就可以使用支持包中具有同樣功能的ActionBar類,這個支持包會打包進(jìn)apk里,這樣使用了新版本系統(tǒng)上功能的App也可以向后兼容以前的老系統(tǒng)版本設(shè)備了。

Support V4和V7是使用最廣泛的2個包,其實是包的集合,v4在后期被拆分為幾個子包,v7一開始就是不同的子包,這樣可以減少apk的體積,另外在編譯的時候使用代碼混淆ProGuard,除了可以混淆源代碼外,還可以移除依賴支持庫中沒有使用到的類,達(dá)到apk瘦身的效果。
7/22/2017 7:58:00 AM

App編譯時用的android sdk(android.jar)不會打包進(jìn)我們的apk中。因為apk編碼是使用android.jar中的接口就是android設(shè)備里系統(tǒng)框架層(framework)對外提供的接口。

minSdkVersion

minSdkVersion表示應(yīng)用兼容的最低API Level,如果手機(jī)的Android系統(tǒng)的API level低于該值,則該手機(jī)無法安裝此apk。API level在選擇時應(yīng)該兼顧市場上大部分的手機(jī)Android系統(tǒng)版本。原則上,如果我們在編寫程序時使用了最低API Level里沒有的API接口,那么程序就會報錯,我們通過使用Support Library來提供最低API Level里沒有的API接口,但注意,這些Support Library本身也使用了minSdkVersion,那么我們工程里的minSdkVersion版本不能低于Support Library使用的minSdkVersion版本。例如我們用了3個庫,他們的minSdkVersion分別是4、7、9,那么我們工程的minSdkVersion至少應(yīng)該是9,否則編譯通不過。如果minSdkVersion沒有設(shè)置的話,默認(rèn)為1。

targetSdkVersion

targetSdkVersion,谷歌給出的解釋是:

targetSdkVersion is the main way Android provides forward compatibility,Specifies the API Level on which the application is designed to run. In some cases. As Android evolves with each new version, some behaviors and even appearances might change. However, if the API level of the platform is higher than the version declared by your app's targetSdkVersion, the system may enable compatibility behaviors to ensure that your app continues to work the way you expect.
If not set, the default value equals that given to minSdkVersion

targetSdkVersion是Android系統(tǒng)提供前向兼容的主要手段,用來保證以前老的app即使運行在新的Android系統(tǒng)上,它的行為還是和以前兼容。因為Android系統(tǒng)是不斷更新的,有些API的行為在新系統(tǒng)上發(fā)生了變化,那么對于那些以前的apk,即使它安裝在了最新的Android系統(tǒng)上,調(diào)用的最新Android系統(tǒng)的API接口,只要apk的targetSdkVersion不變,那么它的行為依然保持不變,依然執(zhí)行原來的行為。這就保證了系統(tǒng)對以前老的app應(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 源碼量來說,這些還是相對較少了。其實原則上,這種會導(dǎo)致兼容性問題的修改還是越少越好,所以每次發(fā)布新的 Android 版本的時候,Android 開發(fā)者網(wǎng)站都會列出做了哪些改變,在這里,開發(fā)者需要特別注意。

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

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

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

AS默認(rèn)的targetSdkVersion和compileSdkVersion都是使用的最新的API Level。

另外,minSdkVersion 和 targetSdkVersion 與 compileSdkVersion 的另一個不同之處是它們會被包含進(jìn)最終的 APK 文件中,如果你查看生成的 AndroidManifest.xml 文件,你會看到類似下面這樣的標(biāo)簽:

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

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

What is API Level?

API Level is an integer value that uniquely identifies the framework API revision offered by a version of the Android platform.

The Android platform provides a framework API that applications can use to interact with the underlying Android system. The framework API consists of:

  • A core set of packages and classes
  • A set of XML elements and attributes for declaring a manifest file
  • A set of XML elements and attributes for declaring and accessing resources
  • A set of Intents
  • A set of permissions that applications can request, as well as permission enforcements included in the system

Each successive version of the Android platform can include updates to the Android application framework API that it delivers.

Updates to the framework API are designed so that the new API remains compatible with earlier versions of the API. That is, most changes in the API are additive and introduce new or replacement functionality. As parts of the API are upgraded, the older replaced parts are deprecated but are not removed, so that existing applications can still use them. In a very small number of cases, parts of the API may be modified or removed, although typically such changes are only needed to ensure API robustness and application or system security. All other API parts from earlier revisions are carried forward without modification.

The framework API that an Android platform delivers is specified using an integer identifier called "API Level". Each Android platform version supports exactly one API Level, although support is implicit for all earlier API Levels (down to API Level 1). The initial release of the Android platform provided API Level 1 and subsequent releases have incremented the API Level.

The API Level identifier serves a key role in ensuring the best possible experience for users and application developers:

  • It lets the Android platform describe the maximum framework API revision that it supports
  • It lets applications describe the framework API revision that they require
  • It lets the system negotiate the installation of applications on the user's device, such that version-incompatible applications are not installed.

Each Android platform version stores its API Level identifier internally, in the Android system itself.

參考:

Android targetSdkVersion 原理

如何選擇 compileSdkVersion, minSdkVersion 和 targetSdkVersion

Android中build target,minSdkVersion,targetSdkVersion,maxSdkVersion概念區(qū)分

https://developer.android.com/guide/topics/manifest/uses-sdk-element.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,892評論 2 372

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