Android 在异步任务期间未授予存储访问框架持久权限
Android storage access framework persistable permission not granted during asyntask
我在这里设置了意图标志:
public void createAlbum(View view) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
String intentChooserDialog = getResources().getString(R.string.pick_image_dialog);
startActivityForResult(Intent.createChooser(intent, intentChooserDialog), PICK_IMAGE);
}
在我的 activity 结果中,我设置了持久权限,因为它们被解释 here:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE) {
// Get image selection
if (data != null) {
ClipData clipData = data.getClipData();
if (clipData != null) {
int clipDataCount = clipData.getItemCount();
if (clipDataCount > 1) {
int clipIndex = 0;
BitmapUri[] bitmapUris = new BitmapUri[clipDataCount];
while (clipIndex < clipDataCount) {
ClipData.Item item = clipData.getItemAt(clipIndex);
Uri uri = item.getUri();
int takeFlags = data.getFlags();
takeFlags &= Intent.FLAG_GRANT_READ_URI_PERMISSION;
getContentResolver().takePersistableUriPermission(uri, takeFlags);
BitmapUri bitmapUri = new BitmapUri(Uri.decode(uri.toString()), data.getFlags());
bitmapUris[clipIndex] = bitmapUri;
clipIndex++;
}
DatabaseAlbumWriter dab = new DatabaseAlbumWriter(this);
dab.execute(bitmapUris);
}
} else {
int oneImageSelected = 1;
BitmapUri[] bitmapUris = new BitmapUri[oneImageSelected];
Uri uri = data.getData();
int takeFlags = data.getFlags();
takeFlags &= Intent.FLAG_GRANT_READ_URI_PERMISSION;
getContentResolver().takePersistableUriPermission(uri, takeFlags);
BitmapUri bitmapUri = new BitmapUri(Uri.decode(uri.toString()), data.getFlags());
bitmapUris[0] = bitmapUri;
DatabaseAlbumWriter dab = new DatabaseAlbumWriter(this);
dab.execute(bitmapUris[0]);
}
}
}
}
将内容样式 Uri 保存到 sqlite3 数据库后,我想将它们加载到 gridview 中,但如所述 here 异步加载。这是我在培训指南中对 decodeSampledBitmapFromResource 的实现。传入一个带有 Uri 解码字符串的对象和来自原始意图的持久权限。这些值保存在数据库中并再次加载到这里。
protected Bitmap decodeSampledBitmapFromResource(BitmapUri bitmapUri, int reqWidth, int reqHeight) {
Bitmap bitmap = null;
Uri uri = Uri.parse(bitmapUri.getStringUri());
int permissions = bitmapUri.getPermissions();
permissions &= Intent.FLAG_GRANT_READ_URI_PERMISSION;
try {
getContentResolver().takePersistableUriPermission(uri, permissions);
ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Rect rect = new Rect(-1,-1,-1,-1);
BitmapFactory.decodeFileDescriptor(fileDescriptor, rect, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, rect, options);
parcelFileDescriptor.close();
} catch (NullPointerException | SecurityException | IOException e) {
e.printStackTrace();
}
return bitmap;
}
}
正是在这里我得到了这个错误:
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: java.lang.SecurityException: No persistable permission grants found for UID 10058 and Uri 0 @ content://com.android.providers.media.documents/document/image:32
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at android.os.Parcel.readException(Parcel.java:1599)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at android.os.Parcel.readException(Parcel.java:1552)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at android.app.ActivityManagerProxy.takePersistableUriPermission(ActivityManagerNative.java:4217)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at android.content.ContentResolver.takePersistableUriPermission(ContentResolver.java:1703)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at com.example.app.AlbumCreator$BitmapWorkerTask.decodeSampledBitmapFromResource(AlbumCreator.java:395)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at com.example.app.AlbumCreator$BitmapWorkerTask.doInBackground(AlbumCreator.java:343)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at com.example.app.AlbumCreator$BitmapWorkerTask.doInBackground(AlbumCreator.java:329)
如果我从 activity 结果中带有 BitmapFactory.decodeFileDescriptor 的 parcelFileDescriptor 加载位图,我不会收到此错误。因此,据我所知,AsyncTask 是具有不同权限的不同用户。有人知道如何为 AsyncTask 分配持久权限吗?我不想在 UI 线程上加载位图。
这是我的清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name=".AlbumCreator"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--
ATTENTION: This was auto-generated to add Google Play services to your project for
App Indexing. See https://g.co/AppIndexing/AndroidStudio for more information.
-->
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<activity
android:name=".AlbumEditor"
android:label="@string/title_activity_album_editor"
android:parentActivityName=".AlbumCreator">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.app.AlbumCreator" />
</activity>
</application>
</manifest>
您需要在清单中添加必要的权限。
请添加:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
如果要进行写操作,这是必需的。
试一试,如果有帮助请告诉我们。
我解决了我自己的问题。如果您查看我的代码,您会发现我使用了 intent.getData()。然后我坚持使用该 uri 的许可。当我保存 uri 供以后使用时,我对其进行了解码。 Uri.decode(uri.toString()
.
编码的 URI:content://com.android.providers.media.documents/document/image%3A32
解码:content://com.android.providers.media.documents/document/image:32
因此,我改为使用 intent.getDataString(),然后使用 Uri.parse() 为 takePersistableUriPermission() 方法创建一个 Uri。然后,我将 Intent 中的初始数据字符串保存在保留编码组件的数据库中。
我在这里设置了意图标志:
public void createAlbum(View view) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
String intentChooserDialog = getResources().getString(R.string.pick_image_dialog);
startActivityForResult(Intent.createChooser(intent, intentChooserDialog), PICK_IMAGE);
}
在我的 activity 结果中,我设置了持久权限,因为它们被解释 here:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE) {
// Get image selection
if (data != null) {
ClipData clipData = data.getClipData();
if (clipData != null) {
int clipDataCount = clipData.getItemCount();
if (clipDataCount > 1) {
int clipIndex = 0;
BitmapUri[] bitmapUris = new BitmapUri[clipDataCount];
while (clipIndex < clipDataCount) {
ClipData.Item item = clipData.getItemAt(clipIndex);
Uri uri = item.getUri();
int takeFlags = data.getFlags();
takeFlags &= Intent.FLAG_GRANT_READ_URI_PERMISSION;
getContentResolver().takePersistableUriPermission(uri, takeFlags);
BitmapUri bitmapUri = new BitmapUri(Uri.decode(uri.toString()), data.getFlags());
bitmapUris[clipIndex] = bitmapUri;
clipIndex++;
}
DatabaseAlbumWriter dab = new DatabaseAlbumWriter(this);
dab.execute(bitmapUris);
}
} else {
int oneImageSelected = 1;
BitmapUri[] bitmapUris = new BitmapUri[oneImageSelected];
Uri uri = data.getData();
int takeFlags = data.getFlags();
takeFlags &= Intent.FLAG_GRANT_READ_URI_PERMISSION;
getContentResolver().takePersistableUriPermission(uri, takeFlags);
BitmapUri bitmapUri = new BitmapUri(Uri.decode(uri.toString()), data.getFlags());
bitmapUris[0] = bitmapUri;
DatabaseAlbumWriter dab = new DatabaseAlbumWriter(this);
dab.execute(bitmapUris[0]);
}
}
}
}
将内容样式 Uri 保存到 sqlite3 数据库后,我想将它们加载到 gridview 中,但如所述 here 异步加载。这是我在培训指南中对 decodeSampledBitmapFromResource 的实现。传入一个带有 Uri 解码字符串的对象和来自原始意图的持久权限。这些值保存在数据库中并再次加载到这里。
protected Bitmap decodeSampledBitmapFromResource(BitmapUri bitmapUri, int reqWidth, int reqHeight) {
Bitmap bitmap = null;
Uri uri = Uri.parse(bitmapUri.getStringUri());
int permissions = bitmapUri.getPermissions();
permissions &= Intent.FLAG_GRANT_READ_URI_PERMISSION;
try {
getContentResolver().takePersistableUriPermission(uri, permissions);
ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Rect rect = new Rect(-1,-1,-1,-1);
BitmapFactory.decodeFileDescriptor(fileDescriptor, rect, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, rect, options);
parcelFileDescriptor.close();
} catch (NullPointerException | SecurityException | IOException e) {
e.printStackTrace();
}
return bitmap;
}
}
正是在这里我得到了这个错误:
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: java.lang.SecurityException: No persistable permission grants found for UID 10058 and Uri 0 @ content://com.android.providers.media.documents/document/image:32
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at android.os.Parcel.readException(Parcel.java:1599)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at android.os.Parcel.readException(Parcel.java:1552)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at android.app.ActivityManagerProxy.takePersistableUriPermission(ActivityManagerNative.java:4217)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at android.content.ContentResolver.takePersistableUriPermission(ContentResolver.java:1703)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at com.example.app.AlbumCreator$BitmapWorkerTask.decodeSampledBitmapFromResource(AlbumCreator.java:395)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at com.example.app.AlbumCreator$BitmapWorkerTask.doInBackground(AlbumCreator.java:343)
05-08 14:17:40.850 2728-2813/com.example.app W/System.err: at com.example.app.AlbumCreator$BitmapWorkerTask.doInBackground(AlbumCreator.java:329)
如果我从 activity 结果中带有 BitmapFactory.decodeFileDescriptor 的 parcelFileDescriptor 加载位图,我不会收到此错误。因此,据我所知,AsyncTask 是具有不同权限的不同用户。有人知道如何为 AsyncTask 分配持久权限吗?我不想在 UI 线程上加载位图。
这是我的清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name=".AlbumCreator"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--
ATTENTION: This was auto-generated to add Google Play services to your project for
App Indexing. See https://g.co/AppIndexing/AndroidStudio for more information.
-->
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<activity
android:name=".AlbumEditor"
android:label="@string/title_activity_album_editor"
android:parentActivityName=".AlbumCreator">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.app.AlbumCreator" />
</activity>
</application>
</manifest>
您需要在清单中添加必要的权限。 请添加:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
如果要进行写操作,这是必需的。
试一试,如果有帮助请告诉我们。
我解决了我自己的问题。如果您查看我的代码,您会发现我使用了 intent.getData()。然后我坚持使用该 uri 的许可。当我保存 uri 供以后使用时,我对其进行了解码。 Uri.decode(uri.toString()
.
编码的 URI:content://com.android.providers.media.documents/document/image%3A32
解码:content://com.android.providers.media.documents/document/image:32
因此,我改为使用 intent.getDataString(),然后使用 Uri.parse() 为 takePersistableUriPermission() 方法创建一个 Uri。然后,我将 Intent 中的初始数据字符串保存在保留编码组件的数据库中。