安卓适配--FileProvider

官方文档说:
对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode API 政策禁止在您的应用外部公开 file:// URI。如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,并出现 FileUriExposedException 异常。

要在应用间共享文件,您应发送一项 content:// URI,并授予 URI 临时访问权限。进行此授权的最简单方式是使用 FileProvider 类。

在所有情况下,要将应用中的文件提供给其他应用,唯一安全的做法就是向接收方应用发送文件的内容 URI,并授予对该 URI 的临时访问权限。具有临时 URI 访问权限的内容 URI 之所以安全,是因为它们仅供接收该 URI 的应用使用,并且会自动过期。Android FileProvider 组件提供了 getUriForFile() 方法,用于生成文件的内容 URI。

使用FileProvider

1、在清单中声明provider标签,如下:
由于FileProvider的默认功能包括文件的内容URI生成,因此不需要在代码中定义子类。相反,您可以在应用程序中包含一个文件提供程序,方法是完全用XML指定它。要指定FileProvider组件本身,请在应用程序清单中添加< provider>元素。
将android:name属性设置为androidx.core.content.FileProvider。
将android:authorities属性设置为基于您控制的域的URI权限;例如,如果您控制域mydomain.com,则应使用authority com.mydomain.fileprovider。
将android:exported属性设置为false;文件提供程序不需要是公共的。
将android:grantUriPermissions属性设置为true,以允许您授予对文件的临时访问权限

        <provider
            android:authorities="com.example.broadcast_force_offline.fileprovider"
            android:name="androidx.core.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>
//android:authorities表示授权者,这里的格式一般是[appId].fileprovider
//android:exported只能为false,文件提供程序不需要是公共的
//android:grantUriPermissions="true"表示授权Uri权限 ,且必须为true

meta-data里设置指定的文件目录,为引用某个xml文件,格式如下:

< meta-data >
直译为“元数据”,该标签可为< activity>、< activity-alias>、< application>、< provider>、< receiver>、< service>等组件提供附加数据项。
组件元素可以包含任意数量的< meta-data >子元素。系统将meta-data配置的数据存储于一个Bundle对象中,可以通过PackageItemInfo.metaData字段获取。
语法配置:
1、android:name 分配给该标签的键,即唯一名称。
2、android:resource 对资源的引用,如“@string/app_name”。该资源ID可以通过该metaData.getInt()方法获取 。
3、android:value 分配给该标签的值,如String、Boolean等。

例如:file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
    name="my_images"
    path=""/>
    <!--path属性的值表示共享的的具体路径,为空代表将整个SD卡共享-->
</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()

参考代码案例:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <!--存储卡的Pictures目录放图片文件-->
    <external-path
        name="my_images"
        path="Pictures"/>
    <!--存储卡的flyaudiosmart2019/apk目录放安装包文件-->  
    <external-path
        name="my_download"
        path="flyaudiosmart2019/apk"/>
</paths>

2、使用FileProvider API
调用系统拍照,构造Intent就需要传入一个Uri,那么Uri就必须使用FileProvider来获取:

       	Uri imageUri;
       	
        protected void onCreate(Bundle savedInstanceState){
       
       								......
       
        takePhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //创建File对象,用于存储拍照后的照片,将图片命名为output_image.jpg,并将它存放在当前应用缓存数据的位置,4.4系统以前访问SD卡关联目录需要声明访问SD卡权限
                File outputImage=new File(getExternalCacheDir(),"output_image.jpg");
                try {
                    if (outputImage.exists()){
                        outputImage.delete();
                    }
                    outputImage.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (Build.VERSION.SDK_INT>=24)
                {
                //生成Uri
                    imageUri= FileProvider.getUriForFile(CameraAlbumActivity.this,"com.example.broadcast_force_offline.fileprovider",outputImage);
                }
                else
                {
                    imageUri=Uri.fromFile(outputImage);
                }
                //启动相机程序
                Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");
                intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
                //调用putExtra()方法指定图片的输出地址
                startActivityForResult(intent,1);
            }
        });
        
        							......
        
        }
     @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode)
        {
            case 1:
                if(resultCode==RESULT_OK)
                {
                    try {
                        //将照片显示出来
                        Bitmap bitmap= BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                        picture.setImageBitmap(bitmap);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }

                }
                break;
                default:
                    break;
        }
    }

这里在ImageView里直接显示Bitmap。如果需要上传图片到服务器,需要把图片保存为临时文件。创建文件需要声明对外部存储的写权限

参考资料:
Android适配总结之FileProvider
第一行代码(第二版)
浅谈Android中的meta-data及其应用
官方文档:FileProvider

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值