alwaystest / Blog

24 stars 2 forks source link

FileProvider冲突 #80

Open alwaystest opened 6 years ago

alwaystest commented 6 years ago

FileProvider冲突

标签(空格分隔): Android


Android N以上为了提高文件共享的安全性,引入了FileProvider,基于ContentProvider来实现。

在集成某个SDK的时候,发现里面针对FileProvider的写法是这样的:

<application>
    ...
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths"/>
    </provider>
    ...
</application>

问题就在于provider的name是直接使用了Support V4包下的对应的实现类。 当另一个Lib也有同样的实现方式的时候,在MergeAndroidManifest的过程中就会提示冲突。

一种解决办法是使用tools:replace之类的声明去做替换,除非Dev明确知道自己在做什么,否则很容易因为缺少对应的path声明而导致出错。 使用tools:replace声明的原理在这里有说 https://developer.android.com/studio/build/manifest-merge 原理就是告诉MergeTool遇到冲突的时候选择哪一个。

另一种办法,看到有的文章说新建一个FileProvider,继承自android.support.v4.content.FileProvider就好了,里面什么都不需要做就好。然后在Manifest里面把name指定给新建的FileProvider。看完之后其实挺懵的,为什么新建一个就能解决冲突,什么冲突都能解决吗?

其实解决的原理是这样的,两个provider的声明中,name都是android.support.v4.content.FileProvider,就相当于在一个AndroidManifest中声明了两次同一个Activity。因为FileProvider实际上是ContentProvider,也是四大组件之一嘛,同一个组件声明两次,两次声明中要是一模一样倒还好说,直接Merge就好了,不会出错,但是一旦两个声明中某个属性不同,那MergeTool就不知道怎么选了,那就报错,我处理不了,你行你上。 换个名字,实际上是声明了两个不同的组件,不存在Merge的问题。

但是对于ContendProvider,声明了两个authorities相同的provider,能行吗?不行。 可能有人遇到过安装两个App的时候,因为Provider的authorities相同而导致第二个应用不能安装的。原因就是一旦允许安装,那就没有办法根据uri找出来到底应该从哪个Provider中获取数据了。 fileProvider生成的uri的格式是这样的

content://{authorities}/xxxxx

如果两个FileProvider的authorities声明成一样的,就没有办法区分应该找哪个FileProvider去获取文件了。

两个App的时候是这样。一个App中声明了两个一样的authorities的provider呢?

在Pixel 2XL,Android Studio 3.2上测试。应用可以正常编译,安装,但是到了使用的过程中,就会出现问题。

当两个FileProvider声明的resource不同的时候,系统通过URI找到的FileProvider如果刚好是声明了对应resource的Provider还好,一旦到的是另一个,在生成URI的过程中就会发现FileProvider的resource声明中就没有这个路径(声明在另一个正确匹配的FileProvider中声明啦),这是一个非法分享,Crash。

系统怎么找对应的FileProvider呢?我大胆的猜,按照AndroidManifest里声明的顺序,从上往下,哪个authorities先匹配,就用哪个。

所以即使在同一个应用中,也要保证authorities不能冲突呀。

看起来是个小问题。知识系统不连贯的情况下,很难想清楚。