安卓sd卡分区软件(判断手机在a分区还是b分区工具无法)

Andid 10(Q)/11(R) 分区存储适配

大部分应用都会请求 ( READ_EXTERNAL_STORAGE ) ( WRITE_EXTERNAL_STORAGE ) 存储权限,来做一些诸如在 SD 卡中存储文件或者读取多媒体文件等常规操作。这些应用可能会在磁盘中存储大量文件,即使应用被卸载了还会依然存在。另外,这些应用还可能会读取应用的一些敏感文件数据。

为此, 终于下定决心在 Andid 10 中引入了分区存储,对权限进行场景的细分,按需索取,并在 Andid 11 中进行了进一步的调整。

Andid 存储分区情况

Andid 中存储可以分为两大类:私有存储和存储

    私有存储 (Pvate Storage) : 每个应用在都拥有自己的私有目录,其它应用看不到,彼此也无法访问到该目录:内部存储私有目录 (/data/data/packageName) ;外部存储私有目录 (/sdcard/Andid/data/packageName),存储 (Shared Storage) : 存储应用可访问文件, 包含媒体文件、文档文件以及文件,对应设备DCIM、Pictes、Alarms、Music、Notifications、Podcasts、Ringtones、Movies、Download等目录。

Andid 10(Q) :

Andid 10 中主要对目录进行了权限详细的划分,不再能通过路径访问。

受影响的接口:

访问不同分区的方式:

    私有目录:和以前的版本一致,可通过 File API 访问,无需申请权限。目录:需要通过Store和Storage Access Framework API 访问,视具体情况申请权限,下面详细介绍。

其中,对目录的权限进行了细分:

    无需申请权限的操作:通过 Store API对媒体集、文件集进行媒体/文件的添加、对 自身APP 创建的 媒体/文件 进行查询、修改、删除的操作。需要申请READ_EXTERNAL_STORAGE 权限:通过 Store API对所有的媒体集进行查询、修改、删除的操作。调用 Storage Access Framework API :会启动的文件选择器向用户申请操作指定的文件

新的访问方式:

Andid 11 (R):

Andid 11 (R) 在 Andid 10 (Q) 中分区存储的基上进行了调整

1. 执行批量操作

为实现各种设备之间的一致并增加用户便利,Andid 11 向 Store API 中添加了多种方法。对于希望简化特定媒体文件更改流程(例如在原位置编辑照片)的应用而言,这些方法尤为有用。

Store API 的方法

在调用以上一个方法后,会构建一个 PendingIntent 对象。应用调用此 intent 后,用户会看到一个对话框,请求用户同意应用更新或删除指定的媒体文件。

2. 使用直接文件路径和原生库访问文件

为了帮助您的应用更顺畅地使用第三方媒体库,Andid 11 允许您使用除 Store API 之外的 API 访问存储空间中的媒体文件。不过,您也可以转而选择使用以下任一 API 直接访问媒体文件:File API。原生库,例如 fopen。

简单来说就是,可以通过 File 等API 访问有权限访问的媒体集了。

能:

通过 File 等直接通过路径访问的 API 实际上也会映为Store API 。按文件路径顺序读取的时候能相当;随机读取和写入的时候则会更慢,所以还是推荐直接使用 StoreAPI。

3. 权限

MANAGE_EXTERNAL_STORAGE : 类似以前的 READ_EXTERNAL_STORAGE + WRITE_EXTERNAL_STORAGE ,除了应用专有目录都可以访问。

应用可通过执行以下操作向用户请求名为所有文件访问权限的特殊应用访问权限:

    在清单中声明 MANAGE_EXTERNAL_STORAGE 权限。使用 ACTION_MANAGE_ALL_FI_ACCESS_PERMISSION intent 操作将用户引导至一个设置页面,在该页面上,用户可以为您的应用启用以下选项:授予所有文件的权限。
    在 Play 上架的话,需要提交使用此权限的说明,只有指定的几种类型的 APP 才能使用。

Sample

    使用 Store 增删改查媒体集使用 Storage Access Framework 访问文件集

1. 媒体集

1) 查询媒体集(需要 READ_EXTERNAL_STORAGE 权限)

实际上 Store 是以前就有的 API ,不同的是过去主要通过 这个 colum 请求原始数据,可以得到U ,现在需要请求来得到相对U再进行处理。

// Need the READ_EXTERNAL_STORAGE permission if accessing video fi that yo
//  didn't .
// Container for infortion about each video.
data class Video(
val u: U,
val name: Stng,
val dation: Int,
val size: Int
)
val videoList = mutableListOf<Video>
val ion = arrayOf(
,
,
,
)
// Show only videos that are at least 5 minutes in dation.
val selection = "${} >= ?"
val selectionArgs = arrayOf(
(5, ).toStng
)
// Display videos in alphabetical order based on their display name.
val sortOrder = "${} ASC"
val query = ContentResolver.query(
,
ion,
selection,
selectionArgs,
sortOrder
)
query?.use { csor ->
// Cache column indices.
val idColumn =
val nameColumn =
val dationColumn =
val sizeColumn =
while  {
// Get values of columns for a given video.
val id = (idColumn)
val name = (nameColumn)
val dation = (dationColumn)
val size = (sizeColumn)
val contentU: U = ContentUs.withAppendedId(
,
id
)
// Stores column values and the contentU in a local object
// that represents the media file.
videoList += Video(contentU, name, dation, size)
}
}

2)入媒体集(无需权限)

// Add a media  that other s shouldn't see until the  is
// lly wtten to the media store.
val resolver =
// Find all dio fi on the pry external storage device.
// On API <= 28, use VOLUME_EXTERNAL tead.
val dioCollection =
.getContentU
val songDetails = ContentValues.ly {
put(, "My Workout ")
put(, 1)
}
val songContentU = (dioCollection, songDetails)
(songContentU, "w", null).use { pfd ->
// Wte data into the pending dio file.
}
// Now that we're finished, release the "pending" status, and allow other s
// to play the dio track.
(, 0)
(songContentU, songDetails, null, null)

3)更新自己创建的媒体集(无需权限)

删除类似

// Updates an existinedia .
val mediaId = //
val resolver =
// When performing a single  update, prefer using the ID
val selection = "${} = ?"
// By using selection + args we ptect agat impper escaping of // values.
val selectionArgs = arrayOf
// Update an existing song.
val updatedSongDetails = ContentValues.ly {
put(, "My Favote ")
}
// Use the individual song's I to represent the collection that's
// updated.
val numSongsUpdated = (
myFavoteSongU,
updatedSongDetails,
selection,
selectionArgs)

4)更新/删除其它媒体创建的媒体集

若已经开启分区存储则会抛出 RecoverableSecityException,捕获并通过SAF请求权限

// Apply a grayscale filter to the ige at the given content I.
try {
(ige-content-i, "w")?.use {
setGrayscaleFilter(it)
}
} catch (secityException: SecityException) {
if (>= ) {
val recoverableSecityException = secityException as?
RecoverableSecityException ?:
thw RuntimeException(, secityException)
val intentSender =
intentSender?.let {
startIntentSenderForResult(intentSender, ige-request-code,
null, 0, 0, 0, null)
}
} else {
thw RuntimeException(, secityException)
}
}

2. 文件集 (通过 SAF)

1)创建文档

注:创建操作若重名的话不会覆盖原文档,会添加 (1) 为后缀,如 > document(1).pdf

// Request code for creating a PDF document.
const val _FILE = 1
pvate n File(pickerInitialU: U) {
val intent = Intent.ly {
addCategory
type = "lication/pdf"
putExtra(, "")
// Optionally, specify a I for the directory that should be opened in
// the  file picker before yo  s the document.
putExtra(, pickerInitialU)
}
startActivityForResult(intent, _FILE)
}

2)打开文档

建议使用 type 设置 MIME 类型

// Request code for selecting a PDF document.
const val PICK_PDF_FILE = 2
n openFile(pickerInitialU: u) {
val intent = Intent.ly {
addCategory
type = "lication/pdf"
// Optionally, specify a I for the file that should ear in the
//  file picker when it loads.
putExtra(, pickerInitialU)
}
startActivityForResult(intent, PICK_PDF_FILE)
}

3)授予对目录内容的访问权限

用户选择目录后,可访问该目录下的所有内容

Andid 11 中无法访问 Downloads

n openDirectory(pickerInitialU: U) {
// Choose a directory using the 's file picker.
val intent = Intent.ly {
// Pvide read access to fi and sub-directoes in the user-selected
// directory.
flags =
// Optionally, specify a I for the directory that should be opened in
// the  file picker when it loads.
putExtra(, pickerInitialU)
}
startActivityForResult(intent, yo-request-code)
}

4)获取目录访问权限

上面提到的授权是临时的,重启后则会失效。可以通过下面的方法获取相应目录的权限

val contentResolver =
val takeFlags: Int =
// Check for the freshest data.
(i, takeFlags)

5)SAF API 响应

SAF API 调用后都是通过 onActivityResult来相应动作

overde n onActivityResult(
requestCode: Int, resultCode: Int, resultData: Intent?) {
if (requestCode == yo-request-code
&& resultCode == ) {
// The result data conta a I for the document or directory that
// the user selected.
resultData?.data?.also { u ->
// Perform operations on the document using its I.
}
}
}

6) 其它操作

除了上面的操作之外,对文档其它的、等操作都是通过设置不同的 FLAG 来实现,见

3. 批量操作媒体集

构建一个媒体集的写入操作 WteRequest

val usToModify = /* A collection of content Is to modify. */
val editPendingIntent = (contentResolver,
usToModify)
// Lnch a  pmpt requesting user permission for the operation.
startIntentSenderForResult(, EDIT_REQUEST_CODE,
null, 0, 0, 0)
//相应
overde n onActivityResult(requestCode: Int, resultCode: Int,
data: Intent?) {
when (requestCode) {
EDIT_REQUEST_CODE ->
if (resultCode == ) {
/* Edit request granted; pceed. */
} else {
/* Edit request not granted; explain to the user. */
}
}
}

FavoteRequest TrashRequest DeleteRequest 同理

适配和兼容

在 targetSDK = 29 APP 中,在 AndidManifes 设置 requestLegacyExternalStorage="true" 启用兼容模式,以传统分区模式运行。

   <nifest  >
<!-- This attbute is "false" by deflt on s targeting
Andid 10 or higher. -->
<lication andid:requestLegacyExternalStorage="true"  >
</lication>
</nifest>
注意:如果某个应用在安装时启用了传统外部存储,则该应用会保持此模式,直到卸载为止。无论设备后续是否级为搭载 Andid 10 或更高版本,或者应用后续是否更新为以 Andid 10 或更高版本为目标,此兼容行为均适用。

就是在新新安装的应用才会启用,覆盖安装会保持传统分区模式,例如:

    通过 OTA 级到 Andid 10/11应用通过更新级到 targetSdkVersion >= 29

补充

Q:之前讨论过一些问题,APP 无需权限可以访问自己创建的媒体,那么如何进行判断?

A:创建媒体时会给媒体打上 packageName tag,应用被卸载则会 tag ,所以不会存在使用同样 packageName 进行欺骗的情况。

Q:我可以在媒体集文件夹下创建文档,就可以避开权限的问题了?

A:文档上写了只能创建相应类型的媒体/文件,具体如何限制的,没有说明。

总结

从 Andid 10提出分区存储之后到现在已经一年多了,所以 从强制推行的态度到现在 targetSDK >=30 才强制启用分区存储来看, 还是渐渐地选择给者留更多的时间。缺点当然是不强制启用的话, APP 适配进度估计得延后了。不过好是在查资料的时候,看到了大厂的相关适配文章,至少说明大厂在跟进了。

去年(19年)的文档描述是无论 targetSDK 多少,明年(20年)高版本强制启用。

今年(20)文档描述是 targetSDK >=30 才强制启用

关于适配的难度:

对路径相关接口依赖比较深的 APP 适配还是改动挺多的;其次权限的划分很细,什么时候需要什么权限以及调用哪个接口,理解起来需要时间;Store API SAF API 这类接口以前就设计好了,我也觉得也不算特别好;后也需要重新进行。

所以虽然明年才会分区存储,但还是建议尽早理解和 review 中需要适配的代码。

文末附上大厂学长给我的资料,内容包含:Andid学PDF+架构+文档+源码笔记,架构技术进阶脑、Andid专题资料,进阶架构资料 这几块的内容

这些都是我现在闲暇还会反复翻阅的精品资料。里面对近几年的大厂高频知识点都有详细的讲解。相信可以有效的帮助大家掌握知识、理解原理。

如果你有需要的话,可以私信我我发给你

喜欢本文的话,不妨顺手给我点个赞、区留言或者转发支持一下呗~

上一篇: 如何修复硬盘的方法(移动硬盘灯亮但不读取无法识别硬盘数据恢复)
下一篇: 返回列表

为您推荐