Maison > Questions et réponses > le corps du texte
java.lang.SecurityException: Permission Denial: writing android.support.v4.content.FileProvider uri content://com.tianshaokai.demo.fileprovider/camera_photos/temp/1480414713257.jpg from pid=23075, uid=10041 requires the provider be exported, or grantUriPermission()
public void cropPhoto(File file) {
cropfile = new File(Environment.getExternalStorageDirectory(), "/temp/" + System.currentTimeMillis() + ".jpg");
if (!cropfile.getParentFile().exists()) cropfile.getParentFile().mkdirs();
Uri outputUri = FileProvider.getUriForFile(this, getProvider(), cropfile);
Uri imageUri = FileProvider.getUriForFile(this, getProvider(), file);//通过FileProvider创建一个content类型的Uri
Intent intent = new Intent("com.android.camera.action.CROP");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 400);
// intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
// intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent, 1002);
}
file = new File(Environment.getExternalStorageDirectory(), "/temp/" + System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
Uri imageUri = FileProvider.getUriForFile(this, getProvider(), file);//通过FileProvider创建一个content类型的Uri
Log.d(TAG, "imageUri: " + imageUri);
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
startActivityForResult(intent, 1001);
现在就是拍照完成后,裁剪 就报最上边的 权限错误,测试机是 7.0 的模拟器
看到大家的回答我补充一下啊,我已经添加了6.0 的 SD卡和摄像头 动态权限,我现在的问题是裁剪完 保存时 报上边的错误。
怪我咯2017-04-17 17:59:50
Pour intercepter la sortieUri de la photo, vous ne pouvez utiliser que Uri.fromFile, pas FileProvider.getUriForFile
怪我咯2017-04-17 17:59:50
Oui, les autorisations sont erronées. Après la version 6.0, les autorisations doivent être obtenues dynamiquement.
黄舟2017-04-17 17:59:50
Il n'y aura plus d'invite maintenant. Vous devez lancer activement la demande d'autorisation. Généralement, pour prendre des photos, il existe deux autorisations pour la carte SD et l'appareil photo. Les connaissances liées au modèle d'autorisation 6.0 peuvent être interrogées en ligne. http://www.tuicool.com/articl... Je l'ai trouvé en ligne et vous pouvez voir si cela peut être résolu,
巴扎黑2017-04-17 17:59:50
Mes pensées et pratiques actuelles :
1. Utilisez FileProvider pour être compatible avec Android N et supérieur
2. Utilisez un fichier pour enregistrer les photos prises et recadrées
Étapes :
1. Déclarez FileProvider dans AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="包名.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
2. Créez le répertoire xml sous res et créez filepaths.xml avec le contenu suivant :
<paths>
<external-path
name="my_images"
path="Android/data/包名/files/header/" />
</paths>
Remarque : L'avantage de sauvegarder avec ce chemin est que le fichier sera supprimé lors de la désinstallation de l'application file/header/ est un chemin personnalisé
.3. Le point d'appel doit gérer les autorisations de stockage externe (le système étant utilisé pour prendre des photos, il n'est pas nécessaire de fournir les autorisations de la caméra)
int permission = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_HEAD);
} else {
//调用拍照或者从相册选取
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_HEAD:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//调用拍照或者从相册选取
} else {
//提示:"要使用该功能,必须允许或者在应用访问授权中打开存储空间权限"
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
4. Traitement de l'URI, le chemin a été déclaré dans filepath.xml, vous devez définir un nom de fichier pour enregistrer l'image (save.jpg)
private Uri getUri() {
File path = new File(Environment.getExternalStorageDirectory(), "Android/data/包名/files/header");
if (!path.exists()) {
path.mkdirs();
}
File file = new File(path, "save.jpg");
//由于一些Android 7.0以下版本的手机在剪裁保存到URI会有问题,所以根据版本处理下兼容性
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return FileProvider.getUriForFile(context, "com.maidouvr.fileprovider", file);
} else {
return Uri.fromFile(file);
}
}
5. Traitement des photos
Uri uri = getUri();
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
//将存储图片的uri读写权限授权给相机应用
List<ResolveInfo> resInfoList = getActivity().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
getActivity().grantUriPermission(packageName, uri , Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
startActivityForResult(Intent.createChooser(intent, "选择拍照工具"), 1001);
6. Traitement de coupe
Uri uri = getUri();
Intent intent = new Intent("com.android.camera.action.CROP");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setDataAndType(uri , "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 500);
intent.putExtra("outputY", 500);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getUri());
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true);
//将存储图片的uri读写权限授权给剪裁工具应用
List<ResolveInfo> resInfoList = getActivity().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
getActivity().grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
startActivityForResult(Intent.createChooser(intent, "选择剪裁工具"), 1002);
Une dernière chose à ajouter : certains téléphones mobiles peuvent avoir le resultCode toujours RESULT_CANCEL après le découpage, il est donc recommandé de définir le launchMode de l'activité en utilisant cette fonction sur singleTask
天蓬老师2017-04-17 17:59:50
Exception de sécurité, l'autorisation de l'utilisateur est requise pour la version 6.0 et supérieure.