Xamarin.Android : Deserialize a file in ApplicationData? - android

I'm storing user data in ApplicationData folder. Its path is obtained with :
userDataPath = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), "userData");
This variable is equal to /data/user/0/APPNAME/files/.config/userData.
Each time I rebuild the project, if I delete the userData file with File.Delete(userDataPath), I can successfully create the file, write and read to it several times. I can indeed check the created file in /data/data/APPNAME/files/.config/userData.
I check in /data/data/.../.config/userData and not in /data/user/.../.config/userData because apparently the latter is a symlink to the former, so it should be equivalent ? Moreother I don't have access to /data/user/.../.config/userData.
The problem is that if I rebuild the app without deleting the file, I got an unhandled exception at the following Deserialization (which worked fine before) :
if (File.Exists(userDataPath))
{
Stream reader = new FileStream(userDataPath, FileMode.Open);
Console.WriteLine(userDataPath);
userData = (UserData)serializer.Deserialize(reader); // ERROR HERE
reader.Close();
}
It is very strange because the file located at /data/data/APPNAME/files/.config/userData does not exist but since File.Exists(userDataPath) is true, the file located at /data/user/0/APPNAME/files/.config/userData does exist.
So how can this be explained and is this the correct way to store data in ApplicationData folder ?

After switching to another SpecialFolder (LocalApplicationData), I can't reproduce the unhandeld exception anymore (even when switching back to ApplicationData).
I'll keep this post updated if it ever happens again.

Related

Xamarin.essentials FilePicker copies selected external file to cache folder

For the last 2 weeks I've been successfully converting a WPF application to a Xamarin.forms android app. Everything works as intended except for 1 thing. I've been searching the web for a few days for a solution but I can't find a working solution.
This is my current setup:
Xamarin.Froms android app
Target android version: Android 10.0
Minimum android version: Android 7.0
Xamarin.Essentials version: 1.6.0
READ_EXTERNAL_STORAGE permission
WRITE_EXTERNAL_STORAGE permission
My app should be able to open a selected file, using the Xamarin.Essientials FilePicker, Do some stuff and save the File again to the same path. The file selection is handled in the following code:
var pickresult = await FilePicker.PickAsync();
if (pickresult != null)
{
try
{
var result = await pickresult.OpenReadAsync();
var reader = new StreamReader(result);
var jsonstring = reader.ReadToEnd();
ConfigData = JsonConvert.DeserializeObject<ProjectData>(jsonstring);
PLC_Data.ProjectLoaded = true;
L_LoadedProject.Text = pickresult.FileName;
ProjectData.Filepath = pickresult.FullPath;
reader.Close();
result.Close();
//Load login page
B_Next.IsEnabled = true;
}
This is where the problem occurs. Let me clearify what happens step by step:
The FilePicker opens a File picking window.
I navigate to my preferred file in the "download" folder, could be any folder.
The file is read and converted to an object
The file path is saved
when i check the filepath i get the following string:
"/storage/emulated/0/Android/data/com.FAIS.motorconfigapp/cache/2203693cc04e0be7f4f024d5f9499e13/303bc84665374139b6303c03255e9018/config1.json"
So the FilePicker copies the "External" file to the App cache folder and returns the filepath from the Apps cache folder. When i check this folder there is indeed a copy of my selected file inside it. Reading from and writing to this file works as it should.
Now the actual question:
Why does the FilePicker copy my selected file to his cache folder and how can i prevent it?
The user should be able to select a file from anywere on the device and find the updated file in the same location.
I've checked all my settings and in my opinion everyting should be correct so i don't get why a copy is created. Does anyone have an idea?
If you need more settings, pictures, versions please ask.
Thanks in advance

How do i copy a Json file from the Assets/Resources/ to the Internal storage of an Android device ( persistent data)? [Unity Android]

I want to copy a single json file from Unity's Assets/Resources/ directory to the internal persistent memory of Android device (INTERNAL STORAGE/Android/data/<packagename>/files/) only once at the start of the game. I looked up all over the internet, with solutions saying to use Streaming assets and UnityWebRequests or WWW class which is obsolete now. I tried everything for hours now. And did not find a exact solutions, but only got null references and directory not found.
I added my json file to the <UnityProject>/Assets/Resources/StreamingAssets/, but it doesn't seem to detect any streaming assets. I understand an apk is a zip file and so I can only read the contents of streaming assets, but my I can't find a solution to this.
Once I get my json from streaming asset, I can finally add it to Application.persistentDataPath.
UPDATE
I had actually figured it out,
public void LoadFromResources() {
{mobilePath = "StreamingAssets/"; mobilePath = mobilePath + "stickerJson" + ".json";
string newPath = mobilePath.Replace(".json", "");
TextAsset ta = Resources.Load<TextAsset>(newPath);
string json = ta.text; Debug.Log(json); System.IO.File.WriteAllText(Application.persistentDataPath + "/stickers.json", json);
}
}
To copy a file you only need to have the information of the file and then create a new one in another place.
So if you got your json file into your Resources directory you can retreive like the documentation say:
//Load text from a JSON file (Assets/Resources/Text/jsonFile01.json)
var jsonTextFile = Resources.Load<TextAsset>("Text/jsonFile01");
//Then use JsonUtility.FromJson<T>() to deserialize jsonTextFile into an object
Then you only have to create your android file in your persistentDataPath as #Iggy says in the comments doing:
System.IO.File.WriteAllText(Path.Combine(Application.persistentDataPath, "file.txt"), jsonTextFile);
Note: Not really sure, but for other cases I think that StreamingAssets folder should be inside Assets, no inside Resources.

Can't create an SQLite table on Android

I have been following this tutorial in its entirety, on how to store data in a local database. On iOS everything works fine, unfortunately on android i get an exception upon creating a table in my database file. The method for creating the table is:
public CalcDatabase(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<Calculation>().Wait();
}
And my custom class for getting the database path on Android is as follows:
public class LocalFileHelper : IFileHelper
{
public string GetLocalFilePath(string filename)
{
var path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
path = Path.Combine(path, filename);
if(!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
return path;
}
}
This is the error that im getting from SQLite:
Could not open database file: /data/user/0/com.companyname.XX/files/Calculation.db3 (CannotOpen)
I have tried targeting several different APIs, I have tried to clean and rebuild my solution, and I have tried to reinstall the SQLite-net-pcl NuGet packages across the whole solution. Nothing works.
I have read, that it has to do with permissions, still, I do however find it strange that the official Microsoft tutorial doesn't cover this if it was a thing.
You need to check out the Android Permissions declaration (and grants) for Write and Read to external storage on your device or emulator.
It must be enough.
Make sure to delete bin and obj folders, clean and rebuild solution to get rid of any cached data on app compilation.

(Ionic) Cordova-file-plugin error when trying to read file

So, I'm currently trying to read an Audio file I just saved on the App's directory (Android) through the cordova file-plugin, but I keep getting the same error code 5, which stands for "ENCODING_ERR".
This is how I create the file and start recording
start() {
this.filename = this.file.externalDataDirectory.replace(/file:\/\//g, '');
this.mediaobject = this.media.create(this.filename + 'audioprofile' + '.3gp');
this.mediaobject.startRecord();
}
This is how I stop recording and save the file
stop() {
this.mediaobject.stopRecord();
this.mediaobject.release();
...
And this is where I'm stuck: right after saving it, I need to have it as a String, so I'm try to read it ( alert(content) should show me that string)
stop() {
this.mediaobject.stopRecord();
this.mediaobject.release();
this.storage.get("uid").then((id) => {
try{
this.file.readAsDataURL(this.filename,'audioprofile'+'.3gp').then((filecontent)=>{
alert(filecontent);
},(err)=>{
alert(err.code);
})
} `
After some research I found out it PROBABLY means I'm not giving the right path for it, but I've tried everything, any combinations of 'filename' and 'filepath' were made, even adding the prefix removed on start().
I want to know if someone managed to read a file with this cordova plugin and if you did, please help me out.
Thanks in advance, this is my first post here \o/ (although I've always used the website, love u guys).
i had the same problem. I solved it giving this path:
this.media.create(this.file.externalDataDirectory + this.nameFile);
I dont know why but this.file.readAsDataURL cant read the file if u save it deleting /file:
Remember change the path in all your methods.
Well i managed to do this with the File-Path Plugin, it resolves the Path for your file in a way the File Plugin understands and is able to reach the file, then you just have to manipulate it the way you want.

Files are getting deleted from the SD card

I have developed a Service which will start when I receive the "ON_BOOTUP_COMPLETED" intent,
in "onCreate" of my Service I wrote the logic to create a text file in SD card of the device.
Below is the logic I have used to do so:
File abc = new File(Environment.getExternalStorageDirectory()+"\abc.txt");
if(!abc .exists())
abc.createNewFile();
abcwriter = new FileWriter(abc);
I am using "abcwriter" in other methods to write some content in to text file.
So far it is working fine.
But when rebooted the device, I observed that "abc.txt" file is creating again.
but I put a check before creating file "if(!abc .exists())". But still new file is created.
I suspect that when I rebooted the device my files are deleted. Is this the android behaviour..??
If it is please help me what I can do to make sure my files not created again.
You have to use the constructor below and pass true as the second parameter if you want to append to the file. Otherwise it will just get overwritten each time your code runs (when you reboot).Also get rid of the createNewFile() call, you don't need it since the writer will create it.
FileWriter(File file, boolean append)
abcwriter = new FileWriter(abc); -> this line (re)creates the file.
Make sure it's called only when needed:
File abc = new File(Environment.getExternalStorageDirectory()+"\abc.txt");
if(!abc.exists()) {
// abc.createNewFile(); -> this is not needed since following line handles this
abcwriter = new FileWriter(abc);
}

Categories

Resources