Blog
Blog copied to clipboard
FileProvider冲突
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不能冲突呀。
看起来是个小问题。知识系统不连贯的情况下,很难想清楚。