アプリの設定情報なんかを保存する時、Android では SharedPreference 、iOS では NSUserDefaults を使うわけですが、プラットフォーム毎にコード書くのめんどい!と思って

とツイートしたところ、Xamarin の中の人である @atsushieno さんから、

とアドバイスを頂きました。

IsolatedStorage(分離ストレージ) とは、.NET Framework(当然 Mono も)に用意されている、OS のファイルシステムとは切り離されたデータ領域の事で、アプリケーション毎、ユーザー毎など、アクセス権限を細かく設定できるのが特徴です。

そこで気になったのは、Xamarin.Android/iOS で IsolatedStorage を利用した時に、実体はどこに保存されるのか?ということ。

Android では、ストレージの /data/data/<アプリ名> 配下は、そのアプリ専用のデータ領域であり、そのアプリしかアクセス許可が与えられていない他、アプリをアンインストールするとそのデータ領域も削除されます。
(iOS は詳しくないですが、 userDefaults も同様だろうと思ってます。)

で、調べてみました。

Xamarin.Android の場合

Xamarin Studio で、適当な Xamarin.Android プロジェクトを作って、MainActivity の onCreate で、IsolatedStorage にファイルを作成しています。
IsolatedStorage は、どこまでアクセス許可を与えるかを IsolatedStorageScope 列挙体 で指定しますが、ここでは、SharedPreference の MODE_PRIVATE に最も近いであろう ApplicationUser を組み合わせた Scope で生成する GetUserStoreForApplication() を使います。

サンプルコードは、

を参考にさせてもらいました。

```c# MainActivity.cs
using System;

using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.IO.IsolatedStorage;
using System.IO;

namespace IsolatedStorageTest
{
[Activity (Label = “IsolatedStorageTest”, MainLauncher = true)]
public class Activity1 : Activity
{
int count = 1;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        var file = IsolatedStorageFile.GetUserStoreForApplication();
        
        // 分離ストレージにtest.txtというファイルを作成しストリームを開く
        using (IsolatedStorageFileStream strm = file.CreateFile("test.txt"))
        using (StreamWriter writer = new StreamWriter(strm))
        {
            // データを書き込む
            writer.Write("Hello!");
            writer.Write("Storage.");
        }
    }
} } ```

上記の var file = … の次の行にブレークポイントを設置して、デバッグ実行します。
ブレークしたら、変数 file をウォッチなどを覗いてみると、Non-public なフィールド directory が「/data/data/<アプリ名>/files/.config/.isolated-storage」 を示していることが分かります。

Xamarin.iOS の場合

次に Xamarin.iOS でも適当なプロジェクトを作って、ViewDidLoad に IsolatedStorage への書き出しコードを挿入します。

```c# IsolatedStorageiOSTestViewController.cs
using System;
using System.Drawing;

using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.IO.IsolatedStorage;
using System.IO;

namespace IsolatedStorageiOSTest
{
public partial class IsolatedStorageiOSTestViewController : UIViewController
{
public IsolatedStorageiOSTestViewController() : base (“IsolatedStorageiOSTestViewController”, null)
{
}

    public override void DidReceiveMemoryWarning()
    {
        // Releases the view if it doesn't have a superview.
        base.DidReceiveMemoryWarning();
		
        // Release any cached data, images, etc that aren't in use.
    }
	
    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
		
        var file = IsolatedStorageFile.GetUserStoreForApplication();
        
        // 分離ストレージにtest.txtというファイルを作成しストリームを開く
        using (IsolatedStorageFileStream strm = file.CreateFile("test.txt"))
            using (StreamWriter writer = new StreamWriter(strm))
        {
            // データを書き込む
            writer.Write("Hello!");
            writer.Write("Storage.");
        }
    }
	
    public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation)
    {
        // Return true for supported orientations
        return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
    }
} } ```

デバッグして、file 変数を覗いてみると、directory が「<省略>/iPhone Simulator/6.1/Applications/<アプリのUUID>/Documents/.config/.isolated-storage」 を示していることが分かります。

ということで、IsolatedStorage の保存先は、Android では /data/data/<アプリ名>/、iOS の場合は /<アプリのUUID>/Documents/ と、アプリごとの固有の場所になっている事が分かりました。

セキュリティ上の注意

Android の /data/data/<アプリ名> はアプリしかアクセスできないディレクトリですが、データ自体が暗号化されるわけではありません。(端末のROOT化や、apkを入手してエミュレータでアプリを実行することで /data/data/ のデータは取り出せます。)

また、iOS の /<アプリUIID>/ はセキュアではないようです。(UUIDさえ分かれば他のアプリからもアクセスできるという事?)

秘匿情報の保存には KeyChain を使え、と書いてありますね。

さらに、.NET の IsolatedStorage の説明にも、「暗号化されていないキーやパスワードは保存するな」と書いてあります。

You should not use isolated storage in the following situations:

  • To store high-value secrets, such as unencrypted keys or passwords, because isolated storage is not protected from highly trusted code, from unmanaged code, or from trusted users of the computer.

(つか、日本語サイト、誤訳ってない?)

ということで、パスワードなどの秘匿情報をどうしても端末に保存する時は、

  • iOS なら KeyChain を使う
  • Android の場合は独自の暗号化を施す(Mono の SecureString とか ProtectedData が使える?)

などの対策が必要です。

まとめ

  • IsolatedStorage は、SharedPreference や NSUserDefaults の代わりに、「アプリケーション情報格納領域」として使える
    • 本文に書きませんでしたが、アプリ専用領域なので、アプリをアンインストールするとちゃんと消えます
  • ただし、パスワードとかの秘匿情報は保存しちゃダメよ
  • IsolatedStorageSettings が使えたらもっと便利だったが、 System.Windows.dll が必要なのでムリー

ちょっと気になる

に、

分離ストレージは Windows ストア の apps では使用できません。 代わりに、ローカル データとファイルを格納する Windows ランタイム API に含まれる Windows.Storage の名前空間にアプリケーション データのクラスを使用します。 詳細については、Windows Dev センターの” アプリケーション データ “を参照してください。

と書いてある。Windows 8 の Store App だと、IsolatedStorage が使えなくて、代わりに WinRT を使う必要があるらしい。それを考えると、IsolatedStorage を直で使わずに1枚咬ませた方が良さそう。

Xamarin
Android
iOS
C#

published

Ads

Read more!

amay077

Microsoft MVP(Xamarin). フルリモートワーカー. Geospatial Mobile app developer. Love C#.

amay077 amay077