Feature Image

Adding static shortcuts to your app

Adding static shortcuts to your app

In a previous post I showed how you could use my AppShortcuts plugin to add Dynamic shortcuts to your Xamarin Apps. Along with Dynamic shortcuts, both iOS and Android also provide Static shortcuts which can be added declaratively.

Static shortcuts are declared via the app's manifests, added automatically during installation and can't be manipulated via the app. Dynamic and Static shortcuts both have their uses and can be used in combination with each other.

A full sample app that demo's how to add and use Static shortcuts can be found here: github.com/adenearnshaw/xam-static-shortcuts

Handling AppLinks in Xamarin Forms

The Xamarin Forms Application class has a built in method for handling Shortcuts. This method is the OnAppLinkRequestReceived() and is called once the App's constructor has completed. This allows us to handle any navigation we may wish to occur.

In the sample, I remove the uri's base and then check to see if what remains matches one of the known keys. It's crude and would never see production, but it gives you an idea.

public partial class App : Xamarin.Forms.Application
{
    private const string AppShortcutUriBase = "stc://staticshortcuts/";
    private const string ShortcutKey_Favorite = "favorites";
    ...
    
    protected override async void OnAppLinkRequestReceived(Uri uri)
    {
        var shortcutKey = uri.ToString().Replace(AppShortcutUriBase, "");

        if (shortcutKey == ShortcutKey_Favorite)
            await NavigationService.Instance.Navigate(new FavoritesPage());
        else
            base.OnAppLinkRequestReceived(uri);
    }
}

iOS implementation

To add shortcuts (or Quick Actions as Apple call them) to iOS, is relatively trivial. Firstly declare the shortcuts in the Info.plist and then override AppDelegate.PerformActionForShortcutItem() to martial the data to the Xamarin Forms App.

Updating the Info.plist

Shortcuts are declared as a dictionary item within an array with the key UIApplicationShortcutItems. Each dictionary item within the array must include keys for UIApplicationShortcutItemTitle and UIApplicationShortcutItemType. Optional properties for a Subtitle, Icon and additional data can also be added.

Sample:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  ...
  <key>UIApplicationShortcutItems</key>
    <array>
      <dict>
        <key>UIApplicationShortcutItemType</key>
        <string>stc://staticshortcuts/favorites</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>My favorites</string>
        <key>UIApplicationShortcutItemSubtitle</key>
        <string>View favorited monkeys</string>            
        <key>UIApplicationShortcutItemIconType</key>
        <string>UIApplicationShortcutIconTypeFavorite</string>
        <key>UIApplicationShortcutItemUserInfo</key>
          <dict>
            <key>dataKey1</key>
            <string>dataValue1</string>
          </dict>
      </dict>
    </array>
</dict>
</plist>

Here we've declared one shortcut to allow users to jump straight to the Favorites page of an app. The UIApplicationShortcutItemType can be any string, but I recommend following a URL format so that the Xamarin.Forms.Application identifies the AppLink correctly.

We're also leveraging the built in Favorites icon provided by iOS. A list of the icons can be found in Apple's Human Interface Guidelines and the corresponding Constant values are listed in Apple's Developer Documentation. Custom icons can be declared using UIApplicationShortcutItemIconFile, but that's beyond the scope of this.

Handling the quick action

App links should be handled by Application.OnAppLinkRequestReceived(). However, we need to add some additional code to our AppDelegate in order for the Forms Application to know about the shortcuts.

Add this into the AppDelegate within the iOS project:

public override void PerformActionForShortcutItem(UIApplication application, UIApplicationShortcutItem shortcutItem, UIOperationHandler completionHandler)
{
    if (!string.IsNullOrEmpty(shortcutItem?.Type))
    {
        Xamarin.Forms.Application.Current.SendOnAppLinkRequestReceived(new Uri(shortcutItem.Type));
    }
}

The PerformActionForShortcutItem() method is called automatically when a user clicks through from a Shortcut. Here we check if the shortcutItem's Type property has a value and then pass this as a Uri to the Xamarin Forms App.

Android implementation

Implementing shortcuts on Android is almost as simple as iOS, but there's just a little more ceremony involved.

Updating the Activity

Firstly, find the Activity where you decare MainLauncher = true and add the properties Exported = true and Name = "com.mycompany.myapp.mainlauncher" to the Activity attribute. Exported needs to be set in order for the shortcut to see the activity, and Name must be set in order for a user-friendly version of activity name to be shown (otherwise you'll have to deal with unsightly guids).

Underneath this, add a new MetaDataAttribute to the class to inform the app where the shortcut data is located.

[MetaData("android.app.shortcuts", Resource = "@xml/shortcuts")]

Now you need to create your shortcut data.

Creating Shortcut metadata

In your Resources folder, if one doesn't exist, create an xml folder and within that create a shortcuts.xml. This is where you will declare your shortcuts. Unfortunately, it's a bit more verbose than iOS.

<?xml version="1.0" encoding="utf-8" ?> 
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
  <shortcut
    android:shortcutId="favorites"
    android:enabled="true"
    android:icon="@drawable/ic_sc_favorite"
    android:shortcutShortLabel="@string/sc_favorites_short"
    android:shortcutLongLabel="@string/sc_favorites_long"
    android:shortcutDisabledMessage="@string/sc_favorites_disabled">
    <intent
      android:action="android.intent.action.VIEW"
      android:targetPackage="com.mycompany.myapp"
      android:targetClass="com.mycompany.myapp.mainlauncher"
      android:data="stc://staticshortcuts/favorites" />
    <categories android:name="android.shortcut.conversation" />
  </shortcut>
</shortcuts>

Here again we've declared a shortcut that will navigate users to the app's Favorites page.

Things to note:

  • Labels and messages must come from the strings.xml and can't be hardcoded - this produces a build error.
  • The icon can be any png or android vector stored in your Resources/Drawable folder - Some useful images can be found within my AppShortcuts Plugin Repo
  • The value for android:targetClass must match the Name declared in the Activity attribute earlier.
  • The android:data value must be able to be parsed to a Uri in order for Xamarin Forms to handle it correctly.

Providing the android:data value is a Uri format and the Activity which calls LoadApplication(new App()) has the data within it's Intent. Then Xamarin Forms will automatically call Application.OnAppLinkRequestReceived() without you doing anything further.

If your MainLauncher Activity is not the same as the one that creates the XamarinForms application (e.g. you've got a SplashScreenActivity), then you'll need to pass the shortcut data into the new Intent.

protected override void OnResume()
{
    base.OnResume();
    var intent = new Intent(Application.Context, typeof(MainActivity));
    
    intent.SetAction(Intent.ActionView);
    intent.SetData(Intent?.Data);
    
    StartActivity(intent);
}

It's this data that Xamarin.Forms uses to see whether OnAppLinkRequestReceived() needs to be called

For more detailed information on how to create shortcuts for Android, the developer docs have a derth of information.