Android 11下免MANAGE_STORAGE_ACCESS权限无交互读取卸载留存纯文本文件方案
Android 11 无交互读取BLE配对信息文件解决方案
核心背景说明
Android 11 引入的分区存储机制中,通过MediaStore创建的非媒体类自定义文件,在应用卸载后确实会丢失直接访问权限,你要求的无用户交互、不申请MANAGE_EXTERNAL_STORAGE权限的前提下,有两种可行实现方案:
方案1:直接读取系统蓝牙配对记录(最优解)
你提到系统蓝牙管理器本身会留存已配对设备记录,完全可以跳过自定义文件持久化逻辑,直接通过系统蓝牙接口读取设备Mac地址,不需要任何存储权限,也完全不受应用卸载影响:
- 仅需要常规蓝牙权限,适配起来没有兼容问题
- 代码示例:
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter.isEnabled()) { Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices(); for (BluetoothDevice device : bondedDevices) { String macAddress = device.getAddress(); // 结合设备名、服务UUID等特征筛选你需要的BLE设备即可 } }
方案2:保留自定义文件逻辑的适配方法
如果业务必须保留自定义文本文件存储配对信息的逻辑,可以按以下规则实现:
- 写入文件阶段:将文本文件存入公共下载目录
Environment.DIRECTORY_DOWNLOADS,文件名添加应用专属前缀(比如com_xxx_ble_bonded_list.txt),写入操作不需要额外存储权限 - 读取文件阶段:应用重装后不需要申请存储权限,直接通过MediaStore查询公共下载目录下匹配你专属文件名的文件即可读取内容,Android 10及以上版本原生支持该操作,无需用户交互
- 代码示例:
val projection = arrayOf(MediaStore.Files.FileColumns._ID, MediaStore.Files.FileColumns.DISPLAY_NAME) val selection = "${MediaStore.Files.FileColumns.DISPLAY_NAME} = ?" val selectionArgs = arrayOf("com_xxx_ble_bonded_list.txt") val contentUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) contentResolver.query(contentUri, projection, selection, selectionArgs, null)?.use { cursor -> if (cursor.moveToFirst()) { val fileId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)) val targetUri = ContentUris.withAppendedId(contentUri, fileId) contentResolver.openInputStream(targetUri)?.use { inputStream -> // 直接读取输入流中的文本内容即可 } } }
注意事项
不要尝试用内部存储、SharedPreferences存储配对信息,应用卸载后这些数据会被系统自动清除,无法满足持久化需求。
内容的提问来源于stack exchange,提问作者Varsha Kulkarni
相关产品推荐
相关产品推荐

