关于Bugly版本兼容Android7.0 FileProvider与PhotoPicker冲突问题

前几天小米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">
    <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-->
    <external-path name="beta_external_path" path="Download/${applicationId}/.beta/apk"/>
    <!--/storage/emulated/0/Android/data/${applicationId}/files/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*"]

一定要加上这几句混淆代码和白名单,要不然还是一样循环下载

猜你喜欢

转载自blog.csdn.net/iamzgx/article/details/61628305