I want to be able to pre-configure my Android app to include a json file that is read/writeable, that is usable on other platforms as well (iOS, UWP). I started looking at AssetManager but found that I could only read the file, not edit it later.
Is internal storage the answer? If so, how do I pre-populate the app's internal storage with this file? I couldn't find any documentation online on how to do this besides performing a full write method in C# code, which kind of defeats the purpose of sharing the same config.json file on all platforms. I just want my Android app to store this config.json file, and have the file be readable and writeable.
Any help would be greatly appreciated.
I decided to answer my own question and show how it can be done in code. In this answer, I am using both an Android asset and internal storage to manipulate the file that contains my serialized object.
1) Copy your file into the Xamarin.Android project's Assets folder, and change its Build Action to "AndroidAsset". This will ensure that the file is packaged with your Android app initially.
2) In your C# code, what you really want is to read and write this file from your Android App's internal storage, not from the AssetManager (you can't write to the AssetManager anyways, only read!). So to do this, you must first pull the file from the AssetManager and then all subsequent read/writes will occur from internal storage.
/// <summary>
/// This method will read the application settings from internal storage.
/// If it can't find it, it will use the default AndroidAsset version of
/// the appsettings.json file from this project's Asset folder.
/// </summary>
/// <returns></returns>
public async Task<DefaultSettings> GetDefaultSettingsAsync()
{
var path = Application.Context.FilesDir.Path;
if (File.Exists(Path.Combine(path, "appsettings.json")))
{
using (var sr = Application.Context.OpenFileInput("appsettings.json"))
{
using (var ms = new MemoryStream())
{
await sr.CopyToAsync(ms);
var memoryBytes = ms.ToArray();
var content = System.Text.Encoding.Default.GetString(memoryBytes);
var defaultSettings = JsonConvert.DeserializeObject<DefaultSettings>(content);
return defaultSettings;
}
}
}
else
{
var result = await GetDefaultSettingsAssetAsync();
return result;
}
}
/// <summary>
/// This method gets the appsettings.json file from the Android AssetManager, in the case
/// where you do not have an editable appsettings.json file yet in your Android app's internal storage.
/// </summary>
/// <returns></returns>
private static async Task<DefaultSettings> GetDefaultSettingsAssetAsync()
{
try
{
var assetsManager = MainActivity.Instance.Assets;
using (var sr = assetsManager.Open("appsettings.json"))
{
using (var ms = new MemoryStream())
{
await sr.CopyToAsync(ms);
var memoryBytes = ms.ToArray();
var content = System.Text.Encoding.Default.GetString(memoryBytes);
var defaultSettings = JsonConvert.DeserializeObject<DefaultSettings>(content);
// This will write the Asset to Internal Storage for the first time. All subsequent writes will occur using SaveDefaultSettingsAsync.
using (var stream = Application.Context.OpenFileOutput("appsettings.json", FileCreationMode.Private))
{
await stream.WriteAsync(memoryBytes, 0, memoryBytes.Length);
}
return defaultSettings;
}
}
}
catch (Exception ex)
{
return new DefaultSettings();
}
}
/// <summary>
/// This method will save the DefaultSettings to your appsettings.json file in your Android App's internal storage.
/// </summary>
/// <param name="settings"></param>
/// <returns></returns>
public async Task SaveDefaultSettingsAsync(DefaultSettings settings)
{
using (var stream = Application.Context.OpenFileOutput("appsettings.json", FileCreationMode.Private))
{
var content = JsonConvert.SerializeObject(settings);
var bytes = Encoding.Default.GetBytes(content);
await stream.WriteAsync(bytes, 0, bytes.Length);
}
}