web-dev-qa-db-ja.com

Android-ファイルプロバイダー-許可の拒否

App1とapp2の2つのアプリがあります。

App2には次のものがあります。

<provider
        Android:name="Android.support.v4.content.FileProvider"
        Android:authorities="com.Android.provider.ImageSharing"
        Android:exported="false"
        Android:grantUriPermissions="true" >
        <meta-data
            Android:name="Android.support.FILE_PROVIDER_PATHS"
            Android:resource="@xml/paths" />
</provider>

paths.xml:

<paths>

     <files-path name="my_images" path="images/"/>

</paths>

App2は、そのアクティビティでApp1から画像のURIを取得する要求を受け取ります。 URIが決定されると、App2アクティビティは次のことを行います。

Intent intent = new Intent();

intent.setDataAndType(contentUri, getContentResolver().getType(contentUri));

int uid = Binder.getCallingUid();
String callingPackage = getPackageManager().getNameForUid(uid);

getApplicationContext().grantUriPermission(callingPackage, contentUri,
                    Intent.FLAG_GRANT_READ_URI_PERMISSION);

setResult(Activity.RESULT_OK, intent);
finish();

App2から結果を受信すると、App1は次のことを行います。

Uri imageUri = data.getData();
if(imageUri != null) {
    ImageView iv = (ImageView) layoutView.findViewById(R.id.imageReceived);
    iv.setImageURI(imageUri);
}

App1でApp2から戻ると、次の例外が発生します。

Java.lang.SecurityException:許可拒否:からエクスポートされないProcessRecord {52a99eb0 3493:com.Android.App1.app/u0a57}(pid = 3493、uid = 10057)からプロバイダーAndroid.support.v4.content.FileProviderを開くuid 10058

私は何を間違えていますか?

56
Jake

これを解決する唯一の方法は、次のように、それを必要とする可能性のあるすべてのパッケージに許可を与えることです。

List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
    String packageName = resolveInfo.activityInfo.packageName;
    context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
64
limlim

まず、grantUriPermission()から切り替えて、Intent自体に_FLAG_GRANT_READ_URI_PERMISSION_を置くだけです via addFlags() またはsetFlag()

何らかの理由で機能しない場合は、getCallingUid()ロジックをどこにでもある代わりにonCreate()に移動して、実際の「呼び出し元」を見つけられるかどうかを確認できます。 。

34
CommonsWare

Android <= Lollipop(API 22)

Lorenzo Quiroliによる すばらしい記事 があります。これは、古いAndroidバージョン。

彼は、次のように、IntentのClipDataを手動で設定し、アクセス許可を設定する必要があることを発見しました。

if ( Build.VERSION.SDK_INT <= Build.VERSION_CODES.Lollipop ) {
    takePictureIntent.setClipData( ClipData.newRawUri( "", photoURI ) );
    takePictureIntent.addFlags( Intent.FLAG_GRANT_WRITE_URI_PERMISSION|Intent.FLAG_GRANT_READ_URI_PERMISSION );
}

これをAPI 17でテストしたところ、うまく機能しました。機能するソリューションがどこにも見つかりませんでした。

31
Joshua Pinter

setData(contentUri);を追加し、要件に基づいてaddFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);またはaddFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);を追加します

これにより、Java.lang.SecurityException:Permission Denialが解決されます

確認済み。

これは https://developer.Android.com/reference/Android/support/v4/content/FileProvider.html#Permissions に従って行われます

22
RamiReddy

ファイルプロバイダーを使用してNougatでカメラを使用して画像をキャプチャする方法。

ファイルプロバイダーについて読むには、このリンクに従ってください ファイルプロバイダー

、キットカットとマシュマロは次の手順に従います。まず、MainfestFileのアプリケーションタグの下にある広告タグプロバイダー。

 <provider
        Android:name="Android.support.v4.content.FileProvider"
        Android:authorities="${applicationId}.provider"
        Android:exported="false"
        Android:grantUriPermissions="true">
        <meta-data
            Android:name="Android.support.FILE_PROVIDER_PATHS"
            Android:resource="@xml/provider_paths"/>
    </provider>

resフォルダーの下に(provider_paths.xml)でファイル名を作成します enter image description here

<paths xmlns:Android="http://schemas.Android.com/apk/res/Android">
<external-path name="external_files" path="."/>

キットKitKatバージョンに含まれるこの問題を解決しました

private void takePicture() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        Uri photoURI = null;
        try {
            File photoFile = createImageFileWith();
            path = photoFile.getAbsolutePath();
            photoURI = FileProvider.getUriForFile(MainActivity.this,
                    getString(R.string.file_provider_authority),
                    photoFile);

        } catch (IOException ex) {
            Log.e("TakePicture", ex.getMessage());
        }
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Lollipop) {
            takePictureIntent.setClipData(ClipData.newRawUri("", photoURI));
            takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION|Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        startActivityForResult(takePictureIntent, PHOTO_REQUEST_CODE);
    }
}

  private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_DCIM), "Camera");
    File image = File.createTempFile(
            imageFileName,  /* prefix */
            ".jpg",         /* suffix */
            storageDir      /* directory */
    );

    // Save a file: path for use with ACTION_VIEW intents
    mCurrentPhotoPath = "file:" + image.getAbsolutePath();
    return image;
}
12
Najaf Ali

そのようにして問題を解決しました:

        Intent sIntent = new Intent("com.appname.ACTION_RETURN_FILE").setData(uri);
        List<ResolveInfo> resInfoList = activity.getPackageManager().queryIntentActivities(sIntent, PackageManager.MATCH_DEFAULT_ONLY);
        for (ResolveInfo resolveInfo : resInfoList) {
            activity.grantUriPermission(FILE_PROVIDER_ID, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        sIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        activity.setResult(RESULT_OK, sIntent);
3
Rainmaker

このアドバイスをありがとう、@ CommonsWare。

私の問題は、呼び出し元のパッケージにありました。何らかの理由で、Binder.callingUid()およびgetPackageManager().getNameForUid(uid)App2 の代わりに App1

App2のonCreateonResumeで呼び出してみましたが、喜びはありませんでした。

私はそれを解決するために次を使用しました:

getApplicationContext().grantUriPermission(getCallingPackage(), 
          contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);

結局のところ、アクティビティにはこれ専用のAPIがあります。 here を参照してください。

2
Jake

特定のパッケージ名の許可を設定する必要があります。その後、それにアクセスできるようになります。

context.grantUriPermission("com.Android.App1.app", fileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
1
Jd Prajapati