Rob*_*b B 44 android file android-developer-api android-storage android-11
我试图更好地了解 Android 11 版本发布后我将能够做什么。
我的应用程序使用提供的图像的文件路径Environment.getExternalStorageDirectory()来创建照片相册,但使用Android 11 我将无法直接访问 files。
根据Android开发人员文档,他们最近引入了该MANAGE_EXTERNAL_STORAGE权限,但我不明白添加此权限是否可以继续访问文件Environment。
有没有人有想法???
谢谢
2021 年 1 月更新
我在 Android 11 虚拟设备上尝试了我的应用程序,即使没有请求MANAGE_EXTERNAL_STORAGE许可,它似乎也能完美运行!
阅读 Android Developers 上的文档,似乎使用FILEAPI 仅访问照片和媒体位置的应用程序可以继续工作,但我不确定。
有没有人更了解Android文档???
Tho*_*lad 70
安卓 11
如果您的目标是 Android 11 ( targetSdkVersion 30),那么您需要 AndroidManifest.xml 中的以下权限以进行修改和文档访问。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
Run Code Online (Sandbox Code Playgroud)
对于 Android 10,您将以下行放在 AndroidManifest.xml 标记中
android:requestLegacyExternalStorage="true"
Run Code Online (Sandbox Code Playgroud)
下面的方法检查权限是被允许还是被拒绝
private boolean checkPermission() {
if (SDK_INT >= Build.VERSION_CODES.R) {
return Environment.isExternalStorageManager();
} else {
int result = ContextCompat.checkSelfPermission(PermissionActivity.this, READ_EXTERNAL_STORAGE);
int result1 = ContextCompat.checkSelfPermission(PermissionActivity.this, WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
}
}
Run Code Online (Sandbox Code Playgroud)
以下方法可用于在 android 11 或更低版本中请求权限
private void requestPermission() {
if (SDK_INT >= Build.VERSION_CODES.R) {
try {
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
intent.addCategory("android.intent.category.DEFAULT");
intent.setData(Uri.parse(String.format("package:%s",getApplicationContext().getPackageName())));
startActivityForResult(intent, 2296);
} catch (Exception e) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivityForResult(intent, 2296);
}
} else {
//below android 11
ActivityCompat.requestPermissions(PermissionActivity.this, new String[]{WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}
}
Run Code Online (Sandbox Code Playgroud)
处理Android 11及以上版本的权限回调
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 2296) {
if (SDK_INT >= Build.VERSION_CODES.R) {
if (Environment.isExternalStorageManager()) {
// perform action when allow permission success
} else {
Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
处理 Android 11 以下操作系统版本的权限回调
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0) {
boolean READ_EXTERNAL_STORAGE = grantResults[0] == PackageManager.PERMISSION_GRANTED;
boolean WRITE_EXTERNAL_STORAGE = grantResults[1] == PackageManager.PERMISSION_GRANTED;
if (READ_EXTERNAL_STORAGE && WRITE_EXTERNAL_STORAGE) {
// perform action when allow permission success
} else {
Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
}
}
break;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 15
Android 11 不允许直接访问存储中的文件,您必须从存储中选择文件并将该文件复制到您的应用程序包 chache com.android.myapp 中。下面是将文件表单存储复制到应用程序包缓存的方法
private String copyFileToInternalStorage(Uri uri, String newDirName) {
Uri returnUri = uri;
Cursor returnCursor = mContext.getContentResolver().query(returnUri, new String[]{
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE
}, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File output;
if (!newDirName.equals("")) {
File dir = new File(mContext.getFilesDir() + "/" + newDirName);
if (!dir.exists()) {
dir.mkdir();
}
output = new File(mContext.getFilesDir() + "/" + newDirName + "/" + name);
} else {
output = new File(mContext.getFilesDir() + "/" + name);
}
try {
InputStream inputStream = mContext.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(output);
int read = 0;
int bufferSize = 1024;
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
inputStream.close();
outputStream.close();
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return output.getPath();
}
Run Code Online (Sandbox Code Playgroud)
Naj*_*Ali 10
在此处查看 Android 11 Scoped Storage 更新
快速解决方案在这里:
对于快速解决方案,如果您放置 android 目标并编译 sdk 版本为 29,那么您的应用程序将在 android 11 上运行,其实现与您在此处在 android 10 上所做的相同
在 mainfest 文件中
当您将 android 设备从 api 10(29) 更新到 android 11(30) Api 时,无法从您的设备存储或移动目录中检索数据存储它们不在 android 11 上工作,因为 android 11 引入了新的范围存储更新,您必须在其中实施新方法以使用 MediaStore 对象获取媒体文件,
在阅读了 android 文档后,我想与您分享的一些有用信息列在此处:
在 android 11 中,您只能访问自己特定应用的缓存。
应用程序无法在外部存储上创建自己的应用程序特定目录。要访问系统为您的应用程序提供的目录,请调用 getExternalFilesDirs()
如果您的应用面向 Android 11,则它无法访问任何其他应用的数据目录中的文件,即使其他应用面向 Android 8.1(API 级别 27)或更低版本并使其数据目录中的文件可供所有人阅读
在 Android 11 上,应用无法再访问外部存储中任何其他应用的专用应用特定目录中的文件。
在 Android 11 上运行但面向 Android 10(API 级别 29)的应用仍然可以请求 requestLegacyExternalStorage 属性。此标志允许应用程序暂时退出与范围存储相关的更改,例如授予对不同目录和不同类型媒体文件的访问权限。在您将应用更新为面向 Android 11 后,系统会忽略 requestLegacyExternalStorage 标志。
在此之前,我们在 android 10 上使用
android:requestLegacyExternalStorage="true"
tools:targetApi="q"
Run Code Online (Sandbox Code Playgroud)
现在在应用程序属性下的清单中,此方法在 android 11 中不起作用。
所以现在迁移到新的更新谢谢
遵循此处的教程指南 遵循 GitHub 上的 Scoped Storage 教程
我为Android 11 (SDK R - 30)找到了这种方式:
1- 在Manifest 中必须添加此权限:(仅适用于 R)
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
Run Code Online (Sandbox Code Playgroud)
2- 请求操作系统对话以请求许可:
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.MANAGE_EXTERNAL_STORAGE}, 1);
Run Code Online (Sandbox Code Playgroud)
3- 检查您的应用可以访问存储空间:
if (!Environment.isExternalStorageManager())
Run Code Online (Sandbox Code Playgroud)
4- 使用 Intent为您的应用打开“所有文件访问”
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
Uri uri = Uri.fromParts("package", this.getPackageName(), null);
intent.setData(uri);
startActivity(intent);
Run Code Online (Sandbox Code Playgroud)
注:此回答无需MANAGE_EXTERNAL_STORAGE许可
在 Android 10 及更高版本中,MANAGE_EXTERNAL_STORAGE我们无法将其用于 Play 商店应用程序,除非文件管理器或防病毒软件使其变得毫无用处。
因此,要在没有 MANAGE_EXTERNAL_STORAGE 的情况下从存储中访问照片,下面的答案会很有用
在清单中
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
Run Code Online (Sandbox Code Playgroud)
访问媒体文件
// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your
// app didn't create.
// Container for information about each video.
data class Image(val uri: Uri,
val name: String,
val duration: Int,
val size: Int
)
val imgList = mutableListOf<Image>()
val collection =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Images.Media.getContentUri(
MediaStore.VOLUME_EXTERNAL
)
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.SIZE
)
// Display videos in alphabetical order based on their display name.
val sortOrder = "${MediaStore.Images.Media.DISPLAY_NAME} ASC"
val query = ContentResolver.query(
collection,
projection,
null,
null,
sortOrder
)
query?.use { cursor ->
// Cache column indices.
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
val nameColumn =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)
while (cursor.moveToNext()) {
val id = cursor.getLong(idColumn)
val name = cursor.getString(nameColumn)
val size = cursor.getInt(sizeColumn)
val contentUri: Uri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id
)
// Stores column values and the contentUri in a local object
// that represents the media file.
imgList += Image(contentUri, name, size)
}
}
Run Code Online (Sandbox Code Playgroud)
创建文件
// Request code
const val CREATE_FILE = 1
private fun createFile(pickerInitialUri: Uri) {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "Type of file"
putExtra(Intent.EXTRA_TITLE, "Name of File")
// Optionally, specify a URI for the directory that should be opened in
// the system file picker before your app creates the document.
putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
}
startActivityForResult(intent, CREATE_FILE)
}
Run Code Online (Sandbox Code Playgroud)
根据 Android 开发人员文档,他们最近引入了 MANAGE_EXTERNAL_STORAGE 权限,但我不明白添加此权限是否可以继续按环境访问文件。
是的你将会。但是,请记住,如果您打算在 Play 商店(也可能是其他地方)上分发您的应用程序,您需要证明请求该许可的理由。所以,除非你有一个非常好的理由来使用MANAGE_EXTERNAL_STORAGE,请用别的东西。
| 归档时间: |
|
| 查看次数: |
52163 次 |
| 最近记录: |