【Android 10 适配】隐私权限变更

更详细内容请参考 Android 10 中的隐私权变更

Android 10(API 级别 29)引入了多项功能和行为变更,旨在更好地保护用户的隐私。这些变更让用户更清楚地了解并更好地控制自己的数据及为应用提供的权能。

下面是 Android 10 中与隐私权限相关的主要变更。

1. 外部存储访问权限范围限定为应用文件和媒体【分区存储】

默认情况下,以 Android 10 及更高版本为目标平台【targetSdkVersion 30】的应用对外部存储空间进行分区访问(即分区存储)。此类应用可以查看外部存储设备内以下类型的文件,而无需请求任何与存储相关的用户权限:

  • 特定于应用的目录中的文件(使用 getExternalFilesDir() 访问)。
  • 应用创建的照片、视频和音频片段(通过媒体库访问)。

在 Android 10 及以上版本中常见存储类型的具体路径示例:

外部私有目录(应用专属目录):
内部存储:/storage/emulated/0/Android/data/包名/files/
外部存储:/storage/emulated/0/Android/data/包名/files/外部公共目录(共享存储区域):
图片目录:/storage/emulated/0/Pictures/
音频目录:/storage/emulated/0/Music/
视频目录:/storage/emulated/0/Movies/
下载目录:/storage/emulated/0/Download/

getExternalFilesDir() 的使用

val fileDir = getExternalFilesDir(null)
if (fileDir != null) {val fileName = "example.txt"val file = File(fileDir, fileName)try {// 写入文件file.writeText("Hello, World!")// 读取文件val content = file.readText()Log.d("getExternalFilesDir", content)} catch (e: IOException) {e.printStackTrace()}
} else {Log.d("getExternalFilesDir", "Failed to get external files directory.")
}

保存应用创建的照片

fun createExternalStoragePrivatePicture() {// 在应用程序私有目录中创建一个图片路径,我们将放置我们自己的图片。// 注意,我们实际上不需要将图片放在 DIRECTORY_PICTURES 中,// 因为媒体扫描程序将会看到这些目录中的所有媒体文件;// 但是还有其他的媒体文件类型,例如 DIRECTORY_MUSIC,所以将媒体文件分类展示有利于用户交互。val path = getExternalFilesDir(Environment.DIRECTORY_PICTURES)val file = File(path, "DemoPicture.jpg")try {val inputStream = resources.openRawResource(R.drawable.add_ic)val outputStream = FileOutputStream(file)val data = ByteArray(inputStream.available())inputStream.read(data)outputStream.write(data)inputStream.close()outputStream.close()// 告诉媒体扫描程序有关新文件的信息,以便立即对用户可用。MediaScannerConnection.scanFile(this,arrayOf(file.toString()), null){ p, uri ->Log.d("ExternalStorage", "已扫描路径:$p")Log.d("ExternalStorage", "-> uri=$uri")}} catch (e: IOException) {// 无法创建文件,可能是因为外部存储当前未挂载。Log.d("ExternalStorage", "写入文件时出错:$file", e)}}

访问共享存储空间中的媒体文件

更多详细内容请参考
访问共享存储空间中的媒体文件

fun getAllExternalImages() :List<Uri>{val collection = MediaStore.Images.Media.getContentUri("external")val projection = arrayOf(MediaStore.Images.Media._ID,MediaStore.Images.Media.DISPLAY_NAME,MediaStore.Images.Media.DATE_TAKEN)val sortOrder = "${MediaStore.Images.Media.DATE_TAKEN} DESC"val query = contentResolver?.query(collection,projection,null,null,sortOrder)val uriList = mutableListOf<Uri>()query?.use { cursor ->val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)while (cursor.moveToNext()) {val id = cursor.getLong(idColumn)val contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,id)uriList.add(contentUri)}}return uriList
}

使用照片选择器

更详尽内容请参考
照片选择器
注意:为了简化照片选择器的集成,请添加 1.7.0 版或更高版本的 androidx.activity 库。

选择单个媒体项
// 注册一个照片选择器活动启动器,以单选模式运行。
val pickMedia = registerForActivityResult(PickVisualMedia()) { uri ->// 在用户选择媒体项目或关闭照片选择器后调用回调。if (uri != null) {Log.d("PhotoPicker", "Selected URI: $uri")} else {Log.d("PhotoPicker", "No media selected")}
}// 启动照片选择器,并允许用户选择图像和视频。
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))// 启动照片选择器,并仅允许用户选择图像。
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))// 启动照片选择器,并仅允许用户选择视频。
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.VideoOnly))// 启动照片选择器,并仅允许用户选择特定 MIME 类型的图像/视频,例如 GIF。
val mimeType = "image/gif"
pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.SingleMimeType(mimeType)))
选择多个媒体项
// 注册一个多选模式的照片选择器活动启动器。
// 在此示例中,应用程序允许用户选择最多5个媒体文件。
val pickMultipleMedia =registerForActivityResult(PickMultipleVisualMedia(5)) { uris ->// 用户选择媒体项目或关闭照片选择器后调用回调。if (uris.isNotEmpty()) {Log.d("PhotoPicker", "选择的项目数量:${uris.size}")} else {Log.d("PhotoPicker", "未选择媒体文件")}
}// 启动照片选择器,并允许用户选择图像和视频。
pickMultipleMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))

2. 在后台运行时访问设备位置信息需要权限

Android 10 引入了 ACCESS_BACKGROUND_LOCATION 权限。

与 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION 权限不同,ACCESS_BACKGROUND_LOCATION 权限仅会影响应用在后台运行时对位置信息的访问权限。

除非符合以下条件之一,否则应用会被视为在后台访问位置信息:

  • 属于该应用的 activity 可见。
  • 该应用运行的某个前台服务已声明前台服务类型为 location。

应用在后台访问位置信息需要设置ACCESS_BACKGROUND_LOCATION 权限

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.myapp"><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /><!-- 其他清单文件声明 --><application><!-- 应用程序组件声明 --></application></manifest>

如果应用创建并监控地理围栏,并以 Android 10(API 级别 29)或更高版本为目标平台,那么也必须声明 ACCESS_BACKGROUND_LOCATION 权限。

地理围栏解释 地理围栏

以 Android 9 或更低版本为目标平台时自动授予访问权限

对于目标平台为 Android 9 或更低版本的应用,在 Android 10 或更高版本上运行时, 如果你在应用的清单文件中声明了 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 权限,系统会在安装过程中自动为 ACCESS_BACKGROUND_LOCATION 添加相应的权限声明。

也就是说,尽管你的应用的目标平台是 Android 9 或更低版本,但在 Android 10 或更高版本上运行时,系统会自动处理 ACCESS_BACKGROUND_LOCATION 权限的授予,无需额外的代码或处理。

但对于目标平台为 Android 10 或更高版本的应用,仍然需要显式请求 ACCESS_BACKGROUND_LOCATION 权限。

3. 标识符和数据

更多内容请参考 标识符和数据

应用程序无法直接访问 /proc/net

从 Android 10 开始,应用程序无法直接访问 /proc/net 文件系统,其中包含与设备的网络状态相关的信息。这是出于安全和隐私的考虑,以防止应用程序获取敏感的网络信息。

对不可重置的设备标识符实施了限制

从 Android 10 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 特许权限才能访问设备的不可重置标识符(包括 IMEI 和序列号)。

限制了对剪贴板数据的访问权限

除非您的应用是默认的输入法 (IME) 或当前获得焦点的应用,否则它在 Android 10 或更高版本上无法访问剪贴板数据。

4. 摄像头和连接性

对访问摄像头详情和元数据的权限实施了限制

Android 10 更改了 getCameraCharacteristics() 方法默认返回的信息的广度。具体而言,您的应用必须具有 CAMERA 权限才能访问此方法的返回值中可能包含的设备特定元数据。

对启用和停用 WLAN 实施了限制

以 Android 10 或更高版本为目标平台的应用无法启用或停用 Wi-Fi。WifiManager.setWifiEnabled() 方法始终返回 false。

如果您需要提示用户启用或停用 Wi-Fi,请使用下面的方式打开设置面板:

fun openWifiSetting() {val intent = Intent(Settings.ACTION_WIFI_SETTINGS)startActivity(intent)
}

对直接访问已配置的 Wi-Fi 网络实施了限制

详见 官网

如果您的应用以 Android 10 或更高版本为目标平台,并且它不是系统应用或 DPC,则以下方法不会返回有用数据:

  • getConfiguredNetworks() 方法始终返回一个空列表。
  • 每个返回整数值的网络操作方法(addNetwork() 和 updateNetwork())始终返回 -1。
  • 每个返回布尔值的网络操作(removeNetwork()、reassociate()、enableNetwork()、disableNetwork()、reconnect() 和 disconnect())始终返回 false。

可选方式:

  1. 如需触发与 Wi-Fi 网络的即时本地连接,请在标准 NetworkRequest 对象中使用 WifiNetworkSpecifier。

详情请参考官网
注意 :使用此 API 创建连接并不会提供与应用或设备的互联网连接。如需为设备上的应用提供互联网连接,请改用 Wi-Fi Suggestion API。

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.net.wifi.WifiNetworkSpecifier
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivityclass MainActivity : AppCompatActivity() {private val TAG = "WifiNetworkSpecifier"override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 获取 ConnectivityManager 实例val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager// 创建 NetworkRequest 对象val requestBuilder = NetworkRequest.Builder()// 设置网络类型为 Wi-FirequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)// 创建 WifiNetworkSpecifier 对象val specifier = WifiNetworkSpecifier.Builder().setSsid("Your_WiFi_SSID") // 设置要连接的 Wi-Fi 网络的 SSID.build()// 将 WifiNetworkSpecifier 添加到 NetworkRequest 中requestBuilder.setNetworkSpecifier(specifier)// 注册网络回调connectivityManager.requestNetwork(requestBuilder.build(),object : ConnectivityManager.NetworkCallback() {override fun onAvailable(network: Network) {// 当网络可用时触发Log.d(TAG, "Network available")// 可以使用返回的 Network 对象进行网络操作// ...}override fun onUnavailable() {// 当网络不可用时触发Log.d(TAG, "Network unavailable")}})}
}
  1. 使用 Wi-Fi Suggestion API。

详情请参考官网
注意 :Wi-Fi 建议不是已保存的网络,也不会显示在“已保存的网络”页面中。

import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.wifi.WifiNetworkSuggestion
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivityclass MainActivity : AppCompatActivity() {private val TAG = "WifiNetworkSuggestion"override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 获取 ConnectivityManager 实例val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager// 创建 WifiNetworkSuggestion 列表val suggestionsList = mutableListOf<WifiNetworkSuggestion>()// 创建一个 WifiNetworkSuggestion 对象val suggestion = WifiNetworkSuggestion.Builder().setSsid("Your_WiFi_SSID") // 设置要添加的 Wi-Fi 网络的 SSID.setWpa2Passphrase("Your_WiFi_Password") // 设置 Wi-Fi 网络的密码.build()// 将 WifiNetworkSuggestion 添加到列表中suggestionsList.add(suggestion)// 添加网络建议connectivityManager.addNetworkSuggestions(suggestionsList)// 注册网络回调connectivityManager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {override fun onAvailable(network: android.net.Network) {// 当网络可用时触发Log.d(TAG, "Network available")// 可以使用返回的 Network 对象进行网络操作// ...}override fun onLost(network: android.net.Network) {// 当网络丢失时触发Log.d(TAG, "Network lost")}})}override fun onDestroy() {super.onDestroy()// 移除网络建议val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManagerconnectivityManager.removeNetworkSuggestions(emptyList())}
}

5. 权限

详情请见 官网
注意 :本部分介绍的每项变更都会影响搭载 Android 10 或更高版本的设备上的所有应用,甚至是以 Android 9(API 级别
28)或更低版本为目标平台的应用。

限制对屏幕内容的访问

为了保护用户的屏幕内容,Android 10 更改了 READ_FRAME_BUFFER、CAPTURE_VIDEO_OUTPUT 和 CAPTURE_SECURE_VIDEO_OUTPUT 权限的作用域,从而禁止以静默方式访问设备的屏幕内容。从 Android 10 开始,这些权限只能通过签名访问。

需要访问设备屏幕内容的应用应使用 MediaProjection API,此 API 会显示提示,要求用户同意声明。

使用 MediaProjection API 请求屏幕捕获权限:

import android.content.Intent
import android.media.projection.MediaProjectionManager
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivityclass MainActivity : AppCompatActivity() {private val REQUEST_MEDIA_PROJECTION = 1private lateinit var mediaProjectionManager: MediaProjectionManageroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)mediaProjectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManager// 请求屏幕捕获权限startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION)}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == REQUEST_MEDIA_PROJECTION && resultCode == RESULT_OK) {// 用户已授权屏幕捕获权限// 在这里可以开始捕获屏幕内容// ...}}
}

面向用户的权限检查(针对旧版应用)

如果您的应用以 Android 5.1(API 级别 22)或更低版本为目标平台,当用户首次在搭载 Android 10 或更高版本的设备上使用您的应用时,会看到权限屏幕。通过该界面,用户可以撤消系统先前在安装应用时授予应用的权限。

身体活动识别

Android 10 针对需要检测用户步数或对用户的身体活动(例如步行、骑车或坐车)进行分类的应用引入了 android.permission.ACTIVITY_RECOGNITION 运行时权限。此项权限旨在让用户了解设备传感器数据在“设置”中的使用方式。

从界面中移除了权限组

从 Android 10 开始,应用无法在界面中查询权限的分组方式。

Thank you for your reading, best regards!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/614982.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux ----冯诺依曼体系结构与操作系统

目录 前言 一、冯诺依曼体系结构 二、为什么选择冯诺依曼体系结构&#xff1f; 三、使用冯诺依曼结构解释问题 问题1&#xff1a; 问题2: 四、操作系统 1.操作系统是什么 2.为什么需要操作系统 3.操作系统怎样管理的 4.如何给用户提供良好环境 五、我们是怎样调用系…

Windows Copilot 更新及使用教程

要更新并使用 Windows Copilot&#xff0c;在 Windows 11 上&#xff0c;首先确保您的系统已经更新到最新版本。Windows Copilot 是随 Windows 11 23H2 更新一起发布的新 AI 助手功能。它可以回答您的问题&#xff0c;完成任务&#xff0c;导航 Windows&#xff0c;并提高您的工…

native2ascii命令详解

native2ascii命令详解 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;让我们一同深入研究Java开发中常用的工具——"native2ascii"命令&a…

Github 2024-01-12Java开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-01-12统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Java项目10Vue项目3 Apache Flink: 开源流处理框架 创建周期&#xff1a;3506 天开发语言&#xff1a;Java协…

安卓 onActivityResult 废弃,registerForActivityResult 使用详解

文章目录 onActivityResult 存在的问题registerForActivityResult 有哪些改进registerForActivityResult 实战registerForActivityResult 自定义使用registerForActivityResult 开箱即用StartActivityForResultGetContent 后记注意事项附录 安卓的兼容性是出了名的低&#xff0…

C语言中的位运算详解

在C语言中&#xff0c;位运算符用于对二进制位进行操作&#xff0c;包括左移、右移、按位与、按位或、按位异或和按位取反等操作。本文将详细介绍C语言中的位运算符&#xff0c;包括运算规则和具体的例子。 1. 位运算符概述 C语言提供了一些位运算符&#xff0c;用于直接操作…

iOS rootless无根越狱解决方案

据游戏工委数据统计&#xff0c;2023年国内游戏市场实际销售收入与用户规模双双创下新高&#xff0c;游戏普遍采用多端并发方式&#xff0c;成为收入增长的主因之一。 中国市场实际销售收入及增长率丨数据来源&#xff1a;游戏工委 多端互通既是机遇&#xff0c;也是挑战。从游…

python实例100第16例:使用datetime输出指定格式的日期

题目&#xff1a;输出指定格式的日期。 程序分析&#xff1a;使用 datetime 模块。 #!/usr/bin/python # -*- coding: UTF-8 -*-import datetimeif __name__ __main__:# 输出今日日期&#xff0c;格式为 dd/mm/yyyy。更多选项可以查看 strftime() 方法print(datetime.date.t…

【AI大模型应用开发】1.0 Prompt Engineering(提示词工程)- 典型构成、原则与技巧,代码中加入Prompt

从这篇文章开始&#xff0c;我们就正式开始学习AI大模型应用开发的相关知识了。首先是提示词工程&#xff08;Prompt Engineering&#xff09;。 文章目录 0. 什么是提示词&#xff08;Prompt&#xff09;1. 为什么Prompt会起作用 - 大模型工作原理2. Prompt的典型构成、原则与…

【5】商密测评密码辅助工具

0X01 前言 最近在学了下商密测评&#xff0c;研究了下技术层面的测评&#xff0c;感觉找工具不方便&#xff0c;就顺手自己造了个辅助工具&#xff0c;都是自己遇到需要用的。 0x02 工具功能介绍 不爱打字&#xff0c;直接上图。后续根据技术测评层面需要继续完善和增加功能。…

基于VSG控制的MMC并网逆变器MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介 根据传统同步发电机的运行特性设计了MMC-VSG功频控制器和励磁控制器&#xff0c; 实现了MMC-VSG逆变器对高压电网电压和频率的支撑。该模型包含MMC变流器模块&#xff0c;环流抑制模块&#xff0c;…

HackTheBox-Keeper

OpenVPN连接 连接上HackTheBox&#xff01; 同时找到这个靶机&#xff0c;进行join&#xff01;分配的靶机的地址位10.10.11.227&#xff01; 信息收集 nmap -sT --min-rate 10000 -p- 10.10.11.227 开放端口为22和80端口 服务版本和操作系统信息探测&#xff1a; nmap -s…

Milvus Cloud与携程的向量探索大公开

【User Tech】2024 我们来啦&#xff01; 今年&#xff0c;【User Tech】将更加专注于为社区用户提供技术功能解读、热点答疑&#xff0c;聚焦更丰富、更多样化的行业或使用场景的用户案例。我们期待通过分享更多关于 Milvus Cloud 的实战经验&#xff0c;为大家在 AI、大模型、…

ASM磁盘组配置共享存储:裸设备(60)_块设备(12)_(99)方式

--1.块设备方式配置共享存储 存储信息&#xff1a; 20个1TB的LUN&#xff0c;/dev/mapper/mpath1--mpath20 修改/etc/udev/rules.d/12-dm-permissions.rules添加内容 vi /etc/udev/rules.d/12-dm-permissions.rules ENV{DM_NAME}"mpath1", OWNER:"grid",…

YOLOv8算法改进【NO.98】改进损失函数为最新提出的Shape-IoU

前 言 YOLO算法改进系列出到这&#xff0c;很多朋友问改进如何选择是最佳的&#xff0c;下面我就根据个人多年的写作发文章以及指导发文章的经验来看&#xff0c;按照优先顺序进行排序讲解YOLO算法改进方法的顺序选择。具体有需求的同学可以私信我沟通&#xff1a; 第一…

1-08运算符和表达式

一、概述 在C语言中&#xff0c;表达式和语句是构成程序的基本元素。本节和下一章节我们就围绕它们展开讲一讲其中的C语言基础语法。 首先&#xff0c;让我们区分这两个概念&#xff1a; 语句(statement)&#xff0c;语句是代码中的一个完整的&#xff0c;可以执行的步骤。 …

微信小程序内嵌h5 分享子页面点击进入后是主页面解决办法

<web-view src{{src}}></web-view>src: https://XXXXXX,/*** 生命周期函数--监听页面加载 */ onLoad(options) {this.srcFun(options) },srcFun(options){//当有子页面id时 更改内嵌页链接if (options.urlPathNew) { let urlhttps://XXX/caseOrder?classicId${opt…

李沐之经典卷积神经网络

目录 1. LeNet 2. 代码实现 1. LeNet 输入是32*32图片&#xff0c;放到一个5*5的卷积层里面&#xff0c;卷积层的输出通道数是6&#xff0c;高宽都是28&#xff08;32-5128&#xff09;。再经过2*2的池化层&#xff0c;把28*28变成14*14&#xff08;28-22&#xff09;/214&am…

《Vue2 进阶知识》动态挂载组件之Vue.extend + vm.$mount

前言 目前工作还是以 Vue2 为主&#xff0c;今早有人提问 如何动态挂载组件&#xff1f; 话说很久很久以前就实现过&#xff0c;今天再详细的整理一下此问题&#xff01; 开始 动态组件如下&#xff0c;是个简单的例子&#xff1a; 但请注意这里给了个 id"test2"…

vue 组件 import make sure to provide the “name“ option.

百度了好多结果&#xff0c;都过时了&#xff0c;例如&#xff1a; 模块引入是否加{} 再比如&#xff1a; 对于递归组件&#xff0c;请确保提供“name”选项。 出现该错误情况之一&#xff1a; 错误由未正确引入组件或子组件引起&#xff0c;如element-ui中form表单组件未引…