android 7.0 应用间文件共享FileProvider

时间:2022-03-04 15:04:25

1.官方教程

  Android 7.0 以后安全系数提高,应用间文件共享要使用FileProvider。原来的 file:/// Uri 替换为 content://Uri 

  https://developer.android.com/reference/android/support/v4/content/FileProvider

2.步骤

  1. Defining a FileProvider
  2. Specifying Available Files
  3. Retrieving the Content URI for a File
  4. Granting Temporary Permissions to a URI
  5. 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;
}