Android个版本适配之7.0

相关文章:

Android各版本适配之6.0

Android各版本适配之8.0

在Android 7.0 的适配中,遇到了些问题,主要是新特性上的一些变化,须要针对性的做适配。

附Android7.0新特性:Android7.0新特性


私有文件的文件权限不再放权给全部的应用,使用 MODE_WORLD_READABLE 或 MODE_WORLD_WRITEABLE 进行的操作将触发 SecurityException。
应对策略:这项权限的变更将意味着你无法通过File API访问手机存储上的数据了。基于File API的一些文件浏览器等也将受到非常大的影响,看到这大家是不是惊呆了呢,只是迄今为止,这样的限制尚不能全然运行。
应用仍可能使用原生 API 或 File API 来改动它们的私有文件夹权限。 可是,Android官方强烈反对放宽私有文件夹的权限。
能够看出收起对私有文件的访问权限是Android将来发展的趋势。


在Android7.0系统上Android 框架强制运行了 StrictMode API 政策禁止向你的应用外公开 file:// URI。
假设一项包含文件 file:// URI类型 的 Intent 离开你的应用(给其它应用传递 file:// URI 类型的Uri),应用失败,并出现 FileUriExposedException 异常,如调用系统相机拍照

应对策略:若要在应用间共享文件。能够发送 content:// URI类型的Uri,并授予 URI 暂时访问权限。 进行此授权的最简单方式是使用 FileProvider类。


DownloadManager 不再按文件名称分享私人存储的文件。
COLUMN_LOCAL_FILENAME在Android7.0中被标记为deprecated, 旧版应用在访问 COLUMN_LOCAL_FILENAME时可能出现无法访问的路径。
面向 Android N 或更高版本号的应用在尝试访问COLUMN_LOCAL_FILENAME 时会触发 SecurityException。

应对策略:大家能够通过ContentResolver.openFileDescriptor()来訪问由 DownloadManager 公开的文件。


实例讲解


在Android7.0之前,假设你想调用系统相机拍照能够通过下面代码来进行:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri imageUri = Uri.fromFile(file);
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
startActivityForResult(intent,1006);

在Android7.0上使用上述方式调用系统相拍照会抛出例如以下异常:

android.os.FileUriExposedException: file:storage/emulated/0/temp/1474956193735.jpg
exposed beyond app through Intent.getData()


解决方案

使用FileProvider 
使用FileProvider的大致过程例如以下:

第一步:在manifest清单文件里注冊provider

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="app包名.fileprovider"
    android:grantUriPermissions="true"
    android:exported="false">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

心得:exported:要求必须为false,为true则会报安全异常。grantUriPermissions:true,表示授予 URI 暂时訪问权限。

第二步:指定共享的文件夹

为了指定共享的文件夹我们须要在资源(res)文件夹下创建一个xml文件夹,然后创建一个名为“file_paths”(名字能够随便起,仅仅要和在manifest注冊的provider所引用的resource保持一致就可以)的资源文件。内容例如以下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <paths>
    <external-path path="." name="files_root"/>
  </paths>
</resources>

代表的根文件夹: Context.getFilesDir() 
代表的根文件夹: Environment.getExternalStorageDirectory() 
代表的根文件夹: getCacheDir()

心得:上述代码中path=”.“,是有特殊意义的,它代码根文件夹。也就是说你能够向其它的应用共享根文件夹及其子文件夹下不论什么一个文件了,假设你将path设为path=”pictures”, 
那么它代表着根文件夹下的pictures文件夹(eg:/storage/emulated/0/pictures),假设你向其它应用分享pictures文件夹范围之外的文件是不行的

第三步:使用FileProvider 
上述准备工作做完之后,如今我们就能够使用FileProvider了。


还是以调用系统相机拍照为例,我们须要将上述拍照代码改动为例如以下:

File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri imageUri = FileProvider.getUriForFile(context, "包名.fileprovider", file);//通过FileProvider创建一个content类型的Uri
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,1006);

上述代码中主要有两处改变:

1、将之前Uri的scheme类型为file的Uri改成了有FileProvider创建一个content类型的Uri。 
2、加入了intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);来对目标应用暂时授权该Uri所代表的文件。

心得:上述代码通过FileProvider的Uri getUriForFile (Context context, String authority, File file) 
静态方法来获取Uri,该方法中authority參数就是清单文件里注冊provider的android:authorities=”app包名.fileprovider”。

对Webserver如tomcat。IIS比较熟悉的小伙伴,都仅仅知道为了站点内容的安全和高效,Webserver都支持为站点内容设置一个虚拟文件夹,事实上FileProvider也有异曲同工之处。

将getUriForFile方法获取的Uri打印出来例如以下:

content://app包名/files_root/1474960080319.jpg。

当中app包名/files_root/就是file_paths.xml中paths的name。

由于上述指定的path为path=”.“,所以content://app包名/files_root/代表的真实路径就是根文件夹,即:/storage/emulated/0/。 
content://app包名/files_root/temp/1474960080319.jpg代表的真实路径是:/storage/emulated/0/temp/1474960080319.jpg。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值