Android 各 API Level 权限变更和功能限制汇总
参考:
https://developer.android.google.cn/preview/privacy/checklist
https://developer.android.google.cn/about/versions/pie/android-9.0-changes-all
https://developer.android.google.cn/about/versions/pie/android-9.0-changes-28
https://developer.android.google.cn/about/versions/oreo/android-8.0-changes
https://developer.android.google.cn/about/versions/oreo/background-location-limits
https://developer.android.google.cn/about/versions/nougat/android-7.0-changes
https://developer.android.google.cn/about/versions/marshmallow/android-6.0-changes
https://developer.android.google.cn/about/versions/android-5.0-changes
信息访问限制
序列号
如果以 Android 9 为目标平台,Build.SERIAL
始终设置为 "UNKNOWN"
以保护用户的隐私。
如果您的应用需要访问设备的硬件序列号,您应改为请求 READ_PHONE_STATE
权限,然后调用 getSerial()
。
不可重置的设备标识符
从 Android Q(API 级别 29)开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE
特许权限才能访问设备的不可重置标识符(包含 IMEI
和序列号
)。此权限为系统级别权限
,第三方应用加入无效。
如果您的应用没有该权限,平台的响应会因目标 SDK 版本和应用类型而异:
-
对于第三方普通应用:
-
如果应用以 Android Q 为目标平台,则会发生
SecurityException
。 -
如果应用以 Android 9(API 级别 28)或更低版本为目标平台,则相应方法会返回
null
或占位符数据(如果应用具有READ_PHONE_STATE
权限)。否则,会发生SecurityException
。 -
对于设备所有者或配置文件所有者应用:
即使您的应用以 Android Q 为目标平台,您也只需READ_PHONE_STATE
权限即可访问不可重置的设备标识符。 -
对于具有特殊运营商权限的应用:
无需任何权限即可访问这些标识符。
如果您的应用将不可重置的设备标识符用于广告跟踪或用户分析目的,请为这些特定用例创建 Android 广告 ID。要了解详情,请参阅唯一标识符的最佳做法。
下面两种方法可以替代这些类型的标识符:
- 使用
com.google.android.gms.iid
InstanceID API。getInstance(Context context).getID()
将为您的应用实例返回一个唯一设备标识符。结果是一个应用实例作用域标识符,在存储有关应用的信息时,该标识符可用作键,如果用户重新安装应用,该标识符会重置。 - 使用
randomUUID()
之类的基本系统函数创建您自己的标识符,其作用域限定为应用的存储空间。
MAC 地址
从 Android 6.0(API 级别 23)版本开始,对于使用 WLAN API 和 Bluetooth API 的应用,Android 移除了对设备本地硬件标识符的编程访问权。WifiInfo.getMacAddress() 方法和 BluetoothAdapter.getAddress() 方法现在会返回常量值 02:00:00:00:00:00
。
要通过蓝牙和 WLAN 扫描访问附近外部设备的硬件标识符,您的应用必须拥有 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 权限。
默认情况下,搭载 Android Q 的设备会传输随机选择的 MAC 地址。如果您的应用处理企业用例,平台会提供几个新的 API:
- 获取随机分配的 MAC 地址:设备所有者应用和配置文件所有者应用可以通过调用
getRandomizedMacAddress()
检索分配给特定网络的随机 MAC 地址。
// Added in API level 29
// 信息仅限于设备所有者、配置文件所有者和运营商应用程序,
// 且这些应用程序将仅获取其创建的配置的地址,
// 其他调用者将收到默认的“02:00:00:00:00:00”MAC地址。
public MacAddress getRandomizedMacAddress ()
- 获取实际的出厂 MAC 地址:设备所有者应用可以通过调用
getWifiMacAddress()
检索设备的实际硬件 MAC 地址。此方法对于跟踪设备队列非常有用。
// Added in API level 24
// Throws SecurityException if admin is not a device owner
public String getWifiMacAddress (ComponentName admin)
涉及位置信息的 telephony、WLAN、Bluetooth API
Android 8
WLAN
由于 Android 8.0 会对后台应用检索用户当前位置的频率进行限制,startScan() 方法对后台应用执行完整扫描的频率仅为每小时数次。如果不久之后后台应用再次调用此方法, WifiManager 类将提供上次扫描所缓存的结果。
Android 9
Telephony
如果用户在运行 Android 9 的设备上停用设备定位,则以下函数不提供结果:
WLAN
从 Android 9 开始,有更严格的 Wi-Fi 扫描限制:
A successful call to WifiManager.startScan() requires all of the following conditions to be met:
- Your app has the ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission.
- Your app has the CHANGE_WIFI_STATE permission.
- Location services are enabled on the device (under Settings > Location).
To successfully call WifiManager.getScanResults() ensure all of the following conditions are met:
- Your app has the ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission.
- Your app has the ACCESS_WIFI_STATE permission.
- Location services are enabled on the device (under Settings > Location).
同样,如果要使用 getConnectionInfo()
函数返回的描述当前 Wi-Fi 连接的 WifiInfo
对象来检索 SSID 和 BSSID 值,就也需要具备与 WifiManager.getScanResults()
相同的3个条件。
If the calling app doesn’t meet all of these requirements, the call fails with a SecurityException.
在 Android 9 中,下列事件和广播不接收用户位置或个人可识别数据方面的信息:
WifiManager
中的getScanResults()
和getConnectionInfo()
函数。WifiP2pManager
中的discoverServices()
和addServiceRequest()
函数。NETWORK_STATE_CHANGED_ACTION
广播。
Wi-Fi 的 NETWORK_STATE_CHANGED_ACTION
系统广播不再包含 SSID(之前为 EXTRA_SSID)、BSSID(之前为 EXTRA_BSSID)或连接信息(之前为 EXTRA_NETWORK_INFO)。 如果应用需要此信息,请改为调用 getConnectionInfo()
。
Android Q
以 Android Q 为目标平台的应用,除非具有 ACCESS_FINE_LOCATION
权限,否则应用在 Android Q 上运行时无法使用 WLAN API、Wi-Fi Aware API 或 Bluetooth API 中的多种方法。下面列出了受影响的方法。
注意:如果您的应用在 Android Q 上运行但以 Android 9(API 级别 28)或更低版本为目标平台,则只要您的应用具有
ACCESS_COARSE_LOCATION
或ACCESS_FINE_LOCATION
权限,您就可以使用受影响的 API。
Telephony
TelephonyManager
getCellLocation()
getAllCellInfo()
requestNetworkScan()
requestCellInfoUpdate()
getAvailableNetworks()
getServiceStateForSubscriber
getServiceState()
TelephonyScanManager
requestNetworkScan()
TelephonyScanManager.NetworkScanCallback
onResults()
PhoneStateListener
onCellLocationChanged()
onCellInfoChanged()
onServiceStateChanged()
WLAN
WifiManager
startScan()
getScanResults()
getConnectionInfo()
getConfiguredNetworks()
WifiAwareManager
WifiP2pManager
WifiRttManager
Bluetooth
BluetoothAdapter
startDiscovery()
startLeScan()
LeScanCallback()
位置访问
Android 8.0
为降低功耗,无论应用的目标 SDK 版本为何,Android 8.0 都会对后台应用检索用户当前位置的频率进行限制。
我们只允许后台应用每小时接收几次位置更新。我们将在整个预览版阶段继续根据系统影响和开发者的反馈优化位置更新间隔。
如果应用在运行 Android 8.0 的设备上处于前台,其位置更新行为将与 Android 7.1.1(API 级别 25)及更低版本上相同。
应用满足以下任一条件即视为前台应用:
- 它具有可见的 Activity,无论 Activity 处于启动还是暂停状态。
- 它具有前台服务。
- 另一个前台应用通过绑定到应用的其中一个服务或使用应用的其中一个内容提供程序与应用相连。
如果以上所有条件均不满足,应用即视为后台应用。
考虑在您的应用接收位置更新不频繁的情况下其后台运行用例是否根本无法成功。如果