Opening files in Xamarin.Forms
Do you want your app to receive files from other applications?
Let’s set a practical example: I built a simple markdown viewer in Xamarin.Forms and what I wanted my app to do was to show up in the available options when a
.md file were about to be opened. This is a pretty straightforward task when developing platform specific projects… but when using Xamarin.Forms you may not know where to start, to be honest, I wasn’t.
First fo all, remember that all Xamarin.Forms apps are nothing but native apps, there is no magic regarding them. They all start in the same point whether it is a MainActivity for Xamarin.Android, an App.xaml for Windows Phone or an AppDelegate form Xamarin.iOS and when dealing with incoming files the same applies. So, with that in mind, let’s start.
Let’s create a sample application that will show the name and content of the received file, just create class to hold the data, for this sample it’ll only contain a
Content property, but you can extend it later to fit your needs.
Next, create a page (in this sample
FilePage.xaml) with two labels (for the file name and file content), give them a name and add the next method in the code behind:
Then, in your Forms app starting point (generally App.cs) create a property of type IncomingFile, don’t just use an autoimplemented property, create a backing field for it. Somewhat like this:
Notice how everytime the IncomingFile property is modified, the method
FilePage is called. We will be using this property to set the file from within each platform code. So, let’s dive right into it.
I’ll start with Windows 8.1, since it was my main target with MrkViewer, check the getting started on how to create a Windows App for more info. I won’t cover Windows Phone or UWP apps because they are similar to Win 8.1.
First of all: you must create a file association inside your application manifest, double click the
appxmanifest file, a window will open, from there select the Declarations tab and using the dropdow list select
File Type Associations and click add.
Add a form will appear to the right, we’ll keep things simple. Fill in the form the following fields:
- Display name: Markdown
- Name: md
- File type: .md (don’t forget the leading dot)
And that’s about it. Next, we’ll have to get the file when our app is launched for that purpose.
In Windows 8.1 different methods are called depending on what kind of event launched our app, when our app is opened as the result of a File Type Association, the starting poit of the app will be the
OnFileActivated method inside the
App class. Let’s override it:
The reference to the recently opened file is inside the
FileActivatedEventArgs, to find it use something like this:
Launching an app to receive a file is not so different than launching it normally, so after we get the reference to the desired file, we must let the launching process continue as usually, for that copy the code inside the
Frame rootFr... to
if (rootF... and paste it after the code above.
Now all we have to do is to navigate to the generated
MainPage passing the file as a navigation parameter:
As you may guess, there is still work to do inside the Windows 8 generated
MainPage, and that’s true. We still need to get the file passed as navigation parameter. First of all, instead of calling the forms app in this way
LoadApplication(new YOUR_NAMESPACE.App());, create a field of type
new YOUR_NAMESPACE.App, like
And then call the
LoadApplication using that field
Now the final step: override the
OnNavigatedTo method inside the
MainPage class, but we need to be extra careful here, since this method will be called regardless of how was the app launched, so take that in consideration:
As with Windows, in Android you must tell the OS that your app is ready to receive a certain kind of files, and to do so, you must edit the
AndroidManifest.xml file. Remember that for Xamarin.Android there are two ways to work with the manifest:
- Editing the XML
- Using class level attributes
For this sample let’s take the attribute approach. Then, once the
MainActivity.cs file is open, separate the
LoadApplication method and the instantiation of the Forms app:
In Android, every time an app is launched to receive a file, the
OnCreate method is executed as if it were launched manually by the user, no special method is called or something, to know if the app was launched to receive a file we’ll have to look at the Activity’s Intent action and type:
After we are sure that the app was to receive a file, we can safely get an
Uri to the file by getting the Intent data, reading it and then creating an instance of the previously defined
We have finally handled a file receiving within the Xamarin.Android project, the last thing we have to do is to set the
IncomingFile property of the Forms app, a call to
application.IncomingFile will do the trick:
We already know that we need to register our app somehow to let the os know about the existence of our app, and in iOS the wa to do this is vía the
Info.plist file. When I started to implement this I struggled a bit because I think the docummentation a bit too vague.
Any way, in your app, open the Info.plist file, and at the bottom part click on the
Advanced tab, now, we have to fill in some information about the type of files we want to open in our app, for Markdown files we must add a new Document Type with the following values:
- Name: Markdown document
- Types: net.daringfireball.markdown
net.daringfireball.markdown is not a known type for iOS, we have to register it in the same UI we declared the filetype association, click add in Exported UTIs, once available, put this values on the text fields:
- Description: Markdown document
- Identifier: net.daringfireball.markdown
- Conforms To: public.plain-text
There is a few lines we need to add in order to make this work, like adding
.md as a file extension for the files… just to be sure, open the
Info.plist with an XML editor and make sure it looks somewhat like this in code or take a look at the following image.
Now, the most fun part, the code.
As with the Windows version of our app, we need to separate the call to
LoadApplicaton from the instatiation of the Forms app, again, create a Field inside the
AppDelegate class of type
new YOUR_NAMESPACE.App, like:
Now, inside the
FinishedLaunching method, instantiate the
_app field and call
LoadApplication using it as a parameter:
When our app is launched to open a file, a method is called in the
AppDelegate class, it’s name is
OpenUrl. In order to handle the icoming file, we must override it. The method receives an
NSUrl as an argument, and that is the url of our file.
I will use the
File.ReadAllText static method inside the
System.IO to get the content of the app that has to be opened by the app, such method takes a file path (in the form of string) as a parameter and returns the text contained by that same file.
Be careful here because there is a catch with the url you are given inside your method: it has the protocol
file:// at the beginning of the url, so you need to remove it before sending the path to the
ReadAllText method, in this case, I just trimmed the first 7 characters of the url:
Now it is safe to read all the text inside the file and pass it to the Forms application:
In iOS you are responsible to clean all the files that your app opens in this way, my recommendation is that you delete the file after reading it.
As you can see, it is not hard to enable your Xamarin.Forms app to open certain kind of files, all you have to do is tell the operating system (through configuration files) that your app is capable of opening that kind of files, and then write some code at the beginning of your app to handle the incoming file.