Xamarin.Essentials: Launcher
The Launcher class enables an application to open a URI by the system. This is often used when deep linking into another application's custom URI schemes. If you are looking to open the browser to a website then you should refer to the Browser API.
Get started
To start using this API, read the getting started guide for Xamarin.Essentials to ensure the library is properly installed and set up in your projects.
Using Launcher
Add a reference to Xamarin.Essentials in your class:
using Xamarin.Essentials;
To use the Launcher functionality call the OpenAsync
method and pass in a string
or Uri
to open. Optionally, the CanOpenAsync
method can be used to check if the URI schema can be handled by an application on the device.
public class LauncherTest
{
public async Task OpenRideShareAsync()
{
var supportsUri = await Launcher.CanOpenAsync("lyft://");
if (supportsUri)
await Launcher.OpenAsync("lyft://ridetype?id=lyft_line");
}
}
This can be combined into a single call with TryOpenAsync
, which checks if the parameter can be opened and if so open it.
public class LauncherTest
{
public async Task<bool> OpenRideShareAsync()
{
return await Launcher.TryOpenAsync("lyft://ridetype?id=lyft_line");
}
}
Additional Platform Setup
Files
This features enables an app to request other apps to open and view a file. Xamarin.Essentials will automatically detect the file type (MIME) and request the file to be opened.
Here is a sample of writing text to disk and requesting it be opened:
var fn = "File.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");
await Launcher.OpenAsync(new OpenFileRequest
{
File = new ReadOnlyFile(file)
});
Presentation Location When Opening Files
When requesting a share or opening launcher on iPadOS you have the ability to present in a pop over control. This specifies where the pop over will appear and point an arrow directly to. This location is often the control that launched the action. You can specify the location using the PresentationSourceBounds
property:
await Share.RequestAsync(new ShareFileRequest
{
Title = Title,
File = new ShareFile(file),
PresentationSourceBounds = DeviceInfo.Platform== DevicePlatform.iOS && DeviceInfo.Idiom == DeviceIdiom.Tablet
? new System.Drawing.Rectangle(0, 20, 0, 0)
: System.Drawing.Rectangle.Empty
});
await Launcher.OpenAsync(new OpenFileRequest
{
File = new ReadOnlyFile(file),
PresentationSourceBounds = DeviceInfo.Platform== DevicePlatform.iOS && DeviceInfo.Idiom == DeviceIdiom.Tablet
? new System.Drawing.Rectangle(0, 20, 0, 0)
: System.Drawing.Rectangle.Empty
});
Everything described here works equally for Share
and Launcher
.
If you are using Xamarin.Forms you are able to pass in a View
and calculate the bounds:
public static class ViewHelpers
{
public static Rectangle GetAbsoluteBounds(this Xamarin.Forms.View element)
{
Element looper = element;
var absoluteX = element.X + element.Margin.Top;
var absoluteY = element.Y + element.Margin.Left;
// Add logic to handle titles, headers, or other non-view bars
while (looper.Parent != null)
{
looper = looper.Parent;
if (looper is Xamarin.Forms.View v)
{
absoluteX += v.X + v.Margin.Top;
absoluteY += v.Y + v.Margin.Left;
}
}
return new Rectangle(absoluteX, absoluteY, element.Width, element.Height);
}
public static System.Drawing.Rectangle ToSystemRectangle(this Rectangle rect) =>
new System.Drawing.Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height);
}
This can then be used when calling RequestAsync
:
public Command<Xamarin.Forms.View> ShareCommand { get; } = new Command<Xamarin.Forms.View>(Share);
async void Share(Xamarin.Forms.View element)
{
try
{
Analytics.TrackEvent("ShareWithFriends");
var bounds = element.GetAbsoluteBounds();
await Share.RequestAsync(new ShareTextRequest
{
PresentationSourceBounds = bounds.ToSystemRectangle(),
Title = "Title",
Text = "Text"
});
}
catch (Exception)
{
// Handle exception that share failed
}
}
You can pass in the calling element when the Command
is triggered:
<Button Text="Share"
Command="{Binding ShareWithFriendsCommand}"
CommandParameter="{Binding Source={RelativeSource Self}}"/>