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

    }
清单文件添加
<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.cyz.android7.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
添加xml文件file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
   <!-- 代表的目录为:Environment.getExternalStorageDirectory()/zz-->
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="external"
        path="/zz/" />
</paths><!--
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <root-path name="root" path="" />
    <files-path name="files" path="" />
    <cache-path name="cache" path="" />
    <external-path name="external" path="" />
    <external-files-path name="name" path="path" />
     <external-cache-path name="name" path="path" />
</paths>


    <root-path/> 代表设备的根目录new File("/");
        <files-path/> 代表context.getFilesDir()
        <cache-path/> 代表context.getCacheDir()
        <external-path/> 代表Environment.getExternalStorageDirectory()
        <external-files-path>代表context.getExternalFilesDirs()
        <external-cache-path>代表getExternalCacheDirs()
    -->
这样得到的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();
                }
            }
        }
    }
代码 点击打开链接






  



猜你喜欢

转载自blog.csdn.net/u013359807/article/details/80611470