Xamarin.Formsでアプリケーションのデータ保存先はどこがいい?
結論としては共有プロジェクト側でSpecialFolder.LocalApplicationData
を使えばいい気がしてきた.
アプリケーションがデータを保存する先はどのディレクトリにしたらいいのだろうか?
各プラットフォームごとに異なるディレクトリを指定しなければならないのだろうか?
プラットフォームごとにコードを変えなければいけないのはいやだな,と思う.
それに対するスレッドが↓
SpecialFolderに対応するディレクトリはプラットフォームごとに異なる
SpecialFolderの種類はこちらにすべてリストアップされている.
この中でモバイルアプリのデータ保存先としてはPersonal
,MyDocuments
,LocalApplicationData
が代表的である.
Android
SpecialFolder.Personal
とSpecialFolder.MyDocuments
は,両方とも/data/data/@PACKAGE_NAME@/files
を指す.
SpecialFolder.LocalApplicationData
は/data/data/@PACKAGE_NAME@/files/.local/share
を指す.
これらのフォルダには他のアプリケーションからアクセスできないし,rootを取得しない限りユーザーもアプリ以外からアクセスできない.
ということはどれ使っても構わない,ということか.
iOS
SpecialFolder.Personal
とSpecialFolder.LocalApplicationData
,SpecialFolder.MyDocuments
はすべて/Documents
を指す.
/Documents /Library /Library/Application Support /Library/Caches /tmp
/Documents
はiTunesから見える.iTunesの共有機能がOnの場合は,この中のデータがiTunes/iCloudにバックアップされる.
/Library
はiTunesから見えない./Library/Caches
以外はiTunes/iCloudにバックアップされる.
ユーザーに直接見せる必要がないファイルやデータ,例えば(SQLiteなどの)Databaseファイルは,Library
フォルダに置くことをおすすめする.もし必要なら暗号化して.
Library
フォルダのパスはiOSでは以下のようにする.
Path.Combine(Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments), "..", "Library");
これはAndroid側とは異なる指定になるため,プラットフォームごとに指定しわける必要がある.
プラットフォームごとにアプリ保存先のパスを変える方法
方法1
各プラットフォームのプロジェクト内でそれぞれパスを取得し,それをAppクラスのコンストラクタに渡す.
Android : MainActivity.cs
var dbPath = Path.Combine(System.Environment.GetFolderPath (System.Environment.SpecialFolder.Personal), "productsDB.db"); var productsRepository = new ProductsRepository(dbPath); Xamarin.Essentials.Platform.Init(this, savedInstanceState); global::Xamarin.Forms.Forms.Init(this, savedInstanceState); LoadApplication(new App(productsRepository));
iOS : AppDelegate.cs
SQLitePCL.Batteries_V2.Init();//iOSはこれが必要らしい var dbPath = Path.Combine(Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments), "..", "Library", "products.db"); var productsRepository = new ProductsRepository(dbPath); global::Xamarin.Forms.Forms.Init(); LoadApplication(new App(productsRepository));
iOS,AndroidそれぞれのプロジェクトにSqlite.Standardプロジェクトへの参照を追加する.
もちろんAppクラスに引数を受け取るコンストラクタを作る必要がある.
Shared : App.xaml.cs
public App(IProductsRepository productsRepository) { InitializeComponent(); MainPage = new MainPage(); }
方法2
Device.RuntimePlatform
で分ける?
App.xaml.csで.
string dbPath = string.Empty; switch (Device.RuntimePlatform) { case Device.iOS: dbPath = Path.Combine(Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments), "..", "Library", "products.db"); break; case Device.Android: dbPath = Path.Combine(System.Environment.GetFolderPath (System.Environment.SpecialFolder.Personal), "productsDB.db"); \ break; case Device.UWP: // break; } productsRepository = new ProductsRepository(dbPath);
これでいけるかどうかは確認していない.