Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
492 views
in Technique[技术] by (71.8m points)

android - android.os.FileUriExposedException:file:///storage/emulated/0/test.txt通过Intent.getData()在应用程序之外公开(android.os.FileUriExposedException: file:///storage/emulated/0/test.txt exposed beyond app through Intent.getData())

The app is crashing when I'm trying to open a file.

(当我尝试打开文件时,应用程序崩溃。)

It works below Android Nougat, but on Android Nougat it crashes.

(它在Android Nougat以下运行,但是在Android Nougat上崩溃。)

It only crashes when I try to open a file from the SD card, not from the system partition.

(仅当我尝试从SD卡而不是系统分区打开文件时,它才会崩溃。)

Some permission problem?

(一些权限问题?)

Sample code:

(样例代码:)

File file = new File("/storage/emulated/0/test.txt");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "text/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); // Crashes on this line

Log:

(日志:)

android.os.FileUriExposedException: file:///storage/emulated/0/test.txt exposed beyond app through Intent.getData()

(android.os.FileUriExposedException:file:///storage/emulated/0/test.txt通过Intent.getData()在应用程序之外公开)

Edit:

(编辑:)

When targeting Android Nougat, file:// URIs are not allowed anymore.

(定位Android牛轧糖时,不再允许file:// URI。)

We should use content:// URIs instead.

(我们应该改用content:// URI。)

However, my app needs to open files in root directories.

(但是,我的应用程序需要打开根目录中的文件。)

Any ideas?

(有任何想法吗?)

  ask by Thomas Vos translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If your targetSdkVersion >= 24 , then we have to use FileProvider class to give access to the particular file or folder to make them accessible for other apps.

(如果您的targetSdkVersion >= 24 ,那么我们必须使用FileProvider类来授予对特定文件或文件夹的访问权限,以使其他应用程序可以访问它们。)

We create our own class inheriting FileProvider in order to make sure our FileProvider doesn't conflict with FileProviders declared in imported dependencies as described here .

(我们创造我们自己的类继承FileProvider ,以确保我们的FileProvider并不冲突与进口的依赖声明FileProviders描述这里 。)

Steps to replace file:// URI with content:// URI:

(将file:// URI替换为content:// URI的步骤:)

  • Add a class extending FileProvider

    (添加一个扩展FileProvider的类)

     public class GenericFileProvider extends FileProvider {} 
  • Add a FileProvider <provider> tag in AndroidManifest.xml under <application> tag.

    (在AndroidManifest.xml <application>标记下添加FileProvider <provider> <application>标记。)

    Specify a unique authority for the android:authorities attribute to avoid conflicts, imported dependencies might specify ${applicationId}.provider and other commonly used authorities.

    (为android:authorities属性指定唯一的权限以避免冲突,导入的依赖项可能指定${applicationId}.provider和其他常用权限。)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    <application
        ...
        <provider
            android:name=".GenericFileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>
    </application>
</manifest>
  • Then create a provider_paths.xml file in res/xml folder.

    (然后在res/xml文件夹中创建一个provider_paths.xml文件。)

    Folder may be needed to created if it doesn't exist.

    (如果文件夹不存在,则可能需要创建该文件夹。)

    The content of the file is shown below.

    (该文件的内容如下所示。)

    It describes that we would like to share access to the External Storage at root folder (path=".") with the name external_files .

    (它描述了我们想共享对外部存储在根文件夹(path=".") ,其名称为external_files 。)

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>
  • The final step is to change the line of code below in

    (最后一步是更改下面的代码行)

     Uri photoURI = Uri.fromFile(createImageFile()); 

    to

    (至)

     Uri photoURI = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", createImageFile()); 
  • Edit: If you're using an intent to make the system open your file, you may need to add the following line of code:

    (编辑:如果要使用意图使系统打开文件,则可能需要添加以下代码行:)

     intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 

Please refer, full code and solution has been explained here.

(请参考,完整的代码和解决方案已在此处进行了说明)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...