33
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Flutter で外部ストレージにアクセスするアプリを作るときは Android バージョンを考慮して『ひと手間』いるから注意してくれよな!

Posted at

TL;DR

READ_EXTERNAL_STORAGE パーミッションや WRITE_EXTERNAL_STORAGE パーミッションを必要としているアプリは、 AndroidManifest.xmlandroid:requestLegacyExternalStorage="true" を設定すれば OK です。

app/src/main/AndroidManifest.xml
<application
    android:name="io.flutter.app.FlutterApplication"
    android:label="YourAppName"
    android:icon="@mipmap/ic_launcher"
    android:requestLegacyExternalStorage="true">

事の発端

開発中のアプリで image_picker を使っていました。
エミュレーターでは問題なく動作していたのですが、いざ実機で動作確認をしてみると……

「イメージをピックできない!?」

となったわけです。

実はエラーが発生していた

デバッグして確認してみると、

Unable to decode stream: java.io.FileNotFoundException: /storage/emulated/0/Pictures/any_image.jpg: open failed: EACCES (Permission denied)

というエラーが発生していました。

パーミッション? と思い AndroidManifest.xml<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> を設定してみましたが結果は変わりませんでした。

原因

じつは Issues にあがっていました。
Android バージョンが原因のようです。

変更されていた外部ストレージへのアクセス方法

Android 10 ( API レベル 29 )以降から外部ストレージへのアクセス管理が変更 1 になっているようです。

ユーザーがファイルを詳細に管理して整理できるように、Android 10(API レベル 29)以降をターゲットとするアプリには、外部ストレージ デバイスに対する特別アクセス権限がデフォルトで付与されます(対象範囲別ストレージ)

とのことで、 READ_EXTERNAL_STORAGE パーミッションや WRITE_EXTERNAL_STORAGE パーミッションは不要になっています。

また、他のアプリが作成したファイルへのアクセスは、

  1. アプリに READ_EXTERNAL_STORAGE パーミッションが付与されていること。
  2. 対象ファイルが、明確に定義された次のいずれかのメディア コレクション内にあること。

のようになっています。

つまり、 Flutter のパッケージがこの対応についていっていないと外部ストレージにアクセスできない状況が発生するということです。

対策

Android デベロッパー に次のような警告があがっていました。
警告.png
つまり、いずれきれいにしたいけど今は微妙な状態だから気をつけてな! ってことでしょうね。
だから上で紹介した Issues もオープン状態のままなわけで……。

そんな状態でも一応は対処方法があるようなので紹介します。

対象範囲別ストレージをオプトアウトする

Android 9( API レベル 28 )以前をターゲットにする

これはそのとおりですね。
アクセス管理変更前のバージョンを相手にすればエラーは起こりません。

requestLegacyExternalStorage の値を true に設定する

Android 10 以降をターゲットにしている場合は、 AndroidManifest.xmlandroid:requestLegacyExternalStorage="true" を設定すれば OK です。

app/src/main/AndroidManifest.xml
<application
    android:name="io.flutter.app.FlutterApplication"
    android:label="YourAppName"
    android:icon="@mipmap/ic_launcher"
    android:requestLegacyExternalStorage="true">

両方のバージョンをターゲットにしたい場合は?

app/src/main/AndroidManifest.xml
<uses-permission 
	android:name="android.permission.READ_EXTERNAL_STORAGE"
	android:maxSdkVersion="18" />

uses-permissionmaxSdkVersion 属性が追加されたようなので、 18 を指定すれば良さそうです。
(ただ Flutter で利用している分には maxSdkVersion 属性を指定してなくても動きそうなんだよな…… :thinking::question:

まとめ

Flutter の開発をしていると、エラーの解消に割と時間がかかります。
プラットフォーム依存のものが多かったり、そもそも情報が少ないのも理由かもしれません。

自分が遭遇したエラーで情報の少ないものはなるべく書き溜めていこうと思いますので、同じエラーで困っている人のお役に少しでも立てれば幸いです!

  1. 変更内容の詳細は Android デベロッパー に詳しく記載されています

33
19
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
33
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?