java 如何在 android API 19 (KitKat) 中保留权限?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25414352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 07:59:59  来源:igfitidea点击:

How to persist permission in android API 19 (KitKat)?

javaandroidsqliteandroid-4.4-kitkatstorage-access-framework

提问by Pdksock

In my application I store the path of image in my SQlite db for further use. The path that I get is

在我的应用程序中,我将图像的路径存储在我的 SQlite 数据库中以供进一步使用。我得到的路径是

content://com.android.providers.media.documents/document/image%3A71964

When I retrieve this path from the database and try to retrieve the image from that path android throws

当我从数据库中检索此路径并尝试从 android 抛出的该路径中检索图像时

java.lang.SecurityException: Permission Denial: opening provider
com.android.providers.media.MediaDocumentsProvider 
from ProcessRecord{42c84ec8 23911:com.gots.gb/u0a248} (pid=23911, uid=10248) 
requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS

According https://developer.android.com/guide/topics/providers/document-provider.html#permissionsI need to persist permission by adding the following code

根据https://developer.android.com/guide/topics/providers/document-provider.html#permissions我需要通过添加以下代码来保持权限

final int takeFlags = intent.getFlags()
        & (Intent.FLAG_GRANT_READ_URI_PERMISSION
        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(uri, takeFlags);

When I added this code to my ImageAdapter class which extends BaseAdapter android throws

当我将此代码添加到扩展 BaseAdapter 的 ImageAdapter 类时,android 抛出

08-21 02:14:38.530: W/System.err(24452): java.lang.SecurityException:
No permission grant found for UID 10248 and Uri 
content://com.android.providers.media.documents/document/image:71964

This is the relevant part of my ImageAdapter code

这是我的 ImageAdapter 代码的相关部分

public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView ;


    if (convertView == null){
        imageView = new ImageView(mContext);
        imageView.setLayoutParams(new GridView.LayoutParams(185, 185));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setPadding(8, 8, 8, 8);

    }
    else{
        imageView = (ImageView)convertView ;
    }

    InputStream is = null;
    Bitmap bitmap = null ;

    try {

        Log.d(TAG,String.valueOf(list.get(position)));
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        final int takeFlags = intent.getFlags()
                & (Intent.FLAG_GRANT_READ_URI_PERMISSION
                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // Check for the freshest data.

        if (Build.VERSION.SDK_INT >= 19){
            mContext.getContentResolver().takePersistableUriPermission(list.get(position), takeFlags);
        }


        is = mContext.getContentResolver().openInputStream(list.get(position));

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 8;
        bitmap = BitmapFactory.decodeStream(is,null, options);
        is.close();
        imageView.setImageBitmap(bitmap);

        return imageView;

    }
    catch (Exception e) {
        e.printStackTrace();

        return null;
    }

what am I doing wrong? Thanks

我究竟做错了什么?谢谢

回答by DariusL

I believe I've solved it. The request intent:

我相信我已经解决了。请求意图:

Intent intent;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
    intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
    intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
}else{
    intent = new Intent(Intent.ACTION_GET_CONTENT);
}
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent, getResources().getString(R.string.form_pick_photos)), REQUEST_PICK_PHOTO);

and onActivityResult

onActivityResult

...
// kitkat fixed (broke) content access; to keep the URIs valid over restarts need to persist access permission
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    final int takeFlags = data.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION;
    ContentResolver resolver = getActivity().getContentResolver();
    for (Uri uri : images) {
        resolver.takePersistableUriPermission(uri, takeFlags);
    }
}
...

I haven't tested this pre-kitkat, my phone is running 5.1, can anyone verify this on older phones?

我还没有测试过这个 pre-kitkat,我的手机运行的是 5.1,谁能在旧手机上验证一下?

回答by David

The code listed below,

下面列出的代码,

// kitkat fixed (broke) content access; to keep the URIs valid over restarts need to persist access permission
if(Utils.isKitkat())
{
    final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION);
    ContentResolver resolver = getActivity().getContentResolver();
    for (Uri uri : images)
    {
        resolver.takePersistableUriPermission(uri, takeFlags);
    }
}

worked fine for me, anyway I noticed that the max number of persistable uri granted to my app is limited to 128. If I select more than 128 uri, I get the error:

对我来说效果很好,无论如何我注意到授予我的应用程序的最大持久 uri 数量限制为 128。如果我选​​择超过 128 个 uri,我会收到错误消息:

java.lang.SecurityException: Permission Denial: opening provider........

just when I try to process an image for which I wasn't able to persist the permission. Can you figure out any solution?

就在我尝试处理无法保留权限的图像时。你能想出什么解决办法吗?

回答by Ivan Vovk

Other way to avoid request permissions is to use SharedPreferences. save uri as string (or other way you need it) and retrieve it without any trouble.

避免请求权限的其他方法是使用 SharedPreferences。将 uri 保存为字符串(或您需要的其他方式)并轻松检索它。