android 7.0 应用间文件共享FileProvider
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中
1 <provider 2 android:name="androidx.core.content.FileProvider" 3 android:authorities="cn.com.txw.fileprovider" 4 android:exported="false" 5 android:grantUriPermissions="true"> 6 <meta-data 7 android:name="android.support.FILE_PROVIDER_PATHS" 8 android:resource="@xml/file_paths" /> 9 </provider>
非androidx 使用 android:name="android.support.v4.content.FileProvider"
3.2 定义共享文件的路径
1 <?xml version="1.0" encoding="utf-8"?> 2 <paths> 3 <external-files-path name="externalFiles" path="download/"/> 4 <external-path name="externalRoot" path="download/" /> 5 <root-path name="root" path="" /> 6 </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
1 public static void openApkFile(String file ) { 2 3 Intent intent = new Intent(Intent.ACTION_VIEW); 4 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 5 Uri data; 6 File apk = new File(file); 7 8 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 9 final String author = "cn.com.txw.fileprovider"; 10 try { 11 data = FileProvider.getUriForFile(mContext, author, apk); 12 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 13 }catch (Exception e){ 14 e.printStackTrace(); 15 Log.e(TAG, "openApkFile: exception = " + e.getMessage() ); 16 return; 17 } 18 } else { 19 data = Uri.fromFile(apk); 20 } 21 intent.setDataAndType(data, "application/vnd.android.package-archive"); 22 mContext.startActivity(intent); 23 }
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开启权限
1 uri = FileProvider.getUriForFile(mContext, author, apk); 2 int mode_flags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 3 mContext.grantUriPermission(mContext.getPackageName(), uri, mode_flags); 4 intent.addFlags(mode_flags);
mContext.revokeUriPermission关闭权限
1 mContext.revokeUriPermission(uri,mode_flags);
4.android 8.0的问题
上述示例是打开apk文件,注意在8.0后要申请”未知来源应用“的安装权限。
1 private boolean checkPermissions(){ 2 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { 3 String[] permissions = { 4 Manifest.permission.WRITE_EXTERNAL_STORAGE, 5 Manifest.permission.ACCESS_NETWORK_STATE, 6 Manifest.permission.REQUEST_INSTALL_PACKAGES}; 7 final int KG_PERMISSION = 13440; 8 9 int permissionCheck = 0 ; 10 11 for (String permission : permissions){ 12 permissionCheck += checkSelfPermission(permission); 13 } 14 if (permissionCheck != PackageManager.PERMISSION_GRANTED) { 15 requestPermissions(permissions,KG_PERMISSION); 16 return false; 17 } 18 } 19 return true; 20 }