权限被拒绝:打开未从 uid 导出的提供程序 com.google.android.apps.photos.contentprovider.MediaContentProvider

Posted

技术标签:

【中文标题】权限被拒绝:打开未从 uid 导出的提供程序 com.google.android.apps.photos.contentprovider.MediaContentProvider【英文标题】:Permission denied : opening provider com.google.android.apps.photos.contentprovider.MediaContentProvider that is not exported from uid 【发布时间】:2017-03-19 05:22:27 【问题描述】:

当我尝试访问之前存储在 SharedPreferences 中的照片 URI 时,我的应用程序仅在 android >= 6.0 (marshmallow) 中崩溃。虽然第一次检索图像没有任何错误。我正在使用targetSdkVersion 22,因此我不需要在 API >=23 中处理运行时权限。

我的清单文件中的权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />

我得到的图像如下:

 // Determine Uri of camera image to save.
    final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "pics" + File.separator);
    root.mkdirs();
    final String fname = Calendar.getInstance().getTimeInMillis() + ".jpg";
    final File sdImageMainDirectory = new File(root, fname);
    outputFileUri = Uri.fromFile(sdImageMainDirectory);

    // Camera.
    final List<Intent> cameraIntents = new ArrayList<Intent>();
    final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    final PackageManager packageManager = getPackageManager();
    final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
    for (ResolveInfo res : listCam) 
        final String packageName = res.activityInfo.packageName;
        final Intent intent = new Intent(captureIntent);
        intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
        intent.setPackage(packageName);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
        cameraIntents.add(intent);
    

    // Filesystem.
    Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

    // Chooser of filesystem options.
    final Intent chooserIntent = Intent.createChooser(galleryIntent, "Select Source");

    // Add the camera options.
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[cameraIntents.size()]));
    startActivityForResult(chooserIntent, Constants.IMAGE_PICKER);

这是我的 OnActivityResult 方法:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    if (resultCode == RESULT_OK) 
        if (requestCode == Constants.IMAGE_PICKER) 
            if (data == null) 
                selectedImageUri = outputFileUri;
             else 
                selectedImageUri = data.getData();
            
            if (selectedImageUri != null) 
                try 
                    String path = AppUtils.getPath(this, selectedImageUri);
                    if (path != null) 
                        Bitmap bitmap = AppUtils.decodeFile(new File(path));
                        File f = new File(System.currentTimeMillis() + ".jpg");
                        OutputStream os = new BufferedOutputStream(new FileOutputStream(f));
                        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
                        os.close();
                        uploadImageToServer(f, bitmap);
                    
                 catch (Exception e) 
                    e.printStackTrace();
                
            
        
    

其中 getPath() 是来自https://***.com/a/20559418/3758972 的函数。

堆栈跟踪:

java.lang.RuntimeException: Unable to start activity ComponentInfocom.badiyajobs.app/com.badiyajobs.app.screens.ProfileActivity: java.lang.SecurityException: Permission Denial: opening provider com.google.android.apps.photos.contentprovider.MediaContentProvider from ProcessRecord25e87b7 20432:com.badiyajobs.app/u0a389 (pid=20432, uid=10389) that is not exported from uid 10107
                                                                    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2426)
                                                                    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490)
                                                                    at android.app.ActivityThread.access$900(ActivityThread.java:154)
                                                                    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354)
                                                                    at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                    at android.os.Looper.loop(Looper.java:148)
                                                                    at android.app.ActivityThread.main(ActivityThread.java:5443)
                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
                                                                 Caused by: java.lang.SecurityException: Permission Denial: opening provider com.google.android.apps.photos.contentprovider.MediaContentProvider from ProcessRecord25e87b7 20432:com.badiyajobs.app/u0a389 (pid=20432, uid=10389) that is not exported from uid 10107
                                                                    at android.os.Parcel.readException(Parcel.java:1620)
                                                                    at android.os.Parcel.readException(Parcel.java:1573)
                                                                    at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:3605)
                                                                    at android.app.ActivityThread.acquireProvider(ActivityThread.java:4799)
                                                                    at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2018)
                                                                    at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1466)
                                                                    at android.content.ContentResolver.query(ContentResolver.java:475)
                                                                    at android.content.ContentResolver.query(ContentResolver.java:434)
                                                                    at com.badiyajobs.app.utils.AppUtils.getDataColumn(AppUtils.java:790)
                                                                    at com.badiyajobs.app.utils.AppUtils.getPath(AppUtils.java:776)
                                                                    at com.badiyajobs.app.screens.ProfileActivity.setDefaultValue(ProfileActivity.java:192)
                                                                    at com.badiyajobs.app.screens.ProfileActivity.onCreate(ProfileActivity.java:162)
                                                                    at android.app.Activity.performCreate(Activity.java:6259)
                                                                    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1130)
                                                                    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2379)
                                                                    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490) 
                                                                    at android.app.ActivityThread.access$900(ActivityThread.java:154) 
                                                                    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354) 
                                                                    at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                    at android.os.Looper.loop(Looper.java:148) 
                                                                    at android.app.ActivityThread.main(ActivityThread.java:5443) 
                                                                    at java.lang.reflect.Method.invoke(Native Method) 
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728) 
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 

我不知道我错过了什么。请帮忙。

【问题讨论】:

I try to access a photo URI stored previously in SharedPreferences.。可以,但您没有发布您在其中放入的方式和内容。你如何提取它以及如何使用它。所以没什么好说的。 你有一个复杂的选择意图。从来没见过这样的。 Intent.EXTRA_INITIAL_INTENTS, cameraIntents.这个有什么作用? SharedPreference 部分无关紧要并且工作正常。这会为多个应用创建一个选择器。 在这里发布问题时不要这样做。只需尽可能使用最简单的 ACTION_PICK,然后展示如何将选择的 uri 保存到共享首选项,以及如何直接和之后使用它。您没有发布该代码。这是我第二次要求你这样做。 我使用 ***.com/a/29588566/3758972 解决了我的问题。谢谢。 【参考方案1】:

在您的意图中使用 ACTION_OPEN_DOCUMENT 而不是 ACTION_PICK。它允许对您请求的文件进行长期、持久的访问。

Intent galleryIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);

这里的文档: https://developer.android.com/guide/topics/providers/document-provider.html

【讨论】:

【参考方案2】:

创建一个类名 RealPathUtil,如下所示

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.CursorLoader;
import android.database.Cursor;
import android.net.Uri;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

public class RealPathUtil 

@SuppressLint("NewApi")
public static String getRealPathFromURI_API19(Context context, Uri uri)
    String filePath = "";
    String wholeID = DocumentsContract.getDocumentId(uri);

     // Split at colon, use second item in the array
     String id = wholeID.split(":")[1];

     String[] column =  MediaStore.Images.Media.DATA ;     

     // where id is equal to             
     String sel = MediaStore.Images.Media._ID + "=?";

     Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
                               column, sel, new String[] id , null);

     int columnIndex = cursor.getColumnIndex(column[0]);

     if (cursor.moveToFirst()) 
         filePath = cursor.getString(columnIndex);
        

     cursor.close();

     return filePath;



@SuppressLint("NewApi")
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) 
      String[] proj =  MediaStore.Images.Media.DATA ;
      String result = null;

      CursorLoader cursorLoader = new CursorLoader(
              context, 
        contentUri, proj, null, null, null);        
      Cursor cursor = cursorLoader.loadInBackground();

      if(cursor != null)
       int column_index = 
         cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
       cursor.moveToFirst();
       result = cursor.getString(column_index);
      

      return result;  


public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri)
           String[] proj =  MediaStore.Images.Media.DATA ;
           Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
           int column_index
      = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
           cursor.moveToFirst();
           return cursor.getString(column_index);


那么就可以在onActivityResult中获取Real路径了

String realPath;
        // SDK < API11
        if (Build.VERSION.SDK_INT < 11)
            realPath = RealPathUtil.getRealPathFromURI_BelowAPI11(this, data.getData());

        // SDK >= 11 && SDK < 19
        else if (Build.VERSION.SDK_INT < 19)
            realPath = RealPathUtil.getRealPathFromURI_API11to18(this, data.getData());

        // SDK > 19 (Android 4.4)
        else
            realPath = RealPathUtil.getRealPathFromURI_API19(this, data.getData());

盐:

content://com.android.providers.media.documents/document/image:36

/storage/emulated/0/Pictures/JPEG_20190812_163204_299063245992150918.jpg

希望这有帮助!

【讨论】:

是否可以在所有 SDK 版本上简单地使用“SDK 【参考方案3】:

改进@Ashton Coulson 的回答,你可以处理Kitkat 版本来使用这个参数:

String action;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
    action = Intent.ACTION_OPEN_DOCUMENT;
 else 
    action = Intent.ACTION_PICK;

Intent intent = new Intent(action, uri);

需要 if 是因为如 documentation 中所述,Android 4.4(API 级别 19)中引入了存储访问框架 (SAF)。

【讨论】:

【参考方案4】:

你应该获得一个持久化的 uri 权限:

        Uri uri = intent.getData();

        context.getContentResolver().takePersistableUriPermission(uri
                   , intent.getFlags() 
                          & ( Intent.FLAG_GRANT_READ_URI_PERMISSION 
                          + Intent.FLAG_GRANT_WRITE_URI_PERMISSION 
                          )
                        ); 

【讨论】:

现在我收到了No persistable permission grants found for UID 10389 and Uri 0 @ content://com.google.android.apps.photos.contentprovider/0/1/content://media/external/images/media/41287/ORIGINAL/NONE/1381709033【参考方案5】:

你可以添加这一行:

intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION);

【讨论】:

不起作用 - 同样的错误。

以上是关于权限被拒绝:打开未从 uid 导出的提供程序 com.google.android.apps.photos.contentprovider.MediaContentProvider的主要内容,如果未能解决你的问题,请参考以下文章

权限拒绝:无法附加文件,文件需要导出提供程序,或 grantUriPermission(),API 29

权限拒绝:打开提供程序 com.miui.gallery.provider.GalleryOpenProvider

java.lang.SecurityException:权限被拒绝:打开提供程序 com.quickblox.q_municate_core.db.DatabaseProvider

Laravel:file_put_contents() 无法打开流:会话文件夹的权限被拒绝

ls: 无法打开目录'.': 权限被拒绝

Git Bash 错误:无法分叉子进程:权限被拒绝(-1)