Android 从 N 开始不允许以 file:// 的方式通过 Intent 在两个 App 之间分享文件,取而代之的是通过 FileProvider 生成 content://Uri!
- 新建映射xml文件
- 注册Provider
- 生成URI
新建映射xml文件
1.首先在res下新建xml目录
2.新建映射文件 provider.xml
<resources>
<paths>
<files-path
name="fp"
path="Files/" />
<external-path
name="ep"
path="Images/" />
<cache-path
name="cp"
path="Caches/" />
<external-files-path
name="efp"
path="epfs/" />
<external-cache-path
name="ecp"
path="ecps/" />
</paths>
</resources>
以上:
files-path代表的是Context.getFilesDir()
所以这里代表的路径是Context.getFilesDir()/Files,表示这里面的所有文件、文件夹都可以被临时访问。(其他理解方式同理)external-path 代表的是 Environment.getExternalStorageDirectory()
cache-path
getCacheDir()external-files-path
Context#getExternalFilesDir(String)
or
Context.getExternalFilesDir(null)external-cache-path
Context.getExternalCacheDir()
name属性等会说
注册Provider
<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/provider" />
</provider>
</application>
其中
android:name="android.support.v4.content.FileProvider"
直接写固定值就行,这个自定义才写你相应的类名,FileProvider我们就直接用官方的,所有一般都是固定"android.support.v4.content.FileProvider".
android:exported="false"
android:grantUriPermissions="true"
这两行只能这么写,因为FileProvider源码:
@Override
public void attachInfo(Context context, ProviderInfo info) {
super.attachInfo(context, info);
// Sanity check our security
if (info.exported) {
throw new SecurityException("Provider must not be exported");
}
if (!info.grantUriPermissions) {
throw new SecurityException("Provider must grant uri permissions");
}
mStrategy = getPathStrategy(context, info.authority);
}
不然会SecurityException咯!
android:authorities="${applicationId}.provider"
这里我的applicationId是com.example.chan
生成URI
val path = "/storage/emulated/0/Images/default.jpg"
val provider = FileProvider.getUriForFile(this, "com.example.chan.provider", File(path))
kotlin写的,跟java都是运行在jvm上,所有无所谓了,一行代码就算是小白也能看得懂(虽然我就是小白)。
Log.i("tag","provider:$provider")
得出的结果是:
content://com.example.chan.provider/ep/default.jpg
可以看到我们最后的路径是content://{authorities}/映射文件的name/文件名
对的,一开始的provider.xml 里面的name就是拿来这里映射真实路径的。