1.官方教程
Android 7.0 以后安全系数提高,应用间文件共享要使用FileProvider。原来的 file:///
Uri 替换为
content://
Uri
https://developer.android.com/reference/android/support/v4/content/FileProvider
2.步骤
- Defining a FileProvider
- Specifying Available Files
- Retrieving the Content URI for a File
- Granting Temporary Permissions to a URI
- Serving a Content URI to Another App
3.示例
3.1 定义 FileProvider
在AndroidManifest.xml中
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="cn.com.txw.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
非androidx 使用 android:name="android.support.v4.content.FileProvider"
3.2 定义共享文件的路径
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path name="externalFiles" path="download/"/>
<external-path name="externalRoot" path="download/" />
<root-path name="root" path="" />
</paths>
注意 path的值是目录时要有 "/"
<paths>可选子标签及含义 如下:
子标签 | 路径 |
---|---|
file-path | Context.getFilesDir() |
cache-path | getCacheDir() |
external-path | Environment.getExternalStorageDirectory() |
external-files-path |
Context#getExternalFilesDir(String) Context.getExternalFilesDir(null) . |
external-cache-path | Context.getExternalCacheDir() |
external-media-path | Context.getExternalMediaDirs() |
root-path |
根目录 "/" |
3.3 生成共享文件的uri
public static void openApkFile(String file ) { Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri data;
File apk = new File(file); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
final String author = "cn.com.txw.fileprovider";
try {
data = FileProvider.getUriForFile(mContext, author, apk);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}catch (Exception e){
e.printStackTrace();
Log.e(TAG, "openApkFile: exception = " + e.getMessage() );
return;
}
} else {
data = Uri.fromFile(apk);
}
intent.setDataAndType(data, "application/vnd.android.package-archive");
mContext.startActivity(intent);
}
FileProvider.getUriForFile(mContext, author, apk) 生成uri,其中:
- author 为AndroidManifest 中指定的 android:authorities="cn.com.txw.fileprovider"
- apk 为文件绝对路径
- mContext 为Context
3.4 文件的临时权限
上述代码中的 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 增加uri相关临时权限。
mContext.grantUriPermission开启权限
uri = FileProvider.getUriForFile(mContext, author, apk);
int mode_flags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
mContext.grantUriPermission(mContext.getPackageName(), uri, mode_flags);
intent.addFlags(mode_flags);
mContext.revokeUriPermission关闭权限
mContext.revokeUriPermission(uri,mode_flags);
4.android 8.0的问题
上述示例是打开apk文件,注意在8.0后要申请”未知来源应用“的安装权限。
private boolean checkPermissions(){
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
String[] permissions = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.REQUEST_INSTALL_PACKAGES};
final int KG_PERMISSION = ; int permissionCheck = ; for (String permission : permissions){
permissionCheck += checkSelfPermission(permission);
}
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
requestPermissions(permissions,KG_PERMISSION);
return false;
}
}
return true;
}