69

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>

パス.xml:

<paths>

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

</paths>

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

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: Permission Denial: open provider android.support.v4.content.FileProvider from ProcessRecord{52a99eb0 3493:com.android.App1.app/u0a57} (pid=3493, uid=10057) からエクスポートされていませんuid 10058

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

4

12 に答える 12

39

まず、 から切り替えて、またはを介し​​て をそれ自体grantUriPermission()に単純に配置しFLAG_GRANT_READ_URI_PERMISSIONます。IntentaddFlags()setFlag()

何らかの理由でそれが機能しない場合は、getCallingUid()ロジックをonCreate()どこにでも移動してみて、実際の「呼び出し元」を見つけることができるかどうかを確認してください。

于 2014-06-28T14:41:19.183 に答える
26

追加するだけ 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に従って行われます

于 2017-01-11T12:02:06.553 に答える
15

File Provider を使用して、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) という名前のファイルを作成します。 ここに画像の説明を入力

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

私はこの問題を解決しました

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;
}
于 2017-11-01T07:44:46.903 に答える
2

このアドバイスをくれた@CommonsWareに感謝します。

私の問題は、呼び出しパッケージにありました。何らかの理由で、Binder.callingUid()の代わりに のgetPackageManager().getNameForUid(uid)パッケージ名を付けていました。App2App1

onCreateと同様にApp2'sで呼び出してみましonResumeたが、喜びはありません。

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

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

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

于 2014-06-28T14:45:42.157 に答える
2

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

context.grantUriPermission("com.android.App1.app", fileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
于 2017-03-16T05:53:43.813 に答える
1

権限文字列がアプリごとに一意であることを確認してください。エラーの原因となった同じ権限文字列で別のアプリを複製しました

File file = new File("whatever");
URI uri = FileProvider.getUriForFile(context, "unique authority string", file);
于 2020-10-25T13:02:35.410 に答える