I want to transfer a file to an Android device using a USB cable and file explorer, and then access it in my Xamarin.Forms app.
As far as I understand there are two ways to do this (and please correct me if I'm wrong):
Since it's an image file - Just put it anywhere and let some
background task find it and add it to what seems to be a virtual
folder of Images. And then access it there.
A more general solution - browse to that specific folder.
Both solutions rely on using FileInfos etc. but unfortunately the folder structure is much different than I see using windows explorer - instead of Alarms, Android, etc. which I see on windows explorer - is see cache, config, etc. using C#, and access to some like data is not allowed (I get an exception). I also tried finding information on how I would search for all images on the device, but either it's not as simple as I thought it would be, or I'm using the wrong keywords.
The file will be put there by a user, so it cannot be added to the project's resources.
Xamarin has a nice way to navigate the files in android, using Android.OS.Environment.ExternalStorageDirectory.Pathwhich you can concatenate with your directory/filename so you can save/access data.
If you want to open the android dialog box so the user can find a file in its device, you can take a look at: https://developer.xamarin.com/recipes/android/data/files/selecting_a_gallery_image/
Remembering that you need to add the READ_EXTERNAL_STORAGE permission to your android manifest file and check runtime permissions. Runtime permissions can be easily checked with https://github.com/jamesmontemagno/PermissionsPlugin
Related
File.Exists(filePath); works perfectly inside a console application, but when I do the same thing inside uwp it doesn't detect a file.
I have tried to put breakpoints on various methods and stepped into anything that could give me some information about the issue, but I'm getting no information at all no matter what i try.
Code from UWP app:
string path = #"C:\Users\Name\Desktop\image.jpg";
if (File.Exists(path))
{
ProcessFile(path);
}
else if (Directory.Exists(path))
{
ProcessDirectory(path);
}
UWP:
When it hits File.Exists i get a return value of false, and yes i know for a fact the image is where it is.
Console:
When it hits File.Exists i get a return value of true, then goes onto the called method without any issues.
I'm expecting my code to find a File and pass the filePath into my method called "processFile".
Does UWP applications not have access to files outside of its LocalStorage or is it another issue that I'm not seeing?
UWP does not have direct access to files outside of the application folder and application data folder. That are the only two locations accessible via the System.IO APIs.
You can use StorageFile APIs to access more locations if you enable appropriate capabilities - like access to libraries or broadFileSystemAccess or use file/folder pickers. In particular, broadFileSystemAccess allows you to access the whole file system, but your app should have a good reason to do so (otherwise it will not pass the Microsoft Store certification process).
For more info see the Docs.
This is correct. UWP apps are sandboxed and cannot access files outside of LocalStorage in this way.
If you want to open a file on the users file system you have to use FileOpenPicker.PickSingleFileAsync or similar to prompt the user to pick a file, which you'll then be able to work with.
Further reading: Working with Files in UWP applications
I am making a simple UWP app that takes user input and stores it in an XML file. Eventually I'm going make that into an Open-XML esque file format which I can distribute to different people. I would like an easy way to write to the Documents folder like a normal C# application does. What would be the easiest way to do this. I considered using a sort of 'runner' application that would take command line arguments and write them to the requested folder, but that seems like a bit too much. Is there any other way?
EDIT: LOL after a ton of Googling, I couldn't find it. 5 minutes after I posted this, I found it. You can give this access in the package manifest by adding the following line of code:
<Capabilities><uap:Capability Name="documentsLibrary"/></Capabilities>
EDIT #2: Alternatively you can just use the FileOpenPicker and FileSavePicker
Your app will get rejected by the Windows Store if you include this capability in your manifest:
<Capabilities><uap:Capability Name="documentsLibrary"/></Capabilities>
You must use a FileSavePicker to ask permission from the user to access a certain file on disk. UWP does not allow you to freely roam the user's machine. The only full access you have, is the applications local/temp/roaming storage.
I've been trying to learn how to handle saving normal .txt files in UWP, and have realized that it's quite locked down compared to WPF, especially in the sense of what folders you can access without requesting the user to select a location. I have searched for various ways this might be possible but found no working answer.
Question Description:
I basically would love to know if this is possible, and preferably a point in the direction where I can learn how exactly to do this.
Application settings page requires user to select folder where files are saved.
Application remembers this between launches (unsure if this is possible, but I can't require the user to select the folder on every launch)
Application saves files to the specified folder.
In my understanding, this should be possible, as the user is the one specifying the location via filepicker, but is it possible to have this work between launches so that the user wont be required to re-select the save folder?
I need to figure this out, as I would like my application to support selecting attached network drives, cloud storage folders, etc.
Any help is very much appreciated, and if there are any questions I will answer them to the best of my ability.
Fow this purpose there are two access lists designed: FutureAccessList and MostRecentlyUsedList. Once the user has picked up the folder with the picker, you add it to such list and receive a token, which you save for future purpose in LocalSettings:
ApplicationData.Current.LocalSettings.Values["MyFolder"] = StorageApplicationPermissions.FutureAccessList.Add(pickedFolder);
Then later, once you want to access that folder, you can do it like this:
StorageFolder folder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync(ApplicationData.Current.LocalSettings.Values["MyFolder"].ToString());
You can't save a StorageFolder or a path to it in settings, hence the UWP app needs permissions to access the folder. Using above access lists solves this problem.
I believe you want to save user settings and keep it somewhere so that next time when they launch the application, they can use the same settings.
Please check out this tutorial from Microsoft, which describes how to do exactly that.
https://msdn.microsoft.com/en-us/library/bb397750(v=vs.110).aspx
I am currently attempting to read in files (that the user selects) and store them (with their permission). The trouble I am having is that, having SkyDrive installed and enabled, I have what are known as SMART files, noted with a LocallyIncomplete attribute.
What this means is that the SkyDrive app stores a reference to this file in SkyDrive, but does not actually pull the whole file until the user requests it (by using it in some way). This works totally fine if they access the file in the picker via the SkyDrive app (the drop down at the top left). It even marks those that are not completely offline as LocallyIncomplete while not marking those that are available offline.
The issue (that I was lucky enough to find) is that I have included a folder in my SkyDrive app inside of a library (specifically, my Documents library). This makes all of the files show up in the picker, as it should.
If I try and open any SkyDrive files from the library, then not only does it mark all of them as LocallyIncomplete (even when the SkyDrive app does not), but it throws a native IOException, which is impossible for my app to catch. This happens even if the file being requested is locally available through the SkyDrive App. This is consistently reproducible on my machine.
Upon further investigation, it seems that I can check the Provider property to make sure that files with the LocallyIncomplete attribute come from the SkyDrive app, which is good at least (in that I can avoid an uncatchable exception). This will work for now as a Workaround, but it's less than ideal.
Also, I haven't been able to find any mention of this on Connect/MSDN. I'm hoping a MSFT-y wouldn't mind double checking to see if there's a bug filed for this before I file one myself, as I haven't been able to find one.
Thanks.
LocallyIncomplete means the file is not 100% downloaded to the user's machine.
You can check this way
if (!file.Attributes.HasFlag(FileAttributes.LocallyIncomplete))
{
//dostuff
}
where file is of type StorageFile
I would like to know how Windows generate folder, where will be ClickOnce application installed.
In Startmenu is "shortcut" to file, what is putted in some "startrek" folder like:
C:\Users\USERNAME\AppData\Local\Apps\2.0\GT??4KXX.PRJ\EGV???1G.??C\prin..tion_7???5a2?????74b6_0000.0002_1dae????89111c35
What does those folder names mean?
For example:
If i will have for example some settings.txt file where i want that user can change some parameters of the application. Is there way how to know, WHERE it will be installed and WHERE the file is? (Where user will find this settings.txt file).
I know that i can create the file for example in C:\ and after start the application i will modify the file in "strong" path. But i dont really like too much files, folders, whatever in C:\ and i prefer to have settings files in same folder like the application. But with ClickOnce installations is it really hard - impossible - to find that file.
It seems like when the "startrek" is something like hash of the project.
So i would like to know what does the folder means and if its some hash of the project or what is that.
To find the folder that contains your executable, you can use the Assembly.Location property.
For example:
string exeFolder = System.Reflection.Assembly.GetExecutingAssembly().Location;
However, if you want to store settings for your ClickOnce app, you shouldn't do it by writing a file to the .exe's folder.
Instead, you should use Microsoft's Application Settings support. Doing it any other way is going to be a lot of extra hassle, and Microsoft's support is very good. It does need half an hour to read through the documentation, but it's far and away the best thing to do, IMHO.
(I'm assuming that you only need the settings to be stored on the local PC for the same user to use later. If you want the settings to follow the user around (i.e. roaming settings), you can't use the Microsoft support.)
If you have more complex settings that you want to store in a file that you create directly, you should consider using the isolated storage that the answer from JRoughan mentions.
From inside the ClickOnce app you can find the default directory where files are stored using
ApplicationDeployment.CurrentDeployment.DataDirectory
Or you can use isolated storage and choose whether you want to save per application or per user.
I don't think it's possible to determine these folders from outside the app itself. If you need a known location you'll have to hard-code it.
Update
I also don't believe it's possible to infer what the install directory will be for an app. It would be unwise to use even if possible as updates to the app will not be in the same location.
If you have data that the user is modifying through your program, you will be happier if you don't leave it in the ClickOnce program directory. You can get completely messed up when there's an update. Check out this article about what to do with your data to keep it safe and be able to find it. It talks about putting it in LocalApplicationData, but if you want your user to be able to find it and edit it, just put it in MyDocuments/yourappname/settings or something like that.
I wouldn't use Isolated Storage; there are reported problems with that and ClickOnce.