Xamarin Essentials FileSystem can you save async - xamarin

Looking into Xamarin essentials and wondering what the purpose of FileSystem is.
I was looking for something that would load and save a file for me async out of the box.
It looks to me and may be I am not understanding the usage that the only thing that it gives you is a location where to save and load the file and there is no functionality to actually save it for you eg "Old PCLStorage"
is this correct?

All Xamarin Essentials File System Helpers are doing is providing access to two different directories within your app, CacheDirectory and AppDataDirectory and access to the read-only pre-bundled files within application so you do not have to write platform-based code for these locations and do your own DI (or use Forms' DI) to access them...
Once you have the string-based directory location, then you use the normal .Net(Std) file and directory I/O routines. Create/delete subdirectories, create/read/write/delete a file using the async (or not) functions from the .Net(Std) framework or a third-party framework/package. Your choice...
CacheDirectory
The cache directory is a read/write location and it implements access to the "native" platform cache location. On Android this is the Cache
var cacheDir = FileSystem.CacheDirectory;
AppDataDirectory
The app data directory is the "default" location for where regular files should be stored.
As the docs state:
any files that are not user data file
FYI: This is not the place to be used for Sqlite databases and such if you are implementing/complying with platform dependent norms... Why Essentials did not include a database location is unknown to me when platforms like iOS and Android have APIs for them and formally documented locations... ;-/
Application bundled files (read-only)
OpenAppPackageFileAsync provides access (via a Stream) to read-only bundled files in your application (AndroidAssets, BundleResource, etc..)
using (var stream = await FileSystem.OpenAppPackageFileAsync("sushiLogo.png"))
{
using (var reader = new StreamReader(stream))
{
var fileContents = await reader.ReadToEndAsync();
}
}

Related

Xamarin forms Application retains SQLite Database even after App is Uninstall and Installed even after manifest is configures to AllowbackUp to false

I have a offline Xamarin form Application where I save all the data in SQLite for which I am using [praeclarum/
sqlite-net]
and here is how I create My Database
SqlDataStore.CreateSharedDataStore(
Path.Combine(
Environment.GetFolderPath(
Environment.SpecialFolder.LocalApplicationData
),
DataStoreConstants.DatabaseName
)
);
This is how I have configured my Manifest
xmlns:tools="http://schemas.android.com/tools"
tools:replace="allowBackup" android:allowBackup="false"
I am trying to implement a functionality where SQLite Database should get deleted on Application Uninstalling for which I added android:allowBackup="false" still the database and data inside it retrieves after the Application is Uninstalled and installed back
Also I would Appreciate if someone can help me with what would be good approach to keep my database path right now I am using Environment.SpecialFolder.LocalApplicationData
other Options which I can see for path are
// Summary:
// The directory that serves as a common repository for application-specific data
// for the current roaming user.
ApplicationData = 26,
// Summary:
// The directory that serves as a common repository for application-specific data
// that is used by the current, non-roaming user.
LocalApplicationData = 28,
// Summary:
// The directory that serves as a common repository for application-specific data
// that is used by all users.
CommonApplicationData = 35,
Environment.LocalApplicationData maps to INTERNAL_STORAGE/.local/share . allowBackup works only for application specific data.
Xamarin.Essentials has specific APIs to use App specific directory.
Use FileSystem.AppDataDirectory+ "sqlite" to store your SQLite
Xamrin.Essentials.FileSystemHelpers

Getting file inside PCL project always returning null

I am trying to get file which is added in PCL project usin PCLStorgae as below:
IFile file = await PCLStorage.FileSystem.Current.GetFileFromPathAsync("ProjectName.Data.AuthRequest.json");
Above is always returning null. BuildAction is set to Embedded Resource. It is possible to get file inside PCL, but what am I doing wrong here.
Update
Following code working fine without using PCLStorage:
var assem = typeof(Class).GetTypeInfo().Assembly;
Stream stream = assem.GetManifestResourceStream(string.Format("ProjectName.CustomFolder.FileName"));
using (var reader = new System.IO.StreamReader(stream))
{
text = reader.ReadToEnd();
}
Not sure why its returning null with PCLStorage.
PCLStorage is an abstraction over the file system differences of the various native platforms (iOS, Android, Windows etc).
Maybe you found the name of the library misleading? The "PCL" in "PCLStorage" means, it allows you to access the platform specific file systems from within your shared code (PCL). It's not about accessing files that are embedded into a PCL as a resource.
As you already figured out correctly, GetManifestResourceStream() is the correct way to go for embedded resources.

How can I display images from an arbitrary folder in Xamarin Forms on Windows 8

This may be a dead horse, but I need to be able to supply a local folder full of images OUTSIDE my Xamarin application - not as resources, not requiring compilation to add more images - and display those images in the application, in Image objects. My main target platform is Windows 10. Others nice to have, not required.
Xamarin Forms Image normally takes either a File name (no path) or a URI. I can't get either method to locate and display images from the local file system. I must be doing something basic wrong.
Non-working sample:
Image i = new Image();
i.Source = ImageSource.FromFile(some.png); // Needs to be from folder on local disk
grid.Children.Add(i, c, r);
Most articles I find explain how to bundle images WITH the application as part of the source; again I need to display them in the application from a folder WITHOUT bundling them with the application. Users should be able to add more images to the folder and they would work in the app without recompiling/reinstalling - like an image gallery.
EDIT: I am able to successfully read a text file using PCLStorage https://github.com/dsplaisted/pclstorage. Is there a way to wire that to Xamarin forms image?
You would need to write a platform specific class to read the images and return a stream that could be consumed by StreamImageSource. Then you can use DependencyService to expose this behavior to your Forms PCL.
Alternatively, you could use PCLStorage
var f = await FileSystem.Current.LocalStorage.GetFileAsync (path);
Stream s = await f.OpenAsync (FileAccess.Read);
image.Source = ImageSource.FromStream(() => s);
Basically, you can't. If you don't bundle the images with your application, you somehow have to transfer the images to the application. Most common case is that you serve these images on a web server somewhere, where the application downloads the images from that web server.

Refresh resources in Windows Phone 7 app isolated storage

I have a Windows Phone app that relies on an XML data file that comes packaged with the app. When the app is ran the first time on a phone, I load the file into isolated storage. Once the file is loaded into isolated storage, the app uses the isolated storage version of data. In the next version of my app (the Marketplace update), the XML file will have more elements, how do I update the data file once per app update (new version on the Marketplace)?
I thought I could change the file name in the isolated storage, but that would leave trash behind. I could also check for exceptions when I load the XML file, but are there any other, more elegant ways? I do not want to check for the old file in the isolated storage every time my app runs.
The ideal scenario would be to put a piece of code that would be executed once when the new version of the app is loaded onto the phone, is there a way to do that?
To my knowledge there isn't an "out of the box" event that will run a single time at the first run of an app after it was installed/updated.
You'd have to flag the run your self, like you are already stating (save the current version, compare version at each run of the app to see if app was updated!)
I think I now understand what you want.
Add the XML file as a resource.
Use GetResourceStream to get the content of the XML.
Note that the name for the resource would be something like /DllName;component/Folder/ResourceName
Here is what I did:
In the constructor method of my DataLayer class, I added the following code:
private bool AppIsOld
{
get
{
string storedVersion = GetStoredAppVersion(); //stored previously "seen" version
string currentVersion = GetCurrentlyRunningAppVersion();
return !(storedVersion == currentVersion);
}
}
private string GetCurrentlyRunningAppVersion()
{
var asm = Assembly.GetExecutingAssembly();
var parts = asm.FullName.Split(',');
return parts[1].Split('=')[1].ToString();
}
And then I run the following check:
if (AppIsOld)
RefreshResources(); //do whatever to refresh resources
The code for GetCurrentlyRunningAppVersion() function is taken from here.
This solution is not what I had in mind because it runs every time the class constructor is called while I wanted something that would run once upon version update.

Adding files to WP7 isolated storage from Visual Studio?

I'm working on an Windows Phone 7 app where I'm going to show ATM's nere your location with bing maps.
I have an xml-file with addresses and gps coordinates. But how do I add this file to my program from visual studio? If I set BuildAction to Content and Copy to output directory to Copy always. The file still isn't in IsolatedStorage. Do I have to build a mechanism to download the information from the web? Or is there another way?
Files listed as content in the Visual Studio project are copied to the generated XAP file (which is analogous to a ZIP file). They are not copied to isolated storage.
In the case of an XML file, you can call XmlReader.Create with the path to the file as argument, as follows:
using (XmlReader reader = XmlReader.Create("path/to/file.xml"))
{
// read XML file here
}
Or you can also call Application.GetResourceStream and use the Stream property of the returned StreamResourceInfo object:
StreamResourceInfo sri = Application.GetResourceStream(
new Uri("path/to/file.xml", UriKind.Relative));
// read XML file here from sri.Stream, e.g. using a StreamReader object
You cannot directly pass files to the isolated storage at design time. Only when the application is running.
I'd still recommend passing the file to the application through a web service. Mainly because if eventually you will need to change the contents of the XML, you will need to update the application.
What I would do is simply create a WCF service that will return serialized data (or the existing XML) via a simple HTTP request.
The "Mango" SDK ships with the ISETool that can take and restore snapshots of an application's isolated storage to/from a local directory:
# Copy data from IS to directory
ISETool.exe ts xd <PRODUCT-ID> "C:\TempDirectory\IsolatedStore"
# Copy data from IS to directory
ISETool.exe rs xd <PRODUCT-ID> "C:\TempDirectory\IsolatedStore"
If you don't want to overwrite the entire IS, the tool supports an option (device-folder) for specifying a sub-directory to backup/restore.

Resources