2024-07-16升级问题:调用自带软件打开文件时 android.os.FileUriExposedException

2024-07-16升级问题:调用手机自带软件打开文件时,出现以下问题:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: rs.tabletcropland, PID: 10997
    android.os.FileUriExposedException: file:///storage/emulated/0/arcgis/%E7%9F%B3%E7%8B%AE%E5%B8%82/Attachment/%E7%9F%B3%E7%8B%AE%E5%B8%82%E8%AE%BE%E6%96%BD%E5%86%9C%E4%B8%9A%E5%A4%A7%E6%A3%9A%E8%B0%83%E6%9F%A5%E6%95%B0%E6%8D%AE.xlsx exposed beyond app through Intent.getData()
        at android.os.StrictMode.onFileUriExposed(StrictMode.java:2210)
        at android.net.Uri.checkFileUriExposed(Uri.java:2419)
        at android.content.Intent.prepareToLeaveProcess(Intent.java:11812)
        at android.content.Intent.prepareToLeaveProcess(Intent.java:11764)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1765)
        at android.app.Activity.startActivityForResult(Activity.java:5730)
        at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:767)
        at android.app.Activity.startActivityForResult(Activity.java:5654)
        at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:754)
        at android.app.Activity.startActivity(Activity.java:6152)
        at android.app.Activity.startActivity(Activity.java:6105)
        at com.FJDZYG.GIS.Tools.Base.OpenFileUtil.openFile(OpenFileUtil.java:107)
        at com.FJDZYG.GIS.Common.homePage.view.SearchFileActivity.openfile(SearchFileActivity.java:68)
        at com.FJDZYG.GIS.Common.homePage.view.SearchFileActivity.access$300(SearchFileActivity.java:33)
        at com.FJDZYG.GIS.Common.homePage.view.SearchFileActivity$6.false}
    lifecycleStateRequest PauseActivityItem{finished=true,userLeaving=false,configChanges=0,dontReport=false}
I/Process: Sending signal. PID: 10997 SIG: 9
Process 10997 terminated.

        这个错误是因为在Android 7.0及以上版本中,直接使用file://URI可能会导致FileUriExposedException。为了解决这个问题,你可以将文件路径转换为content://URI,然后使用Intent来打开文件。

解决步骤:

1、在AndroidManifest.xml中添加FileProvider

        在你的AndroidManifest.xml文件中添加一个<provider>元素,用于声明FileProvider和其相关的元数据。这里需要注意的是android:authorities属性的值:

authorities:app的包名.fileProvider
grantUriPermissions:必须是true,表示授予 URI 临时访问权限
exported:必须是false
resource:中的@xml/file_paths是我们接下来要添加的文件

<application ... >
    ...
    <!--authorities="你的包名+fileprovider" -->
    <provider
        android:authorities="${applicationId}.fileprovider"
        android:name="android.support.v4.content.FileProvider"
        android:grantUriPermissions="true"
        android:exported="false">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/filepaths"/>
    </provider>
    ...
</application>

如果是AndroidX的库,则可以如下:

        <!--authorities="你的包名+fileprovider" -->
        <provider
            android:authorities="${applicationId}.fileprovider"
            android:name="androidx.core.content.FileProvider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths"/>
        </provider>

2、创建file_paths.xml文件

        在你的Android项目的res/xml目录下创建一个名为file_paths.xml的文件(如果xml文件夹不存在,则需要创建它)。在这个文件中,你可以定义共享文件的路径。例如,以下代码表示共享外部存储根目录下的所有文件:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="." />
</paths>

完整的:
files-path代表的根目录: Context.getFilesDir().getPath()
external-path代表的根目录: Environment.getExternalStorageDirectory().getPath()
cache-path代表的根目录: getCacheDir().getPath()

path 代表需要共享的目录
name 只是一个标识,随便取

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- external-path:sd ;path:你的应用保存文件的根目录;name随便定义-->
    <!-- root-path 手机存储根目录 -->
    <root-path path="" name="arcgis" />
    <external-path name="external_files" path="." />

    <files-path name="picture" path="internal/pic/"/>
    <files-path name="database" path="internal/db/"/>
    <external-files-path name="picture" path="picture/"/>
</paths>

3、在代码中使用FileProvider 

 在需要构建文件Uri的地方,使用FileProvider来构建Uri,而不是直接使用Uri.fromFile()。

完整代码:

/**
     * 打开文件
     * 兼容7.0
     * @param context     activity
     * @param file        File
     * @param contentType 文件类型如:文本(text/html)
     *                    当手机中没有一个app可以打开file时会抛ActivityNotFoundException
     */
    public static void startActionFile(Context context, File file, String contentType) throws ActivityNotFoundException {
        if (context == null) {
            return;
        }
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//打开只要读取的权限就够了。写的权限会导致失败
        intent.setDataAndType(getUriForFile(context, file), contentType);
        if (!(context instanceof Activity)) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        context.startActivity(intent);
    }
/***
     * Android7.0以上文件在应用间打开方式
     * @param context
     * @param file
     */
    public static void openFile_new(Context context, File file) {
        try {
            if (context == null) {
                return;
            }
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//打开只要读取的权限就够了。写的权限会导致失败
            String contentType = getMIMEType(file);
            intent.setDataAndType(getUriForFile(context, file), contentType);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            context.startActivity(intent);
        }
        catch (ActivityNotFoundException e) {
            // TODO: handle exception
            Toast.makeText(context, "sorry附件不能打开,请下载相关软件!", Toast.LENGTH_LONG).show();
        }
    }

    public static Uri getUriForFile(Context context, File file) {
        if (context == null || file == null) {
            throw new NullPointerException();
        }
        Uri uri;
        if (Build.VERSION.SDK_INT >= 24) {
            uri = FileProvider.getUriForFile(context.getApplicationContext(), context.getPackageName()+".fileprovider", file);
        } else {
            uri = Uri.fromFile(file);
        }
        return uri;
    }

至此,问题解决。

  • 16
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值