Does Application.Current.Properties support persistent storage?

SteveMacdonaldSteveMacdonald CAUniversity, Certified XTC Partners ✭✭

I've seen various bits of information suggesting that Xamarin Forms 1.3 has built-in persistent property storage, however I've not been able to get any formal documentation, examples, or even confirmation that this is true in the first place.

So is that a capability, or not?

Thanks!

Posts

  • FredrikHaglundFredrikHaglund SEUniversity, Developer Group Leader ✭✭

    The Application.Properties dictionary is serialized to a file (named PropertyStore.forms on iOS).

    Read more here:
    http://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/app-lifecycle/#Properties_Dictionary

  • SteveMacdonaldSteveMacdonald CAUniversity, Certified XTC Partners ✭✭

    Thanks Fredrik.

    So the values stored in the PropertyStore aren't actually persisted "permanently", correct? They only exist as long as the app remains alive. If I completely close the app these values are lost. So the intent is to preserve values when the app sleeps, no?

  • FredrikHaglundFredrikHaglund SEUniversity, Developer Group Leader ✭✭

    No, all values in the name-value dictionary are serialized to disk every time when the application goes to sleep. They are read back when the application is loaded again.

    On iOS the actual file location is /Documents/.config/.isolated-storage/PropertyStore.forms inside the Application Sandbox. As far as I can understand everything in Documents will be in backup so the file and settings should even survive a move to a new device. Read more: http://developer.xamarin.com/guides/ios/application_fundamentals/working_with_the_file_system/

    Be aware though that all values in the dictionary are serialized to one single file. If you add your own types to the dictionary it will work fine but you take the risk to get a deserialization exception if you change your types. In that case all values are cleared and you will get an empty dictionary.

    I think one intention with the Application.Properties-dictionary is to preserve state when an application goes to sleep so you can take the user back to the same location when it starts again if the process is killed.

  • BenkoBenko USMember ✭✭

    It seems like this works on iOS but is inconsistent on Android. Does anyone have more information about Persisting Properties for Android?

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @MikeBenkovich, @SteveMacdonald, @FredrikHaglund:

    I have tested the new 1.4 - it seems to work now (if the properties are stored explicit with the new method) see also my posting in thread:

    https://forums.xamarin.com/discussion/34359/xamarin-forms-1-4-0-pre1-released/p2

  • ZaduddaZadudda INMember ✭✭

    You. must call LoadApplication method from Android Platform before using Appliation.Current.Properties.

  • RodjaTrappeRodjaTrappe DEBeta ✭✭

    You could also try our SimpleStorage wrapper around the native property implementations. It's available via NuGet https://www.nuget.org/packages/SimpleStorage/ and can be forked on GitHub: https://github.com/perpetual-mobile/SimpleStorage.

  • here it is the documentation, maybe it's quite late to answer the original question but for anyone that reach this forum might be useful https://developer.xamarin.com/guides/xamarin-forms/working-with/application-class/

  • voidstreamvoidstream FRMember ✭✭✭
    edited December 2016

    @benko @SteveMacdonald

             private void SaveConnectionData(JSON.Connection C)
                        {
                            App.Current.Properties[Cryptography.Encryption("AccessToken")] = Cryptography.Encryption(C.Access_token);
                            App.Current.Properties[Cryptography.Encryption("ExpiresIn")] = Cryptography.Encryption(C.Expires_in.ToString());
                            App.Current.Properties[Cryptography.Encryption("TokenType")] = Cryptography.Encryption(C.Token_type);
                            App.Current.Properties[Cryptography.Encryption("Scope")] = Cryptography.Encryption(JsonConvert.SerializeObject(C.Scope));
                            App.Current.Properties[Cryptography.Encryption("RefreshToken")] = Cryptography.Encryption(C.Refresh_token);
                            App.Current.SavePropertiesAsync();
                        }
    

    Work's for me, data stay whereas app shutdown/restart
    For android, you should active this on Visual Studio:
    Tools => Options => Xamarin => Android => Check "Preserve application data/cache on device between deploys"

  • yes @TonyPinot it works fine

  • SmartmanAppsSmartmanApps AUMember ✭✭✭

    @TonyPinot said:
    Tools => Options => Xamarin => Android => Check "Preserve application data/cache on device between deploys"

    Tried this but didn't work for me (so will have to do it the long-hand way). Maybe has a minimum version of Android that it works with?

  • voidstreamvoidstream FRMember ✭✭✭

    @SmartmanApps said:

    @TonyPinot said:
    Tools => Options => Xamarin => Android => Check "Preserve application data/cache on device between deploys"

    Tried this but didn't work for me (so will have to do it the long-hand way). Maybe has a minimum version of Android that it works with?

    Do you have add this after your code?

    App.Current.SavePropertiesAsync(); 
    
  • BrentThompsonBrentThompson USMember

    This doesn't seem to be working at all.

  • EduardoThiagoEduardoThiago USMember ✭✭

    @BrentThompson Remember we should NOT try to save a class directly using this method, but only primitive types, as mentioned in the App class documentation

    For example, if we have this class:

    class Person {
        public String Name {get;set;}
        public int Age {get;set;}
    }
    
    Person p = new Person();
    p.Name = "MyName";
    p.Age = "20";
    

    So we can't try to do this:

    // WRONG MODE
    App.Current.Properties.Add("savedProp", p);
    App.Current.SavePropertiesAsync();
    

    Instead, we must to use this correct way:

    // CORRECT MODE
    App.Current.Properties.Add("savedPropA", p.Name); 
    App.Current.Properties.Add("savedPropB", p.Age);
    App.Current.SavePropertiesAsync();
    

    Each saved property MUST BE ONLY primitive type like String or Int32.

    Otherwise our code will compile and run, without any apparent error or exception, it will write and read the values while the app is running, giving us the impression everything is ok, but will NOT persist data between app stop / new run.

  • EduardoThiagoEduardoThiago USMember ✭✭

    @voidstream what is this Cryptography library you are using?

  • voidstreamvoidstream FRMember ✭✭✭
    edited June 2017

    @EduardoThiago said:
    @voidstream what is this Cryptography library you are using?

    Nothing, I just anticipate in my code, sorry! But if you have idea!

        static public class Cryptography
        {
            static public string Encryption(string text)
            {
                return text;
            }
            static public string Decryption(string text)
            {
                return text;
            }
        }
    
  • EduardoThiagoEduardoThiago USMember ✭✭

    @voidstream here it is (I found somewhere and tested, it works fine)! Just replace the first line with your secret criptkey and have fun! You can change the EncryptionKey byte array too, if you want, but not necessarely.

    public static class Cryptography
        {
            private const string cryptkey = "1234abcdwhatever";
            public static string Encrypt(string clearText)
            {
                string EncryptionKey = cryptkey;
                byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
                using (Aes encryptor = Aes.Create())
                {
                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                        {
                            cs.Write(clearBytes, 0, clearBytes.Length);
                            cs.Close();
                        }
                        clearText = Convert.ToBase64String(ms.ToArray());
                    }
                }
                return clearText;
            }
            public static string Decrypt(string cipherText)
            {
                string EncryptionKey = cryptkey;
                cipherText = cipherText.Replace(" ", "+");
                byte[] cipherBytes = Convert.FromBase64String(cipherText);
                using (Aes encryptor = Aes.Create())
                {
                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                        {
                            cs.Write(cipherBytes, 0, cipherBytes.Length);
                            cs.Close();
                        }
                        cipherText = Encoding.Unicode.GetString(ms.ToArray());
                    }
                }
                return cipherText;
            }
        }
    
  • JassimRahmaJassimRahma USMember ✭✭✭

    @EduardoThiago I have a question please

    so you mean I should use:

    **App**.Current.Properties.Add("CustomerID", loginuserdata[0].customer_id);

    and not:

    **Application**.Current.Properties["CustomerID"] = loginuserdata[0].customer_id;
    
  • JassimRahmaJassimRahma USMember ✭✭✭
    edited November 2017

    because:

    Application.Current.Properties["CustomerID"] = loginuserdata[0].customer_id;

    doesn't seem to be working and every time I close the app data will be lost on both iOS and Android

  • EduardoThiagoEduardoThiago USMember ✭✭

    Yes @JassimRahma, thats correct. Use it this way, and dont forget to call App.Current.SavePropertiesAsync(); in the end to persist the data between each app execution.

  • JassimRahmaJassimRahma USMember ✭✭✭

    What about calling checking the value?

    Shall I use:

    Application.Current.Properties["id"]

    as described here:

    https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/application-class/#Properties_Dictionary

    or I should also use:

    App.Current.Properties["id"]

  • BalakrishnanSBalakrishnanS USMember ✭✭

    Hi
    Where you are storing the Cryptography key, if you are storing in Class file then we can decompile and get the key right?

    How to handle this.
    Balakrishnan

    @EduardoThiago said:
    @voidstream here it is (I found somewhere and tested, it works fine)! Just replace the first line with your secret criptkey and have fun! You can change the EncryptionKey byte array too, if you want, but not necessarely.

    public static class Cryptography
        {
            private const string cryptkey = "1234abcdwhatever";
            public static string Encrypt(string clearText)
            {
                string EncryptionKey = cryptkey;
                byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
                using (Aes encryptor = Aes.Create())
                {
                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                        {
                            cs.Write(clearBytes, 0, clearBytes.Length);
                            cs.Close();
                        }
                        clearText = Convert.ToBase64String(ms.ToArray());
                    }
                }
                return clearText;
            }
            public static string Decrypt(string cipherText)
            {
                string EncryptionKey = cryptkey;
                cipherText = cipherText.Replace(" ", "+");
                byte[] cipherBytes = Convert.FromBase64String(cipherText);
                using (Aes encryptor = Aes.Create())
                {
                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                        {
                            cs.Write(cipherBytes, 0, cipherBytes.Length);
                            cs.Close();
                        }
                        cipherText = Encoding.Unicode.GetString(ms.ToArray());
                    }
                }
                return cipherText;
            }
        }
    
  • EduardoThiagoEduardoThiago USMember ✭✭

    @BalakrishnanS it depends on your specific use case. In the example the string is a static one, but you may need to change it your way.

    You could store it in a secured remote database like Firebase for example, or use phone number or phone mac address as your crypt key, or even ask the user for a secret phrase each time it needs to use the app, in a more critical situation. This encryption method is pretty simple and easy to use, but maybe not the most recommended in more advanced security scenarios.

    This topic covers application properties storage, supposing you want to store user preferences and other non-sensitive data. If you need to store security sensitive information in your app, I recommend you try to search for other security mechanisms that involves more than just isolated string encryption. Hope it helps, have a nice day.

  • BalakrishnanSBalakrishnanS USMember ✭✭

    Thanks for the reply... I am looking for any other security mechanism, please update me if you find anything.

    @EduardoThiago said:
    @BalakrishnanS it depends on your specific use case. In the example the string is a static one, but you may need to change it your way.

    You could store it in a secured remote database like Firebase for example, or use phone number or phone mac address as your crypt key, or even ask the user for a secret phrase each time it needs to use the app, in a more critical situation. This encryption method is pretty simple and easy to use, but maybe not the most recommended in more advanced security scenarios.

    This topic covers application properties storage, supposing you want to store user preferences and other non-sensitive data. If you need to store security sensitive information in your app, I recommend you try to search for other security mechanisms that involves more than just isolated string encryption. Hope it helps, have a nice day.

Sign In or Register to comment.