LoginSignup
6
6

More than 5 years have passed since last update.

【Androidアプリ】ターゲットAPIレベルを26にしたら、FileUriExposedExceptionが発生してクラッシュした

Posted at

前置き

2018 年 11 月: 既存のアプリのアップデートで、ターゲット API レベル 26 以降が必須になります。
【引用元】Google Developers Japan: 今後の Google Play でのアプリのセキュリティおよびパフォーマンスの改善について

今後もアップデートしていくに辺り、AndroidアプリのターゲットAPIレベルを26に引き上げました。
しかし、アップデートしてからAndroid Vitalsを見て、対応漏れに気づいたことが1つありました。

それが本記事のFileUriExposedExceptionです。
調べていくと、本来であればAndroid7.0(ターゲットAPIレベル24)で対応すべき内容でした。

Android 7.0 向けのアプリでは、Android フレームワークにより、自身のアプリ外への file:// URI の公開を禁止する StrictMode API ポリシーが適用されます。ファイル URI を含むインテントがアプリからなくなると、FileUriExposedException 例外によりアプリはエラーになります。
アプリ間でファイルを共有するには、content:// URI を送信して、この URI への一時的なアクセス パーミッションを付与する必要があります。このパーミッションを付与する最も簡単な方法は、FileProvider クラスを使用することです。
【引用元】Android 7.0 の動作の変更点  |  Android Developers

ということで、FileProviderクラスを使った実装に修正しました。

FileUriExposedException例外対応

共有ディレクトリを定義するXMLの作成

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

AndroidManifest.xmlにFileProviderクラスを定義する

AndroidManifest.xml
...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/paths" />
        </provider>
    </application>
</manifest>

FileProviderクラスを使った実装に修正する

xxxActivity.java
File file = new File(pathString);

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);

Uri uri;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
    uri = Uri.fromFile(file);

} else {
    uri = FileProvider.getUriForFile(xxxActivity.this, BuildConfig.APPLICATION_ID + ".fileprovider", file);

}
intent.setDataAndType(uri, "image/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
        | Intent.FLAG_GRANT_READ_URI_PERMISSION
);

startActivity(Intent.createChooser(intent, "アプリケーションを選択"));

参考

読書尚友のAndroid 7.0対応について - hishidaのblog
Android 画像ファイルを扱う際のFileとUriまとめ

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6