Android - 文件提供者 - 权限拒绝
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24467696/
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
Android - file provider - permission denial
提问by Jake
I have two apps : app1 and app2.
我有两个应用程序:app1 和 app2。
App2 has :
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 :
路径.xml:
<paths>
<files-path name="my_images" path="images/"/>
</paths>
App2 receives request in its Activity from App1 to get URI for an image. The App2 Activity does the following once URI is decided :
App2 在其 Activity 中从 App1 接收请求以获取图像的 URI。一旦确定了 URI,App2 Activity 将执行以下操作:
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();
On receiving the result back from App2, App1 does the following :
从 App2 接收到结果后,App1 执行以下操作:
Uri imageUri = data.getData();
if(imageUri != null) {
ImageView iv = (ImageView) layoutView.findViewById(R.id.imageReceived);
iv.setImageURI(imageUri);
}
In App1, on returning from App2, I get the following exception :
在 App1 中,从 App2 返回时,出现以下异常:
java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{52a99eb0 3493:com.android.App1.app/u0a57} (pid=3493, uid=10057) that is not exported from uid 10058
java.lang.SecurityException: Permission Denial: opens provider android.support.v4.content.FileProvider from ProcessRecord{52a99eb0 3493:com.android.App1.app/u0a57} (pid=3493, uid=10057) 不是从用户名 10058
What am I doing wrong ?
我究竟做错了什么 ?
回答by limlim
Turns out the only way to solve this is to grant permissions to all of the packages that might need it, like this:
事实证明,解决这个问题的唯一方法是向所有可能需要它的包授予权限,如下所示:
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);
}
回答by Joshua Pinter
Android <= Lollipop (API 22)
Android <= Lollipop (API 22)
There's a great articleby Lorenzo Quiroli that solves this issue for older Android versions.
Lorenzo Quiroli的一篇很棒的文章解决了旧 Android 版本的这个问题。
He discovered that you need to manually set the ClipData of the Intent and set the permissions for it, like so:
他发现需要手动设置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 );
}
I tested this on API 17 and it worked great. Couldn't find a solution anywhere that worked.
我在 API 17 上对此进行了测试,效果很好。无法在任何有效的地方找到解决方案。
回答by CommonsWare
First, I would try switching away from grantUriPermission()
and simply put the FLAG_GRANT_READ_URI_PERMISSION
on the Intent
itself via addFlags()
or setFlag()
.
首先,我会尝试从切换掉grantUriPermission()
,只是把FLAG_GRANT_READ_URI_PERMISSION
上Intent
本身通过addFlags()
或setFlag()
。
If for some reason that does not work, you could try moving your getCallingUid()
logic into onCreate()
instead of wherever you have it, and see if you can find out the actual "caller" there.
如果由于某种原因不起作用,您可以尝试将您的getCallingUid()
逻辑移入onCreate()
而不是您拥有它的任何地方,看看您是否可以在那里找到实际的“调用者”。
回答by RamiReddy
Just add
setData(contentUri);
and
based on requirement add
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
or
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
只需添加
setData(contentUri);
并根据需求添加
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
或
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
This solves the java.lang.SecurityException: Permission Denial
这解决了 java.lang.SecurityException: Permission Denial
Verified.
验证。
This is done as per https://developer.android.com/reference/android/support/v4/content/FileProvider.html#Permissions
这是按照 https://developer.android.com/reference/android/support/v4/content/FileProvider.html#Permissions 完成的
回答by Najaf Ali
How you can capture image using camera on Nougat using File Provider.
如何使用 File Provider 在 Nougat 上使用相机捕获图像。
To read about about file provider follow this link File Provider
要阅读有关文件提供程序的信息,请点击此链接 文件提供程序
,and kit kat and marshmallow follow these steps. First of all ad tag provider under application tag in MainfestFile.
,kit kat 和棉花糖按照以下步骤操作。首先是 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>
create a file name with (provider_paths.xml) under res folder
在 res 文件夹下创建一个带有 (provider_paths.xml) 的文件名
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
I have solved this issue it comes on kit kitkat version
我已经解决了这个问题,它来自 kit 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;
}
回答by Rainmaker
I solved the problem that way:
我是这样解决问题的:
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);
回答by Jd Prajapati
You need to set permission of specific package name, after that you can able to access it..
您需要设置特定包名称的权限,之后您才能访问它..
context.grantUriPermission("com.android.App1.app", fileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
回答by Jake
Thanks, @CommonsWare for this advice.
谢谢,@CommonsWare 的建议。
My problem was with the calling package. For some reason, Binder.callingUid()
and getPackageManager().getNameForUid(uid)
was giving me package name of App2
instead of App1
.
我的问题是调用包。出于某种原因,Binder.callingUid()
并getPackageManager().getNameForUid(uid)
准备给我包的名称App2
来代替App1
。
I tried calling it in App2's onCreate
as well as onResume
, but no joy.
我尝试在 App2onCreate
和 中调用它onResume
,但没有任何乐趣。
I used the following to solve it :
我使用以下方法来解决它:
getApplicationContext().grantUriPermission(getCallingPackage(),
contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
Turns out, activity has dedicated API for this. See here.
事实证明,活动为此具有专用的 API。见这里。