Flutter: file_pickerで取得したファイルがiOSのtmpフォルダからすぐ消える
結論:tmpフォルダからファイルが消えないアプリ内専用フォルダに移動させる
2023/1/22 Flutter エラー・バグ日記
開発したアプリに、file_pickerパッケージを使って画像を取得後、ボタンを押すと、その画像をギャラリーに保存できる機能を実装していた(画像保存部分は、image_gallery_saverというパッケージを使用)。
しかし、iOSで試したところ、画像を取得した直後は保存できるが、しばらく経ってから保存しようとすると、エラーになり、画像を保存できなかった。
Androidでは発生しないが、iOSのシミュレーター・実機いずれでも発生した。
また、ファイルは画像に限らず、テキストなど他の種類のファイルでも同様に発生した。
1分経つと、一時保存フォルダから自動的に消えていた。。
file_pickerで取得した画像は、「tmp」という一時保存用のフォルダに保存されるが、そのパスは、
filePickerResultO.files.single.path!
※「filePickerResultO」は、「FilePicker.platform.pickFiles」メソッドの返り値を入れた「FilePickerResult」型のプロパティ
で取得できる。
そこで、上記プロパティから取得したパスを、print文などで表示させ、Finder上でそのフォルダを見てみると、「tmp」フォルダ内に、画像が存在していないことが分かった。
正確には、「tmp」フォルダ直下ではなく、「tmp」の更に下にある
「bundle identifier名-Inbox」
※例えば、bundle identifierが「com.example.studyapp」の場合は、「com.example.studyapp-Inbox」
という名前のフォルダ内にあるはずなのだが、それが消えていた。
[iOSシミュレーターの例]
/Users/######/Library/Developer/CoreSimulator/Devices/####デバイスの識別番号####/data/Containers/Data/Application/####デバイスの識別番号####/tmp/com.example.studyapp-Inbox/画像ファイル名.jpg
再度、Finderで上記パスを開いたまま、画像取得をしたところ、1分を経過すると、自動的に削除されることが分かった(1分ちょうどで、Finder上からファイルが消えるのを確認した)。
実は写真アプリから取得した場合は消えない
iOSの場合、file_pickerでファイルを取得できる先は、あらかじめ指定するメディアタイプによって、「写真アプリ」か「ファイルアプリ」のいずれかになる。
※参考記事
ファイル取得処理を行う「pickFiles」メソッドの「type:」引数に何も設定しないと(デフォルトだと)、ファイルアプリからの取得になる(引数として「type: FileType.any」や「type: FileType.custom」を設定した状態と同じ)。
一方、写真アプリから取得したい場合は、引数を「type: FileType.image」か「type: FileType.media」に設定する必要がある。
そこで、引数の設定を切り替えて、ファイルアプリから取得するケースと、写真アプリから取得するケースを比較したところ、今回のファイルが消える問題は、ファイルアプリからの取得時に起きることが分かった。
ちなみに、写真アプリから取得した際の一時保存先のパスは、ファイルアプリからの取得時とは異なり、「tmp」フォルダ直下になっていた。
[iOSシミュレーターの例]
/Users/######/Library/Developer/CoreSimulator/Devices/####デバイスの識別番号####/data/Containers/Data/Application/####デバイスの識別番号####/tmp/画像ファイル名.jpg
「tmp」フォルダ直下だと、1分以上経っても画像は消えなかった。
そのため、ファイルアプリから取得した場合だけ、対処が必要となる模様。。
Apple Developer公式サイトでは説明が見つからず
「tmp」フォルダの仕様を確認したいと思い、Apple Develperの下記公式説明
の中段にある「iOSデータストレージガイドライン」
を見てみたが、「システムは定期的にtmpフォルダ内のファイルを削除する」という説明しか無く、1分経ったら削除する、とか、「bundle identifier名-Inbox」フォルダ配下のみ削除する、といった具体的な説明はない(どこかに記載されているのかもしれないが、、)。
また、下記公式ドキュメント
では、「tmp」フォルダについて、もう少し詳しい説明がなされているが、ここでも「アプリが動作していないときに削除する」という内容にとどまっている。
GitHubのイシューに報告あり
ネット上を調べると、GitHubのイシューに、「tmp」フォルダ内のファイルが1分で消えるという報告が上がっていた。
自分が確認した状況と全く同じで、
- 「写真アプリ」からの取得だと消えないが、「ファイルアプリ」からの取得だと消える
- 「写真アプリ」からと「ファイルアプリ」からでは、一時保存されるパスが異なる
という内容も報告されている。
本イシューの結論(対処法)としては、「tmp」フォルダ内の画像を、自動削除されないアプリ内の別フォルダに移動させておくことが提案されていた。
そのため、「path_provider」パッケージの「getApplicationDocumentsDirectory()」メソッドを使い、取得したアプリ内専用フォルダのパスに、「tmp」フォルダ内の画像を移動させる形で対処することにした。
なぜファイルアプリから取得した時だけ1分で削除するのか、やや疑問が残ったが、自動削除する仕様自体は、「tmp」フォルダの肥大化を防ぐ仕様だと思うので、いったん割り切ることにする。
\一般的なエラー対処法をまとめた記事はこちら/
リリースしたアプリ(全てFlutterで開発)
個人アプリ開発で役立ったもの
おすすめの学習教材
\超初心者向けでオススメな元Udemyの講座/
\キャンペーン時を狙えば安価で網羅的な内容が学べる(日本語訳あり)/
\Gitの基礎について無料で学べる/
おすすめの学習書籍
\実用的。image_pickerに関してかなり助けられた/
\Dartの基礎文法を素早くインプットできる/