Android 7.0 应用间共享文件FileProvider代码笔记

学习http://blog.csdn.net/lmj623565791/article/details/72859156

Android7.0之前的拍照常规实现代码

public void takePhoto() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {

            String filename = new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.CHINA)
                    .format(new Date()) + ".png";
        
            File file = new File(Environment.getExternalStorageDirectory() + "/zz/", filename);
            mCurrentPhotoPath = file.getAbsolutePath();

            Uri fileUri = Uri.fromFile(file);
            
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
            startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PHOTO);
            
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_TAKE_PHOTO) {
            image.setImageBitmap(BitmapFactory.decodeFile(mCurrentPhotoPath));
        }

    }
Uri.fromFile(file)//为file:///storage/emulated/0/zz/20180607-163315.png
此代码在android7.0一下的系统运行正常,但是运行在android7.0上就会崩溃
原因是android7.0禁止应用对外公开;如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,
并出现 FileUriExposedException 异常。
google给出的解决方案是:要在应用间共享文件,您应发送一项 content:// URI,并授予 URI 临时访问权限。
进行此授权的最简单方式是使用 FileProvider 类。 
于是代码改为:

 public void takePhoto() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {

            String filename = new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.CHINA)
                    .format(new Date()) + ".png";
            //对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode API 政策禁止在您的应用外部公开 file:// URI。
            // 如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,并出现 FileUriExposedException 异常。

            //官方解决方案:要在应用间共享文件,您应发送一项 content:// URI,并授予 URI 临时访问权限。
            // 进行此授权的最简单方式是使用 FileProvider 类。如需了解有关权限和共享文件的详细信息,请参阅共享文件。
            File file = new File(Environment.getExternalStorageDirectory() + "/zz/", filename);
            mCurrentPhotoPath = file.getAbsolutePath();


            Uri fileUri = null;
            if (Build.VERSION.SDK_INT > 23) {
                /**Android 7.0以上的方式**/
                fileUri = FileProvider.getUriForFile(this, "com.cyz.android7.fileprovider", file);
            } else {
                fileUri = Uri.fromFile(file);
            }
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
            startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PHOTO);
            System.out.println(fileUri+"   "+Uri.fromFile(file));
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_TAKE_PHOTO) {
            image.setImageBitmap(BitmapFactory.decodeFile(mCurrentPhotoPath));
        }

    }
清单文件添加

            
        
添加xml文件file_paths.xml

   

    

这样得到的fileUrl为
content://com.cyz.android7.fileprovider/external/20180607-163315.png
对比之前的
file:///storage/emulated/0/zz/20180607-163315.png
对比发现android7.0为了文件安全将提供给别的app的路径进行了隐藏。

权限申请代码:
/**
     * 申请权限
     */
    public void requestPower() {
        //判断是否已经赋予权限
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            //如果应用之前请求过此权限但用户拒绝了请求,此方法将返回 true。
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                //这里可以写个对话框之类的项向用户解释为什么要申请权限,并在对话框的确认键后续再次申请权限
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_REQUEST_PERMISSION);
            } else {
                //申请权限,字符串数组内是一个或多个要申请的权限,REQUEST_CODE_REQUEST_PERMISSION是申请权限结果的返回参数,
                // 在onRequestPermissionsResult可以得知申请结果
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,}, REQUEST_CODE_REQUEST_PERMISSION);
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == REQUEST_CODE_REQUEST_PERMISSION) {
            for (int i = 0; i < permissions.length; i++) {
                if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "" + "权限" + permissions[i] + "申请成功", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(this, "" + "权限" + permissions[i] + "申请失败", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
代码 点击打开链接






  



你可能感兴趣的:(Android,FileProvider)