前几天小米5也推送了基于android7.0的MIUI8.2.1版本。相信后面将会越来越多的手机升级到这个版本。做为android开发者,即将面对的也就是兼容android7.0系统。这不,说着兼容,问题就来了。项目中使用的bugly版本更新出现了bug,一直重复下载新版本。通过bugly的SDK说明,我们可以看到,需要配置FileProvider
显然,FileProvider是android7.0引入的新特性。
通过官网说明我们知道,FileProvider是contentProvider一个特殊子类,它的作用是加强访问一个应用文件的安全性。意思也就是不通过FileProvider获取uri,通过以前的file:///Uri访问就会报错了。
例如,访问相册的时候,以前的写法
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file = createImageFile();
Uri photoFile = Uri.fromFile(file);
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoFile);
这段代码在android7.0以下版本是没啥问题的,但是在android7.0运行会遇到FileUriExposedException异常。
显然就要按android7.0说明的方式配置FileProvider,然后再android7.0的系统通过FileProvider. getUriForFile()获取
首先是在manifest.xml配置provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/__picker_provider_paths"/> provider>
然后在res下面创建xml目录,同时在xml目录创建配置的__picker_provider_paths.xml文件
<paths>
<external-path name="external_storage_root" path="."/>
<files-path name="files" path="."/>
paths>
然后上面的Uri通过FileProvider获取
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String authority = mContext.getApplicationInfo().packageName + ".fileProvider";
photoFile = FileProvider.getUriForFile(this.mContext.getApplicationContext(), authority, file);
} else {
photoFile = Uri.fromFile(file);
}
上面是以PhotoPicker获取相册照片代码为例,但是如果我们再在app的manifest.xml按bugly官网配置的话,这要项目就会build报错,
原因是fileProvider对应一个应用是唯一的,所以我们可以通过以下配置解决
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="name,authorities,exported,grantUriPermissions">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"
tools:replace="name,resource"/>
provider>
然后把PhotoPicker的xml配置copy到app的provider_path.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="beta_external_path" path="Download/${applicationId}/.beta/apk"/>
<external-path name="beta_external_files_path" path="Android/data/${applicationId}/files/apk/"/>
<external-path name="external_storage_root" path="."/>
<files-path name="files" path="."/>
paths>
这样就解决了它两的冲突问题,通过tools:replace替换掉其他的provider配置。同时photoPicker的manifest不配置配置都无所谓了。但是photoPicker源码里面配置的是
android:authorities="${applicationId}.provider"
String authority = mContext.getApplicationInfo().packageName + ".provider";
这要就不得不改下源码了,把provider改成fileProvider了。
注意
加上混淆代码
#bugly
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
-keep class android.support.**{*;}
使用了资源混淆AndResGuard框架的还要在白名单里面加上
whiteList = ["R.string.strUpgradeDialog*"]
一定要加上这几句混淆代码和白名单,要不然还是一样循环下载