0
votes

How do I make the hardware back button return to the system's Start page when my app is launched from a secondary tile (i.e. deep linking)?

I'm using XAML and C#, by the way.

2

2 Answers

0
votes

You can just clear the back stack if app is launched from a secondary tile.

Next press on back button will take user back to Start screen.

EDIT:

To clear the back stack:

If you're in page code behind, do

Frame.BackStack.Clear();

else do

var frame = Window.Current.Content as Frame;
frame.BackStack.Clear();
0
votes

So, finally answering my own question months later...

The situation

Whenever my app is launched using a secondary tile, I have to make sure that the back stack is cleared by calling rootFrame.BackStack.Clear() on App.xaml.cs. That's necessary because if there is a suspended instance of my app in memory, this navigation from the secondary tile is added to the top of whatever back stack that suspended instance had. This is a problem because it makes a press of the back button return to the previous page on the stack instead of the Start screen, which is the appropriate behavior for secondary tile launches.

The problem

If the user "cold launches" the app using a secondary tile, whenever s/he leaves it Windows will suspend that session of the app with a clear back stack. That means that new launches from the primary tile will restore that page that was called from the secondary tile, and pressing the back button will suspend the app again instead of going to the app's main page.

The solution

It's actually documented by Microsoft, but only textually (https://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn639128.aspx):

Ensure proper Back button behavior when your app supports multiple launch points

Consider creating new instances of navigation journals for launch points such as primary and secondary tiles, file and URI Associations. Save the activation parameters each time the app is launched and compare when the app is being re-launched. If the app is being re-launched with different parameters, consider creating a new navigation history. Do this by creating a new Frame. This will allow the user to quickly navigate back to the launch point when the hardware Back key button is pressed. To maintain a small memory footprint, the Navigation history for launch points other than the Primary tile doesn’t need to be saved when the app is suspended.

In practice, for me, that meant writing the last received launch argument to a text file in my app's storage and reading it back on the beginning of the OnLaunched method in App.xaml.cs. Then I compare the read value to the current launch arguments. If they are different, I simply assign null to the rootFrame variable, so that a new "navigation journal" is created:

    protected override async void OnLaunched(LaunchActivatedEventArgs e)
    {
        ...
        Frame rootFrame = Window.Current.Content as Frame;
        var lastArgument = await ReadLastArgument();
        if (!string.Equals(lastArgument,currentArgument))
            rootFrame = null;

        // Do not repeat app initialization when the Window already has content,
        // just ensure that the window is active.
        if (rootFrame == null){
        ...
        }
        ...
        if (!String.IsNullOrEmpty(e.Arguments))
        {
            WriteLastArgument(e.Arguments);
            //Navigate to the page...
            ...
            rootFrame.BackStack.Clear();
        }

    private async Task<string> ReadLastArgument()
    {
        StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
        try
        {
            StorageFile file = await folder.GetFileAsync("lastArgument.txt");
            var argument = await Windows.Storage.FileIO.ReadTextAsync(file);
            return argument;
        }
        catch (System.IO.FileNotFoundException)
        {
            return "";
        }

    }

    private async void WriteLastArgument(string argument)
    {
        StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
        StorageFile file = await folder.CreateFileAsync("lastArgument.txt", CreationCollisionOption.ReplaceExisting);
        await FileIO.WriteTextAsync(file, argument);
    }
}