Plugins for Xamarin の PCL Storage でファイルが見えない問題

Plugins for Xamarin の PCL Storage を使っていて、ファイルロケーションではまったので備忘録に.

PCL Storage の説明は下記リンクをご参照ください.

開発環境

  • Windows 10 Home
  • Visual Studio Community 2015
  • Xamarin 4.0.0.1717 (1390b70)
  • Xamarin.Android 6.0.0.35 (d300845)

デバッグ端末

  • Nexus 5X (Android 6.0.1)
  • SH-02E (Android 4.1.2)

Android でファイルを見えない問題

using PCLStorage;

IFolder rootFolder = FileSystem.Current.LocalStorage;
IFile file = await rootFolder.CreateFileAsync("data.txt", CreationCollisionOption.ReplaceExisting);
await file.WriteAllTextAsync("保存するテキスト");

上記コードで簡単にファイルを保存できるのですが,問題はこいつのファイルロケーションにあります.

FileSystem.Current.LocalStorageのパスは “/data/user/0/[package name]/files” なのですが(端末によって変わる可能性があります),この領域は自アプリからでないとファイルを参照することができません.

どういうことかというと,Android にはASTROファイルマネージャーやESファイルエクスプローラーのようなファイラーアプリがあるわけですが,それらを使ってストレージを参照してもファイルはおろかフォルダすら存在しないのです(/dataは空のフォルダと表示されます).

USB接続で端末のストレージを参照しても同様です.

保存したファイルを自アプリ以外から参照したい場合は,root権限を取得する必要があります(これは実際に試してはいません,root権限の取得は自己責任でお願い致します).

もちろん,自アプリでファイルを参照(read)することはできますので,自アプリ内で完結する場合は何の問題もありません.
端末内に保存したファイルをPCにコピーしたいといった需要がある場合に問題になります.

解決策

参照できないのあれば,参照できる場所に保存してしまえー!です.

// 任意のパスで大丈夫です
private static readonly string FilePath = "/sdcard/[package name]";

IFolder rootFolder = await FileSystem.Current.GetFolderFromPathAsync(FilePath);

これでファイラーアプリで参照可能な領域にファイルを保存できます.

ただし,FileSystem.Current.GetFolderFromPathAsync はフォルダが存在しない場合は Null を返すので,あらかじめフォルダを作成する必要があります.

まとめ

  • PCLStorage は簡単にファイルを保存できる
  • しかしながら,FileSystem.Current.LocalStorage ではファイラーアプリで参照できない
  • FileSystem.Current.GetFolderFromPathAsync を使えば参照可能(NRE に注意).

ずっとファイルが保存できていなのだと思いかなり悩みました;
Android でのみ確認していますが,もしかすると iOS や WinPhone でも同様に困ったことがあるかもしれません.

また,参照可能な領域を変数で定義するのではなく,PCL で取って来れるのが理想ですが,無理ですかね…?
ネイティブで書く場合はたぶんできます.

参考になれば幸いです.

以上