Android 適用于眾多類型的設(shè)備,從手機(jī)到平板電腦和電視都能搭載使用。作為開發(fā)者,如此廣泛的設(shè)備類型能為您的應(yīng)用帶來廣大的潛在受眾群體。為了能在所有這些設(shè)備上順利運(yùn)行,應(yīng)用應(yīng)該容許部分設(shè)備功能的變化,并提供可適應(yīng)不同屏幕配置的靈活界面。
兼容性”是什么意思?
隨著您進(jìn)一步閱讀 Android 開發(fā)相關(guān)內(nèi)容,您可能會(huì)在各種語(yǔ)境下遇到“兼容性”一詞。兼容性有兩種類型:設(shè)備兼容性和應(yīng)用兼容性。
作為應(yīng)用開發(fā)者,您無需擔(dān)心設(shè)備是否兼容 Android,因?yàn)橹挥信c Android 兼容的設(shè)備才會(huì)附帶 Google Play 商店或該設(shè)備的官方手機(jī)應(yīng)用市場(chǎng)。因此,您可以放心,通過Google Play 商店和官方手機(jī)應(yīng)用市場(chǎng)安裝您的應(yīng)用的用戶使用的是 Android 兼容設(shè)備。
不過,您確實(shí)需要考慮您的應(yīng)用是否兼容每一種可能的設(shè)備配置。由于 Android 以各種設(shè)備配置運(yùn)行,因此部分功能并不適用于所有設(shè)備。例如,某些設(shè)備可能未配備羅盤傳感器。如果應(yīng)用的核心功能需要使用羅盤傳感器,那么應(yīng)用只能與帶有羅盤傳感器的設(shè)備兼容。
控制應(yīng)用在設(shè)備上的可用性
應(yīng)用可通過平臺(tái) API 利用 Android 支持的各種功能。有些功能基于硬件(例如羅盤傳感器),有些功能基于軟件(如應(yīng)用窗口微件),有些功能則依賴于平臺(tái)版本。并非每臺(tái)設(shè)備都支持所有功能,因此您可能需要根據(jù)應(yīng)用所需的功能控制應(yīng)用在設(shè)備上的可用性。
要盡可能擴(kuò)大應(yīng)用的用戶群,您應(yīng)設(shè)法使用單個(gè) APK 支持盡可能多的設(shè)備配置。在大多數(shù)情況下,要實(shí)現(xiàn)這一目標(biāo),您可以在運(yùn)行時(shí)停用可選功能,并為應(yīng)用資源提供針對(duì)不同配置的替代選項(xiàng)(例如針對(duì)不同屏幕尺寸的不同布局)。不過,如果需要,您可以根據(jù)以下設(shè)備特征,通過 Google Play 商店限制應(yīng)用在設(shè)備上的可用性:
- 設(shè)備功能
- 平臺(tái)版本
- 屏幕配置
設(shè)備功能
為了讓您根據(jù)設(shè)備功能管理應(yīng)用的可用性,Android 為可能并不適用于所有設(shè)備的任何硬件或軟件功能定義了功能 ID。例如,羅盤傳感器的功能 ID 為 FEATURE_SENSOR_COMPASS,而應(yīng)用微件的功能 ID 為 FEATURE_APP_WIDGETS。
根據(jù)需要,要在用戶的設(shè)備不具備特定功能時(shí)阻止用戶安裝您的應(yīng)用,您可以通過應(yīng)用清單文件中的<uses-feature>元素聲明這一點(diǎn)。
例如,如果您的應(yīng)用在沒有羅盤傳感器的設(shè)備上沒有意義,您可以使用以下清單標(biāo)記聲明需要羅盤傳感器:
<manifest ... >
<uses-feature android:name="android.hardware.sensor.compass"
android:required="true" />
...
</manifest>
Google Play 商店會(huì)將您的應(yīng)用所需的功能與每個(gè)用戶的設(shè)備上可用的功能進(jìn)行比較,以確定您的應(yīng)用是否與每臺(tái)設(shè)備兼容。如果設(shè)備不具備您的應(yīng)用所需的所有功能,則用戶無法安裝您的應(yīng)用。
但是,如果應(yīng)用的主要功能不需要某項(xiàng)設(shè)備功能,則應(yīng)將required屬性設(shè)置為 "false"并在運(yùn)行時(shí)檢查是否有該設(shè)備功能。如果應(yīng)用功能在當(dāng)前設(shè)備上不可用,請(qǐng)適當(dāng)降級(jí)相應(yīng)的應(yīng)用功能。例如,您可以通過調(diào)用hasSystemFeature()來查詢功能是否可用,如下所示:
Java
PackageManager pm = getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)) {
// This device does not have a compass, turn off the compass feature
disableCompassFeature();
}
Kotlin
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)) {
// This device does not have a compass, turn off the compass feature
disableCompassFeature()
}
平臺(tái)版本
不同的設(shè)備可能會(huì)運(yùn)行不同版本的 Android 平臺(tái),例如 Android 4.0 或 Android 4.4。每個(gè)后續(xù)的平臺(tái)版本通常會(huì)添加之前版本中不可用的新 API。為表明可用的 API 集,每個(gè)平臺(tái)版本都會(huì)指定API 級(jí)別。例如,Android 1.0 是 API 級(jí)別 1,而 Android 4.4 是 API 級(jí)別 19。
通過 API 級(jí)別,您可以使用<uses-sdk>清單標(biāo)記及其minSdkVersion屬性來聲明應(yīng)用兼容的最低版本。例如,Android 4.0(API 級(jí)別 14)中添加了 日歷提供程序 API。如果您的應(yīng)用在沒有這些 API 的情況下無法運(yùn)行,您應(yīng)將 API 級(jí)別 14 聲明為應(yīng)用的最低支持版本。
minSdkVersion屬性聲明應(yīng)用兼容的最低版本,targetSdkVersion屬性聲明應(yīng)用經(jīng)過優(yōu)化后適用的最高版本。
不過,請(qǐng)注意<uses-sdk>元素中的屬性會(huì)被替換為build.gradle文件中的相應(yīng)屬性。因此,如果您使用的是 Android Studio,則必須在其中指定minSdkVersion和targetSdkVersion值:
android {
defaultConfig {
applicationId 'com.example.myapp'
// Defines the minimum API level required to run the app.
minSdkVersion 15
// Specifies the API level used to test the app.
targetSdkVersion 28
...
}
}
要詳細(xì)了解build.gradle文件,請(qǐng)參閱如何配置編譯版本。
每個(gè)后續(xù)版本的 Android 都為使用之前平臺(tái)版本的 API 構(gòu)建的應(yīng)用提供兼容性,因此您的應(yīng)用應(yīng)始終與未來版本的 Android 兼容,同時(shí)使用已記錄的 Android API。
注意:targetSdkVersion 屬性不會(huì)阻止您的應(yīng)用安裝在高于指定值的平臺(tái)版本上,但它很重要,因?yàn)樗蛳到y(tǒng)指示您的應(yīng)用是否應(yīng)繼承較新版本中的行為更改。如果您不將 targetSdkVersion 更新到最新版本,則系統(tǒng)會(huì)認(rèn)為您的應(yīng)用在最新版本上運(yùn)行時(shí)需要一些向后兼容性行為。例如,在 Android 4.4 中的行為更改中,使用 AlarmManager API 創(chuàng)建的鬧鐘現(xiàn)在默認(rèn)不精確,因此系統(tǒng)可以批量處理應(yīng)用鬧鐘并節(jié)省系統(tǒng)電量,但如果您的目標(biāo) API 級(jí)別低于“19”,則系統(tǒng)會(huì)為您的應(yīng)用保留之前的 API 行為。
不過,如果您的應(yīng)用使用的是較新平臺(tái)版本中添加的 API,但其主要功能并不需要這些 API,則應(yīng)在運(yùn)行時(shí)檢查 API 級(jí)別,并在 API 級(jí)別過低時(shí)適當(dāng)降級(jí)相應(yīng)的功能。在這種情況下,請(qǐng)將 minSdkVersion 盡量設(shè)置為適用于應(yīng)用主要功能的最低值,然后將當(dāng)前系統(tǒng)的版本 SDK_INT 與 Build.VERSION_CODES 中對(duì)應(yīng)于您要檢查的 API 級(jí)別的一個(gè)代號(hào)常量進(jìn)行比較。例如:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// Running on something older than API level 11, so disable
// the drag/drop features that use <code><a href="/reference/android/content/ClipboardManager.html">ClipboardManager</a></code> APIs
disableDragAndDrop();
}
屏幕配置
Android 可在各種尺寸的設(shè)備上運(yùn)行,包括手機(jī)、平板電腦和電視。為了按照屏幕類型對(duì)設(shè)備進(jìn)行分類,Android 為每種設(shè)備定義了兩個(gè)特征:屏幕尺寸(屏幕的物理尺寸)和屏幕密度(屏幕上像素的物理密度,稱為 DPI)。為了簡(jiǎn)化不同的配置,Android 將這些變體歸納成組,使它們更容易作為定位目標(biāo):
四種廣義的尺寸:小、標(biāo)準(zhǔn)、大和特大。
還有幾種廣義的密度:mdpi(中)、hdpi(高)、xhdpi(超高)、xxhdpi(超超高)等。
默認(rèn)情況下,您的應(yīng)用會(huì)兼容所有屏幕尺寸和密度,因?yàn)橄到y(tǒng)會(huì)根據(jù)需要對(duì)各個(gè)屏幕的界面布局和圖片資源進(jìn)行相應(yīng)的調(diào)整。不過,您應(yīng)針對(duì)不同的屏幕尺寸添加專門的布局,針對(duì)常見的屏幕密度添加優(yōu)化的位圖圖片,以優(yōu)化每種屏幕配置的用戶體驗(yàn)。