Controlling Your App‘s Availability to Devices
android 提供了很多 feature,有的基于硬件,例如指南针传感器。有的基于软件,例如 widget。还有的是基于 OS 版本。因为并不是每个设备都支持所有的 feature,所以我们要基于设备所具备的 feature 对 App 的 feature 进行控制。
通常为了用户量,我们要尽量让我们的 App 能在更多的设备运行。为了达到这个目的,有的时候我们要在运行时关掉一些非必须的功能 ,因为有的设备可能没有相应的 feature。并且提供不同的可选配置,例如为不同屏幕尺寸提供不同的 layout 文件。从另一方面讲,因为有的设备太老旧,或者说支持这样的设备开发成本太大。我们就可以通过以下几方面来控制 App 可以安装在哪些设备上。
Device features
不管是基于硬件或者是基于软件的 feature ,Android 都为每一个 feature 都定义了一个 feature ID。例如,指南针传感器的 ID 是 FEATURE_SENSOR_COMPASS, widget 的 ID是
FEATURE_APP_WIDGETS
。
这样如果我们在 manifest file 里面声明了一个 feature,那么那些没有这个 feature 的设备就不能安装我们的 App。
例如,如果我们不确定目标设备是否有指南针传感器,但是我们的 App 又必须要这个传感器才能运行,我们就可以在 manifest 里面声明我们的 App 必需这个 feature:
<manifest ... > <uses-feature android:name="android.hardware.sensor.compass" android:required="true" /> ... </manifest>
Google Play Store 会拿 App 所需的 feature 列表和用户设备所具有的 feature 做对比,来识别某一个设备是否能安装这个 App。如果设备不支持这里声明的任何一个 feature,那么该设备就不能安装这个 App。
另一方面,如果一个 feature 是否存在并不影响 App 的主要功能,那么我们可以把 required 设置为 false ,这样即使没有这个 feature 的设备也可以安装该 App,然后在运行时检测设备是否有这个 feature。如果设备没有这个 feature,这时候我们再关掉 App 相应的功能。下面是在 runtime 检测一个 feature 是否存在的例子:
PackageManager pm = getPackageManager(); if (!pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)) { // This device does not have a compass, turn off the compass feature disableCompassFeature(); }
更多关于 feature 过滤的功能请参考 Filters on Google Play。
注意:有的权限请求声明会默认包含 feature 请求声明。例如如果 App 声明了需要 BLUETOOTH 权限,那么实际上也等于声明了目标设备需要有
FEATURE_BLUETOOTH
feature 。基于此,我们可以再显式地做一个 feature 声明,并把 required 设置为 false 来关闭这个 feature 过滤,这样没有蓝牙的设备也可以安装我们的 App。详情参考 Permissions that Imply Feature Requirements。
Platform version
不同的设备运行的 Android platform 版本不同,例如 Android 4.0、Android 4.4。当然新的 API 不会加到旧版本上去。为了便于区分 API 集,每个 Android platform 版本都会有一个 API level。例如 Android 1.0 的 API level 是 1,而 Android 4.4 是 API level 19。
通过设置 <uses-sdk>
的 minSdkVersion
值,API level 可以用来声明 App 可以兼容的最低版本。例如,Android 4.0(API level 14)才有 Calendar Provider API 集。如果你的 App 没这个 API 不行,那么你就应该把 API level 14 作为 App 支持的最低版本。
minSdkVersion
用于声明 App 兼容到的最低版本。
targetSdkVersion
用于声明 App 已经充分使用的最高版本。
需要注意的是,<uses-sdk>
中的声明会被 build.gradle
file 覆盖。所以如果你使用 Android Studio,必须在 build.gradle
中声明 minSdkVersion
和
targetSdkVersion
,而不是在
manifest
中声明它们:
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 26
...
}
}
关于 build.gradle
详情参考 how to configure your build。
如果 targetSdkVersion
的值为18,而你的手机是 Android 4.4(19),这个手机仍然可以安装你的 App。但是这个属性依然很重要,因为系统可以通过它来识别你的 App 是否使用新版新的特性。如果你不把 targetSdkVersion
写成最高版本,那么当 App 在高版本上运行的时候,系统会让你的 App 用一些旧版本的 API。例如,Android 4.4 中,默认情况下通过 AlarmManager
API 集创建的 alarm 的提醒时间不是很精准,这样系统就可以批量处理这些 alarm 以节约电量。如果你的 targetSdkVersion
小于19,那么系统仍然会用之前的版本的行为来创建 alarm。
另一方面,如果我们的 App 使用了一些高版本才有的 API 集,但是没有这些 API 也不影响主要功能,那么我们就可以在运行时检测 API level ,如果版本太低就关闭相应的 App 功能。这种情况应当把 minSdkVersion
设置为 App 主要功能所需的最低版本,然后在运行时拿当前系统版本
SDK_INT
和 App 想要的 API 版本常量作比较:
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 ClipboardManager APIs disableDragAndDrop(); }
Screen configuration
从手机到平板,包括电视,Android 程序可以在很多尺寸的设备上运行。为了对这些设备的屏幕进行归类,Android 为所有的设备定义了两个参数:屏幕尺寸和屏幕密度(屏幕上的像素密度,就是DPI)。为了便于使用,Android 对它们进行了归类:
屏幕尺寸分为四类:small, normal, large, 和 xlarge.
像素密度分为:mdpi (medium), hdpi (hdpi), xhdpi (extra high), xxhdpi (extra-extra high), and others。
默认情况下系统会根据实际屏幕参数对你的布局及资源图片进行适当的调整,所以你的 App 可以兼容所有屏幕尺寸和像素密度的屏幕。但是为了能在各种设备上有更好的用户体验,你应该为不同屏幕尺寸提供对应的布局,并且基于常见像素密度的屏幕,对图片资源进行优化。
For information about how to create alternative resources for different screens and how to restrict your app to certain screen sizes when necessary, read Supporting Different Screens.