Android10及以上访问公有目录 | 您所在的位置:网站首页 › 共享文件user在哪个目录下打开的 › Android10及以上访问公有目录 |
公有目录指的是系统根目录下的Download、DCIM、Documents、Screenshots、Music等文件夹。 本文说的访问是指:列举出某一公有目录下的所有文件、删除某个文件、保存文件到某个公有目录等意思。 Android10以下按原来的File(path)方式,本文不表。 Android10及以上可以使用MediaStore访问公有目录。如果我们在公有目录下只操作自己应用生成的文件,是不需要申请文件读写权限的。另外,公有目录下的文件在APP卸载后不会被删除,也能被其他应用访问(仅限于媒体类型的文件)。(其他应用只能read,不能write) 下面是关于Android10及以上存储权限的说明:(官方说明:https://developer.android.com/training/data-storage?hl=zh-cn) WRITE_EXTERNAL_STORAGE在Android11已过时,不要再去申请这个。 Android10及以上是新版的权限MANAGE_EXTERNAL_STORAGE。但是如果你要在Google Play上架,且你的APP不是文件管理器之类的应用,那么建议查看一下Google Play的政策说明:https://support.google.com/googleplay/android-developer/answer/9956427。代码里Android Stuido也提示说Most apps are not allowed to use MANAGE_EXTERNAL_STORAGE。 READ_EXTERNAL_STORAGE读取权限。如果你需要读取别的应用保存在公有目录下的文件(仅限于媒体文件,无法读取到其他类型的。。),则需要动态申请这个权限;如果读取的是自己应用保存的文件,即便是公有目录,也不需要申请这个权限(ps:有个场景需要读取权限:应用卸载后,之前创建的文件会变成“无主”文件,以后应用重新安装是需要读取权限的。大白话就是:应用卸载重装后,之前的文件不属于你了,现在你去读取,相当于是读别人的文件,所以要读取权限)。 下面的代码都是以Download文件夹为例的,不再特别说明。如果需要操作其他文件夹,改一下Uri即可。 私有目录文件复制到公有目录 /** * 复制私有目录的文件到公有Download目录 * @param context 上下文 * @param oldPath 私有目录的文件路径 * @param targetDirName 公有目录下的目标文件夹名字。比如传test,则会复制到Download/test目录下。另外如果Download目录下test文件夹不存在,会自动创建。 * @return 公有目录的uri,为空则代表复制失败 */ @RequiresApi(Build.VERSION_CODES.Q) fun copyFileToDownloadDir(context: Context,oldPath: String,targetDirName:String): Uri? { try { val oldFile = File(oldPath) //设置目标文件的信息 val values = ContentValues() values.put(MediaStore.Images.Media.DESCRIPTION, "This is a file.") values.put(MediaStore.Files.FileColumns.DISPLAY_NAME, oldFile.name) values.put(MediaStore.Files.FileColumns.TITLE, oldFile.name) values.put(MediaStore.Files.FileColumns.MIME_TYPE, getMimeType(oldPath)) val relativePath = Environment.DIRECTORY_DOWNLOADS + File.separator + targetDirName values.put(MediaStore.Images.Media.RELATIVE_PATH, relativePath) val downloadUri = MediaStore.Downloads.EXTERNAL_CONTENT_URI val resolver = context.contentResolver val insertUri = resolver.insert(downloadUri, values) if (insertUri != null) { val fos = resolver.openOutputStream(insertUri) if (fos != null) { val fis = FileInputStream(oldFile) fis.copyTo(fos) fis.close() fos.close() return insertUri } } } catch (e: Exception) { e.printStackTrace() } return null } fun getMimeType(path: String?): String { var mime = "*/*" path ?: return mime val mmr = MediaMetadataRetriever() try { mmr.setDataSource(path) mime = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE) ?: mime } catch (e: Exception) { e.printStackTrace() } finally { mmr.release() } return mime } 查询公有目录下的文件 /** * 获取公有Download目录下的文件 * @param dirName Download目录下的下一级文件夹的名字 * @return 文件的uri集合 */ @RequiresApi(Build.VERSION_CODES.Q) fun listFiles(context: Context, dirName: String): List { val resultList = ArrayList() try { val resolver = context.contentResolver val downloadUri = MediaStore.Downloads.EXTERNAL_CONTENT_URI val resultCursor = resolver?.query( downloadUri, null, MediaStore.Files.FileColumns.BUCKET_DISPLAY_NAME + "=?", arrayOf(dirName), null ) if (resultCursor != null) { val fileIdIndex = resultCursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID) // val fileNameIndex = resultCursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME) while (resultCursor.moveToNext()) { val fileId = resultCursor.getLong(fileIdIndex) //文件名 // val fileName = resultCursor.getString(fileNameIndex) val pathUri = downloadUri.buildUpon().appendPath("$fileId").build() resultList.add(pathUri) } resultCursor.close() } } catch (e: Exception) { e.printStackTrace() } return resultList } 删除公有目录下的文件 /** * 删除公有目录的文件。(自己应用创建的文件才有权限删除) */ @RequiresApi(Build.VERSION_CODES.Q) fun deleteFile(context: Context, fileUri: Uri) { try { context.contentResolver?.delete(fileUri, null, null) } catch (e: Exception) { e.printStackTrace() } } 公有目录文件复制到私有目录 /** * 公有目录文件复制到私有目录 * @param fileUri 公有目录文件的uri * @param privatePath 私有目录的路径 */ fun copyToPrivateDir(context: Context,fileUri:Uri,privatePath:String){ try { val fis = FileInputStream(context.contentResolver.openFileDescriptor(fileUri,"r")?.fileDescriptor) fis.copyTo(FileOutputStream(privatePath)) fis.close() }catch (e:Exception){ e.printStackTrace() } }上面用到的api,导包如下: import android.content.ContentValues import android.content.Context import android.media.MediaMetadataRetriever import android.net.Uri import android.os.Build import android.os.Environment import android.provider.MediaStore import androidx.annotation.RequiresApi import java.io.File import java.io.FileInputStream import java.io.FileOutputStream import java.lang.Exception |
CopyRight 2018-2019 实验室设备网 版权所有 |