我有两个应用:app1和app2。
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的Activity中接收请求以获取图像的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:Permission Denial:opening 提供者android.support.v4.content.FileProvider来自 ProcessRecord {52a99eb0 3493:com.android.App1.app/u0a57} (pid = 3493,uid = 10057)未从uid 10058导出
我做错了什么?
答案 0 :(得分:63)
原来解决此问题的唯一方法是为可能需要它的所有软件包授予权限,如下所示:
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);
}
答案 1 :(得分:34)
首先,我会尝试切换grantUriPermission()
并简单地将FLAG_GRANT_READ_URI_PERMISSION
放在Intent
本身via addFlags()
或setFlag()
上。
如果出于某种原因无效,您可以尝试将getCallingUid()
逻辑移至onCreate()
而不是任何地方,并查看是否可以找到实际的&#34;来电和#34;那里。
答案 2 :(得分:30)
Lorenzo Quiroli有一个great article解决了旧版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上对此进行了测试,效果很好。无法在任何有效的地方找到解决方案。
答案 3 :(得分:22)
添加
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
答案 4 :(得分:13)
要阅读有关文件提供程序的信息,请点击此链接 File Provider
,kit kat和marshmallow遵循这些步骤。 首先是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="."/>
我已经解决了这个问题,它来自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;
}
答案 5 :(得分:2)
感谢@CommonsWare提供此建议。
我的问题在于调用包。由于某些原因,Binder.callingUid()
和getPackageManager().getNameForUid(uid)
给了我App2
的包名而不是App1
。
我尝试在App2的onCreate
以及onResume
中调用它,但没有快乐。
我使用以下方法解决它:
getApplicationContext().grantUriPermission(getCallingPackage(),
contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
事实证明,活动有专门的API。请参阅here。
答案 6 :(得分:2)
我解决了这个问题:
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);
答案 7 :(得分:1)
您需要设置特定包名的权限,之后您才能访问它..
context.grantUriPermission("com.android.App1.app", fileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
答案 8 :(得分:0)
在我的情况下,我要与文本共享图片,解决方案是添加两个标志,读取FLAG_GRANT_READ_URI_PERMISSION
并写入FLAG_GRANT_WRITE_URI_PERMISSION
,如下所示:
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setType("image/png");
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, getString(R.string.txtShareAppTitle));
intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.txtShareApp) ;
startActivity(intent);
答案 9 :(得分:0)
我就是这样
try{
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
takePictureIntent.resolveActivity(packageManager)?.also {
val photoFile: File? = try {
createImageFile()
} catch (ex: IOException) {
null
}
photoFile?.also {
val photoURI: Uri = FileProvider.getUriForFile(
this,
"$packageName.fileprovider",
it
)
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
val permissionTemp = Intent.FLAG_GRANT_READ_URI_PERMISSION and Intent.FLAG_GRANT_WRITE_URI_PERMISSION
grantUriPermission(packageName, Uri.fromFile(photoFile), permissionTemp)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile))
}else{
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
}
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
}
}
}
}
catch (ex: IOException){
Log.d("IOException", "${ex.printStackTrace()}")
}
file_provider_paths.xml
<paths>
<external-files-path name="my_images" path="/" />
<external-path name="my_images" path="/"/>
<external-path name="external" path="." />
<external-files-path name="external_files" path="." />
<files-path name="files" path="." />
</paths>
,然后按照文档进行操作 Take photos
答案 10 :(得分:0)
确保授权字符串对于每个应用程序都是唯一的。 我用相同的授权字符串克隆了另一个导致错误的应用程序
File file = new File("whatever");
URI uri = FileProvider.getUriForFile(context, "unique authority string", file);