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.
參考:
如何選擇 compileSdkVersion, minSdkVersion 和 targetSdkVersion
Android中build target,minSdkVersion,targetSdkVersion,maxSdkVersion概念區(qū)分
https://developer.android.com/guide/topics/manifest/uses-sdk-element.html