android.os.FileUriExposedException是在奥利奥引起的(仅限!)

时间:2018-02-23 12:51:54

标签: java android android-intent share android-fileprovider

在Google Play控制台中,我可以看到此异常仅发生在使用Android 8.0 +的设备上。

android.os.FileUriExposedException: 
at android.os.StrictMode.onFileUriExposed (StrictMode.java:1975)
at android.net.Uri.checkFileUriExposed (Uri.java:2355)
at android.content.Intent.prepareToLeaveProcess (Intent.java:9975)
at android.content.Intent.prepareToLeaveProcess (Intent.java:9950)
at android.content.Intent.prepareToLeaveProcess (Intent.java:9929)
at android.app.Instrumentation.execStartActivity (Instrumentation.java:1622)
at android.app.Activity.startActivityForResult (Activity.java:4748)
at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult (BaseFragmentActivityJB.java:10)
at android.support.v4.app.FragmentActivity.startActivityForResult (FragmentActivity.java)
at android.support.v4.app.ActivityCompatJB.finishAffinity (ActivityCompatJB.java)
or                                         .startActivityForResult (ActivityCompatJB.java)
at android.support.v4.app.ActivityCompat.a (ActivityCompat.java:6)
at android.support.v4.app.FragmentActivity.a (FragmentActivity.java:8)
at android.support.v4.app.FragmentActivity$HostCallbacks.a (FragmentActivity.java:2)
at android.support.v4.app.Fragment.a (Fragment.java:38)
at android.support.v4.app.Fragment.a (Fragment.java:1)
at de.test.testapp.FileManagerFragment.onClick (FileManagerFragment.java:113)
at android.view.View.performClick (View.java:6291)
at android.view.View$PerformClick.run (View.java:24931)
at android.os.Handler.handleCallback (Handler.java:808)
at android.os.Handler.dispatchMessage (Handler.java:101)
at android.os.Looper.loop (Looper.java:166)
at android.app.ActivityThread.main (ActivityThread.java:7390)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:245)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:926)

代码:

Intent intent = new Intent(Intent.ACTION_VIEW);
ArrayList<Uri> uri = new ArrayList<Uri>();
for (int i=0; i<checkedItems.size(); i++) {
    if (checkedItems.valueAt(i)) {
        intent.setDataAndType(Uri.fromFile(new File(projectDir, filename), "text/plain");
    }
}
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(intent, "Open RINEX File"));

清单:

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<!-- To access Google+ APIs: -->
<uses-permission android:name="android.permission.INTERNET" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="de.test.testapp"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_providers_paths" />
    </provider>
</application>

file_providers_paths.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>

为什么这会在Android 7上运行而在Android 8上不再运行?发生了什么行为变化?我在片段中称呼它。

3 个答案:

答案 0 :(得分:5)

尝试在 onCreate 中添加此内容。

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();

答案 1 :(得分:2)

如果您有一个使用Uri与其他应用共享文件的应用,则可能在API 24+上遇到了此错误。

当您尝试在Intent广播中共享file:// Uri与其他应用程序共享数据时,会发生此错误。在这种情况下,不建议使用file:// Uri,因为它对目标应用程序进行了一些假设。一方面,我们假设目标应用程序具有READ_EXTERNAL_PERMISSION,但事实并非如此。如果目标应用程序没有READ_EXTERNAL_PERMISSION,则这可能会导致充其量或最大程度的意外行为,从而导致崩溃。

从Android N开始,要变通解决此问题,您需要使用FileProvider API。

第1步:清单输入

<manifest ...>
    <application ...>
        <provider
            android:name="android.support.v4.content.FileProvider"
            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>

第2步:创建XML文件res / xml / provider_paths.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>

第3步:代码更改

File file = ...;
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
// Old Approach
install.setDataAndType(Uri.fromFile(file), mimeType);
// End Old approach
// New Approach
Uri apkURI = FileProvider.getUriForFile(
                         context, 
                         context.getApplicationContext()
                         .getPackageName() + ".provider", file);
install.setDataAndType(apkURI, mimeType);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// End New Approach
context.startActivity(install);

答案 2 :(得分:0)

这是因为来自病房的android 8无论您以编程方式获取的图像都存储到图库中,因此您无法访问图库文件或其URI,如果实现您需要的任何图像捕获功能实现捕获的图像并将其存储到资源文件夹,然后从那里获取URI。这就是为什么我们这样做

  

机器人:资源=&#34; @ XML / file_providers_paths&#34;

实际上从用户的安全角度来看它是好的。