web-dev-qa-db-ja.com

権限が拒否されました:uidからエクスポートされていないプロバイダーcom.google.Android.apps.photos.contentprovider.MediaContentProviderを開いています

以前に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://stackoverflow.com/a/20559418/3758972 の関数です。

スタックトレース :

Java.lang.RuntimeException: Unable to start activity ComponentInfo{com.badiyajobs.app/com.badiyajobs.app.screens.ProfileActivity}: Java.lang.SecurityException: Permission Denial: opening provider com.google.Android.apps.photos.contentprovider.MediaContentProvider from ProcessRecord{25e87b7 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 ProcessRecord{25e87b7 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) 

何が欠けているのかわかりません。助けてください。

11
Nitesh Verma

ACTION_PICKではなくACTION_OPEN_DOCUMENTをインテントで使用します。それはあなたが要求するファイルへの長期的な、永続的なアクセスを可能にします。

Intent galleryIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);

ここにドキュメント: https://developer.Android.com/guide/topics/providers/document-provider.html

10
Ashton Coulson

@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);

ドキュメント に記載されているように、ストレージアクセスフレームワーク(SAF)はAndroid 4.4(APIレベル19)で導入されたため、ifが必要です。

2
androidevil

この行を追加できます:

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

1
Seda T.

以下のようなクラス名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で実際のパスを取得できます

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

これがお役に立てば幸いです!!

1
Damith Thiwanka

永続的なuri権限を取得する必要があります。

        Uri uri = intent.getData();

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