应用安装(FileProvider)
应用内安装apk时涉及到通过Intent在两个应用间共享资源,Android 从 N 开始不允许以 file:// 的方式通过 Intent 在两个 App 之间分享文件,取而代之的是通过 FileProvider 生成 content://Uri,否则直接使用会抛出异常导致奔溃所以首先我们来了解一下FileProvider相关的知识。
首先给出FileProvider的官方介绍https://developer.android.google.cn/reference/androidx/core/content/FileProvider
FileProvider 是一个特殊的 ContentProvider 子类,通过 content://Uri 代替 file://Uri 实现不同 App 间的文件安全共享。当通过包含 Content URI 的 Intent 共享文件时,需要申请临时的读写权限,可以通过 Intent.setFlags() 方法实现。而 file://Uri 方式需要申请长期有效的文件读写权限,直到这个权限被手动改变为止,这是极其不安全的做法。因此 Android 从 N 版本开始禁止通过 file://Uri 在不同 App 之间共享文件。
FileProvider的使用步骤:
1,定义一个FileProvider
2,指定可用的文件
3,生成文件的Content URI
4,给此URI授予临时权限
5,将此Content URI通过Intent传递给另一个App
接下来详细介绍
1,定义FileProvider
<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/provider_paths" />
</provider>
android:authorities:applicationId+fileProvider
applicationId:这里写成动态获取应用包名,如果写死在项目包含多个moudle时出现不一致的情况
android:exported="false":表示此provider是私有的不对其他应用公开
android:grantUriPermissions="true":表示授予临时权限
provider_paths:指定用来配置文件目录的xml文件,此处指定为provider_paths,名称可以自定义
2,指定可用的文件provider_paths.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!--相当于Context.getFilesDir()-->
<files-path name="name" path="path" />
<!--相当于Context. getCacheDir()-->
<cache-path name="name" path="path" />
<!--相当于Environment.getExternalStorageDirectory()-->
<external-path name="name" path="path" />
<!--相当于Context.getExternalFilesDir(String) Context.getExternalFilesDir(null).-->
<external-files-path name="name" path="path" />
<!--相当于Context.getExternalCacheDir()-->
<external-cache-path name="name" path="path" />
<!--相当于Context.getExternalMediaDirs()-->
<external-media-path name="name" path="path" />
...
</paths>
注意:这里只需配置自己文件所保存的path即可,name为别名影藏实际名称,path为实际的文件路径如果对Android文件存储这块知识不太了解可以看一下另一篇介绍:http://08643.cn/p/88dbdd8613db
3,生成文件的Content URI
完成了前两步的配置,接下来通过官方提供的getUriForFile(File file) 方法生成能够被其他应用访问的Content URI加入有一个apk文件路径为磁盘根目录则相应文件对象为
File file = new File("/sdcard/app.apk");
此文件对应的可通过如下方式获得uri
Uri uri=FileProvider.getUriForFile(FaceTempratureActivity.this, BuildConfig.APPLICATION_ID + ".provider", file);
获取到Uri后我们将通过Intent将此Uri传递给另一个应用,此处定义一个Intent
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(uri,"application/vnd.android.package-archive");
4,给此URI授予临时权限
有了可访问的Uri路径我们还得申请临时读写文件权限,这里可以直接通过Intent.setFlags()方法设置
intent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5,将此Content URI通过Intent传递给另一个App
statActivity(intent);
最后给出一个应用安装的示例:
private void installApp(Content content) {
File fileS = new File("/sdcard/temp.apk");
Uri data;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
// 给目标应用一个临时授权
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
data = FileProvider.getUriForFile(content, BuildConfig.APPLICATION_ID + ".provider", fileS);
} else {
data = Uri.fromFile(fileS);
}
intent.setDataAndType(data, "application/vnd.android.package-archive");
startActivity(intent);
}