[flutter]アプリ領域にデータを保存する際の注意点

flutterで端末内、内部領域にデータを保存する方法は調べるとたくさん出てきますが、肝心なところが抜け落ちている記事が多いため、注意喚起もかねて書いてみました。
自分もアプリをリリースして何度もアップデートをした後という、かなり時間が経ってから気付きました。。

内部領域に保存する方法

端末内に保存する処理はシンプルです。まずはこれらをインポート。

// pubspec.yamlにて
dependencies:
  provider:

//保存処理を書きたいところで
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;

端末内に保存するためには各OS毎の保存領域までのパスが必要なので以下で取得

String newPath = (await getApplicationDocumentsDirectory()).path;

上記で保存領域のパスが取得できるのですがここからが見落としがち。
実はこのパス、iOSのシュミレータでデバッグ実行すると毎回変わり、更にストア公開アプリにおいても、アップデートのタイミングで変わってしまうことがあるのです。

なのでもし、「このパス情報を絶対パスとして保存しておいて読み込む」 というような処理を書いてしまうと、アップデートのタイミングで何故か稀に過去データにアクセスできない! という現象に悩まされるのです。

ちなみに自分は画像ファイルを保存・呼び出しする処理でやってしまっていました。

//画像を保存 これは端末内領域に保存しているのでオッケー。ただこのパスを参照情報として保持しない!また、pathパッケージを使ってないのもダメポイント。
String newPath = (await getApplicationDocumentsDirectory()).path + '/' + fileName;
File savedFile = await file.copy(newPath);
saveNewPath(newPath); //ファイルまでの絶対パスを保存する処理。ダメ!
saveFileName(fileName); //ファイル名を保存する処理。オッケー。

// ダメなパターン
String readPath = readNewPath();
var imageFile = File(readPath);

//良いパターン
String fileName = readFileName();
String nowDocumentPath = (await getApplicationDocumentsDirectory()).path;
var imageFile = File(p.join(nowDocumentPath, fileName));

なんでパスが変わるのに過去のデータも読めるの?と思われるかもしれませんが、内部領域のパスが変わる時には、中のデータがそのままコピーされるようなのです。そのため、内部的にはデータが残ったまま、パスが変わっただけな状態なのです。

まとめ

ネイティブ開発者からすれば当たり前なのかもしれませんが、flutterから入った初心者中級者は見落としがちではないでしょうか。まさか本番環境での内部保存領域パスが変わるとは思いませんでした。。

ただこれで半ば諦めるしかなかった、シミュレータでデバッグをする度に内部領域データが参照できなくなるという現象を回避することができました。開発当時ネットで調べると「そんなものです。リリースすれば発生しないので気にしないで。」的な情報が出てましたが、全くそんなことないですね。対処必須です。この現象が現れたのが利用者が少ない時で本当によかった。