android - 7.0系统拍照后,使用系统截图功能,截图保存时崩溃如何解决
ringa_lee
ringa_lee 2017-04-17 17:57:50
0
5
1030
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卡和摄像头 动态权限,我现在的问题是裁剪完 保存时 报上边的错误。

ringa_lee
ringa_lee

ringa_lee

reply all(5)
刘奇

To intercept the output Uri of the photo, you can only use Uri.fromFile, not FileProvider.getUriForFile

刘奇

Yes, the permissions are wrong. After 6.0, permissions need to be obtained dynamically.

黄舟

There will be no prompt now, and you need to actively initiate permission application. Generally, for taking pictures, there are two permissions for SD card and camera. Knowledge related to the 6.0 permission model can be queried online. http://www.tuicool.com/articl... I found it online and see if it can be solved,

巴扎黑

My current thoughts and practices:

1. Use FileProvider to be compatible with Android N and above

2. Use a file to save the taken and cropped pictures

Steps:

1. Declare FileProvider in 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. Create the xml directory under res and create filepaths.xml with the following content:

<paths>
    <external-path
        name="my_images"
        path="Android/data/包名/files/header/" />
</paths>

Note: The advantage of saving with this path is that the file will be deleted when the application is uninstalled. file/header/ is a custom path

3. The calling point needs to handle external storage permissions (because the system is used to take pictures, there is no need to provide camera permissions)

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. URI processing, the path has been declared in filepath.xml, you need to define a file name to save the 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. Photo processing

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. Cutting processing

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);

Finally, one more thing: some mobile phones may have the resultCode after trimming always be RESULT_CANCEL, so it is recommended to set the launchMode of the Activity using this function to singleTask

Peter_Zhu

Security exception, user authorization is required for version 6.0 and above.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template