如何選擇 compileSdkVersion, minSdkVersion 和 targetSdkVersion

當你發佈一個應用之後,(取決於具體的發佈時間)可能沒過幾個月 Android 系統就發佈了一個新版本。這對你的應用意味着什麼,所有東西都不能用了?

別擔心,向前兼容是 Android 非常關注的事情。用戶在升級到新版 Android 的時候,用以前版本的 SDK 構建的現有應用應該不會出問題。這就是 compileSdkVersionminSdkVersion 和 targetSdkVersion 的作用:他們分別控制可以使用哪些 API ,要求的 API 級別是什麼,以及應用的兼容模式。

compileSdkVersion

compileSdkVersion 告訴 Gradle 用哪個 Android SDK 版本編譯你的應用。使用任何新添加的 API 就需要使用對應 Level 的 Android SDK。

需要強調的是修改 compileSdkVersion 不會改變運行時的行爲。當你修改了 compileSdkVersion 的時候,可能會出現新的編譯警告、編譯錯誤,但新的 compileSdkVersion 不會被包含到 APK 中:它純粹只是在編譯的時候使用。(你真的應該修復這些警告,他們的出現一定是有原因的)

因此我們強烈推薦總是使用最新的 SDK 進行編譯。在現有代碼上使用新的編譯檢查可以獲得很多好處,避免新棄用的 API ,並且爲使用新的 API 做好準備。

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

minSdkVersion

如果 compileSdkVersion 設置爲可用的最新 API,那麼 minSdkVersion 則是應用可以運行的最低要求。minSdkVersion 是 Google Play 商店用來判斷用戶設備是否可以安裝某個應用的標誌之一。

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

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

當你決定使用什麼 minSdkVersion 時候,你應該參考當前的 Android 分佈統計,它顯示了最近 7 天所有訪問 Google Play 的設備信息。他們就是你把應用發佈到 Google Play 時的潛在用戶。最終這是一個商業決策問題,取決於爲了支持額外 3% 的設備,確保最佳體驗而付出的開發和測試成本是否值得。

當然,如果某個新的 API 是你整個應用的關鍵,那麼確定 minSdkVersion 的值就比較容易了。不過要記得 14 億設備中的 0.7% 也是個不小的數字。

targetSdkVersion

三個版本號中最有趣的就是 targetSdkVersion 了。 targetSdkVersion 是 Android 提供向前兼容的主要依據,在應用的 targetSdkVersion 沒有更新之前系統不會應用最新的行爲變化。這允許你在適應新的行爲變化之前就可以使用新的 API (因爲你已經更新了 compileSdkVersion 不是嗎?)。

targetSdkVersion 所暗示的許多行爲變化都記錄在 VERSION_CODES 文檔中了,但是所有恐怖的細節也都列在每次發佈的平臺亮點中了,在這個 API Level 表中可以方便地找到相應的鏈接。

例如,Android 6.0 變化文檔中談了 target 爲 API 23 時會如何把你的應用轉換到運行時權限模型上,Android 4.4 行爲變化闡述了 target 爲 API 19 及以上時使用 set() 和 setRepeating() 設置 alarm 會有怎樣的行爲變化。

由於某些行爲的變化對用戶是非常明顯的(棄用的 menu 按鈕,運行時權限等),所以將 target 更新爲最新的 SDK 是所有應用都應該優先處理的事情。但這不意味着你一定要使用所有新引入的功能,也不意味着你可以不做任何測試就盲目地更新 targetSdkVersion ,請一定在更新 targetSdkVersion 之前做測試!你的用戶會感謝你的。

Gradle 和 SDK 版本

所以設置正確的 compileSdkVersion, minSdkVersion 和 targetSdkVersion 很重要。如你所想, Gradle 和 Android Studio 都在構建系統中集成了它們。在你的模塊的 build.gradle 文件中(也可以在 Android Studio 的項目結構選項中)設置:

android {
  compileSdkVersion 23
  buildToolsVersion "23.0.1"

  defaultConfig {
    applicationId "com.example.checkyourtargetsdk"
    minSdkVersion 7
    targetSdkVersion 23
    versionCode 1
    versionName “1.0”
  }
}

編譯時用到的 compileSdkVersion 是和構建工具版本一起設置的 Android 設置之一。其他兩個稍有不同,他們在構建變體(build variant)的那裏聲明。defaultConfig 是所有構建變體的基礎,也是設置這些默認值的地方。你可以想象在一個更復雜的系統中,應用的某些版本可能會有不同的 minSdkVersion 。

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

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

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

綜合來看

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

minSdkVersion <= targetSdkVersion <= compileSdkVersion

這種直覺是合理的,如果 compileSdkVersion 是你的最大值,minSdkVersion 是最小值,那麼最大值必需至少和最小值一樣大且 target 必需在二者之間。

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

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

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

英文原文:Picking your compileSdkVersion, minSdkVersion, and targetSdkVersion

Depending on the time of the year, it might only be a few months after you release an app that a new version of Android is announced. What does that mean for your app though — is everything going to break?

You’ll be happy to know that forward compatibility is a strong focus of Android — existing apps built against prior SDKs should not break when the user updates to a new version of Android. This is where compileSdkVersionminSdkVersion, and targetSdkVersion come in: they control what APIs are available, what the required API level is, and what compatiblity modes are applied, respectively.

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 the Dashboards, 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 changesdetail 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.

Gradle and SDK versions

So setting the correct compileSdkVersion, minSdkVersion, and targetSdkVersion is important. As you might imagine in a world with Gradle and Android Studio, these values are integrated into the tools system through inclusion in your module’s build.gradle file (also available through the Project Structure option in Android Studio):

android {
  compileSdkVersion 23
  buildToolsVersion “23.0.1”

  defaultConfig {
    applicationId “com.example.checkyourtargetsdk"
    minSdkVersion 7
    targetSdkVersion 23
    versionCode 1
    versionName “1.0”
  }
}

The compileSdkVersion, being a compile time thing (who would have guessed!), is one of the android settings alongside with your build tools version. The other two are slightly differently in that they are declared at the build variant level — the defaultConfig is the base for all build variants and where’d you put default values for these, but you could imagine a more complicated system where specific versions of your app have a different minSdkVersion for example.

minSdkVersion and targetSdkVersion also differ from compileSdkVersion in that they are included in your final APK — if you were to look at the generatedAndroidManifest.xml, you’d see a tag such as:

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

You’ll find if you manually put this in your manifest, it’ll be ignored when you build with Gradle (although other build systems might certainly rely on it being there).

Putting it all together

If you made it through the bolded notes, you’ll notice a relationship between the three values:

minSdkVersion <= targetSdkVersion <= compileSdkVersion

This intuitively makes sense — if compileSdkVersion is your ‘maximum’ and minSdkVersion is your ‘minimum’ then your maximum must be at least as high as your minimum and the target must be somewhere in between.

Ideally, the relationship would look more like this in the steady state:

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

You’ll hit the biggest audience with a low minSdkVersion and look and act the best by targeting and compiling with the latest SDK — a great way to #BuildBetterApps.

Join the discussion on the Google+ post and follow the Android Development Patterns Collection for more!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章