Cross-platform preferencies

VitalyVitaly Vitaly ChernikovRUMember

Hi Xamarin users ! We need suggestion about cross platform user's preferences saving technique. As we know there no cross method to save preferences. So how do you suggest to make: Or we should write abstract interface and then implement it for NSUserDefaults on iOS and SharedPreferencies on Android. Or we may write class for saving preferences to JSON object and then save it to app sandbox text file (with getting cross platform directory). Second way seems to easy and flexible (becuse wee need storage two-dimensial array too). So what do you suggest and what troubles may be for both ways? Thanks In Advance!

Posts

  • JonathanPryorJonathanPryor Jonathan Pryor USModerator, Xamarin Team Xamurai

    we may write class for saving preferences to JSON object and then save it to app sandbox text file

    Along those lines, you could use JSON along with System.IO.IsolatedStorage, which should be portable damn near everywhere (except Windows 8)...

  • VitalyVitaly Vitaly Chernikov RUMember

    Is this right I understand that IsolatedStorageSettings of System.IO.IsolatedStorage is only for Silverlight version. And that for Mono android | iOS I should use own txt file and save it in System.IO.IsolatedStorage?

  • JonathanPryorJonathanPryor Jonathan Pryor USModerator, Xamarin Team Xamurai

    I understand that IsolatedStorageSettings of System.IO.IsolatedStorage is only for Silverlight version.

    That is correct: IsolatedStorageSettings is not provided in our System.IO.IsolatedStorage namespace.

    And that for Mono android | iOS I should use own txt file and save it in System.IO.IsolatedStorage?

    You don't have to use System.IO.IsolatedStorage; it's just convenient. :-)

  • VitalyVitaly Vitaly Chernikov RUMember

    It is sadly that IsolatedStorageSettings is not available. Will try to use IsolatedStorageFile. As I realize when I call

    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    // Use a StringBuilder to construct output.
                    StringBuilder sb = new StringBuilder();
    
                    // Create three directories in the root.
                    store.CreateDirectory("MyApp1");
                }
    

    Mono internally already somehow gets Application sandbox folder path in relation of platform (iOS, Android)

  • VitalyVitaly Vitaly Chernikov RUMember
    edited March 2013

    Continue to work with isolatedStorage. Task is to copy file from assets to specific directory of app sandbox. Starts try first on Android app (then will try on iOS).

    1) Create directory on sandbox:

    var store = IsolatedStorageFile.GetUserStoreForApplication ();
    string reportPath = Path.Combine ("reports", "id40100");
    if (!store.DirectoryExists(reportPath))
    {
    store.CreateDirectory(reportPath);
    }
    

    Waiting to get /data/data/BeginnerAndroid.BegiinnerAndroid/files/reports/d40100

    2) Try to copy file from ASSETS

    ASSETS: ZIP/id40100.zip to /data/data/BeginnerAndroid.BegiinnerAndroid/files/reports/d40100/id40100.zip

    string fileEndPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal) 
    + "reports/id40100/id40100.zip";
    byte[] buffer = new byte[8096];
    int len = 0;
    try
    {
        using (var sr = (Application.Context.Assets.Open(assetFilePath)))
    {
    
    var fsr = new FileStream(fileEndPath, FileMode.OpenOrCreate);
    while ((len = sr.Read(buffer, 0, 8096)) > 0)
    {
        fsr.Write(buffer, 0, len);
    }
    
       fsr.Flush();
       fsr.Close();
       sr.Close();
    }
    
    if (!File.Exists(fileEndPath))
    {
    return false;
    }
    }
    catch (Exception e)
    {
    return false;
    }
    

    But when I try FileStream(fileEndPath,...) there got error that Not found part of path /data/data/BeginnerAndroid.BegiinnerAndroid/files/reports/d40100/id40100.zip

    So else I found that IsolatedStorageFile contains non-publish property "directory" that is "/data/data/BeginnerAndroid.BeginnerAndroid/files/.config/.isolated-storage" but when I get Environment.GetFolderPath (Environment.SpecialFolder.Personal) to copy file from assets it returning "/data/data/BeginnerAndroid.BegiinnerAndroid/files/" so may be file getting not found because of directories are different?

  • VitalyVitaly Vitaly Chernikov RUMember
    edited March 2013

    So, it is was right, indeed when i try this

    var basePath =  Environment.GetFolderPath (Environment.SpecialFolder.Personal);
    Path.Combine(basePath, ".config/.isolated-storage")
    

    all errors avoid.

    So

    var store = IsolatedStorageFile.GetUserStoreForApplication ();

    and

    Environment.GetFolderPath (Environment.SpecialFolder.Personal)

    operates with separate paths that different is /.config/.isolated-storage.

    Remain problems that I need manualy create path

    var basePath =  Environment.GetFolderPath (Environment.SpecialFolder.Personal);
    Path.Combine(basePath, ".config/.isolated-storage")
    

    because

     var store = IsolatedStorageFile.GetUserStoreForApplication ();
    

    do no have method to get base directory like this

     var s = store.GetBaseDirectory();
    

    where s will

     "/data/data/BeginnerAndroid.BeginnerAndroid/files/.config/.isolated-storage"
    
  • SridharanSrinivasanSridharanSrinivasan Sridharan Srinivasan SGMember
    edited March 2013

    why are you mixing Isolated Storage with basic .NET IO. If you use IsolatedStorage, then you should never worry about Path??

    cannot you do something like this??

    string reportRelativePath = Path.Combine ("reports", "id40100");
    string fileRelativePath = Path.Combine(reportRelativePath , id40100.zip);
    byte[] buffer = new byte[8096];
    int len = 0;
    
    using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
    {
         if (!store.DirectoryExists(reportPath))
         {
            store.CreateDirectory(reportPath );
         }
    
         using (var sr = (Application.Context.Assets.Open(assetFilePath)))
         {
         using (Stream fs = new IsolatedStorageFileStream(fileRelativePath, FileMode.Create, store))
         {
             StreamWriter w = new StreamWriter(fs);
    
             while ((len = sr.Read(buffer, 0, 8096)) > 0)
             {
                 w.Write(buffer, 0, len);
             }
    
             w.Flush();
          }
          }
     }
    

    Have not compiled the above, just typed it in after extracting some info from my projects.

    I am currently using encrypted json to store my settings/db/media etc (initial copy from Asset in Android and from Bundle Resources in IOS - Can also use embedded Resources for both Android/IOS) using plain file IO

      string appDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
    

    Isolated Storage may have some restrictions on Quota which may need to be managed?? but it should be ok for cross platform json settings file.

  • VitalyVitaly Vitaly Chernikov RUMember

    So there else question rising: If I will copy files to IsolatedStorage directory how can I will get absolute file path to use it in WebView?

    Now I use

    WebView.LoadDataWithBaseURL("file:///android_asset/Content/", data, "text/html", "UTF-8", "");
    WebView.LoadDataWithBaseURL("/data/data/BeginnerAndroid.BeginnerAndroid/files/content/", data, "text/html", "UTF-8", "");
    
    But I think I should get such path now
    WebView.LoadDataWithBaseURL("/data/data/BeginnerAndroid.BeginnerAndroid/files/.config/.isolated-storage/content", data, "text/html", "UTF-8", "");
    

    Or for this case IsolatedStorage is imposible way for me?

  • VitalyVitaly Vitaly Chernikov RUMember
    edited April 2013

    When you want to load local HTML with WebView.LoadURL(/data/data/..../content/local.html) so absolute path is some times required and there no able to get it with isolatedStorage class.

  • JonathanPryorJonathanPryor Jonathan Pryor USModerator, Xamarin Team Xamurai

    Or for this case IsolatedStorage is imposible way for me?

    This is not supported by IsolatedStorage, by design, as IsolatedStorage was intended to be used in "sandboxed" environments and allowing the sandboxed app access to the full path would be considered to be a vulnerability (e.g. it makes it easier to grab a path, throw in ..\..... components to bypass path validation, and open up the machine to the "sandboxed" app...).

    If you need access to full path information -- which you do -- then don't use IsolatedStorage. Use System.IO and Environment.GetFolderPath(Environment.SpecialFolder.Personal).

  • FloydGamesFloydGames Florian Kaiser USMember

    You can just use: https://github.com/mono/moon/blob/master/class/System.Windows/System.IO.IsolatedStorage/IsolatedStorageSettings.cs.

    Don't forget to add "System.Runtime.Serialization" to your references.

  • CetonJoshCetonJosh Josh Clay USMember ✭✭

    I am using mvvmcross in my applications. This might be looking into for you even for just the plugins, but I have a custom plugin for settings: https://github.com/ceton/Mvx.Plugins.Settings

    Basically i use all native preferences saving for Android/WindowsPhone/WindowsStore and then use a JSON file for iOS

    The important thing for me was to use SharedPreferences in Android because you can easily use the preference activity with the xml files.

Sign In or Register to comment.