Windows Store App - Executing a single task when launched from a secondary tile


I have a Windows Store App that creates a secondary tile. When the tile is clicked, I want the app to perform, what is effectively, an off-line function (that is, I don't want to go back into the app, but want the app to do something and then exit). So in this case I want to launch the e-mail client, for exampe. Here's where I am so far:

app.addEventListener("activated", function (args) {
    if (args.detail.kind === activation.ActivationKind.launch) {

        if (args.detail.arguments !== "") {
            // Activation arguments are present that 
            // were declared when the secondary tile was pinned to Start.
            args.setPromise(WinJS.UI.processAll().done(function () {
                var emailaddress = args.detail.arguments;
                var promise = Email.SendNewMail.sendEmail(emailaddress);
                //promise.complete();
                return;
            }));

        } else if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
            // TODO: This application has been newly launched. Initialize
            // your application here.
        } else {
            // TODO: This application has been reactivated from suspension.
            // Restore application state here.
        }
...

Email function here:

    sendEmail: function sendEmail(addess, subject, body) {
        var mailto = new Windows.Foundation.Uri("mailto:?to=" + addess + "&subject=" + subject + "&body=" + body);
        return Windows.System.Launcher.launchUriAsync(mailto);
    }

The error I currently get is "Object has disconnected from its client" - which I assume is caused by the program exiting before the promise completes. How can this kind of behaviour be achieved in WInRT?

UPDATE:

I've had feedback from MS on this, and their response if that whether or not this is possible, it is definitely unsupported because exiting an app programatically breaches certification requirement 3.6.

It does not seem that the Secondary Tiles are intended to launch third party applications:

Secondary tiles enable users to promote specific content and deep links—a reference to a specific location inside of the pinning app—from Windows Store app apps [sic] onto the Start screen.

Source: http://msdn.microsoft.com/en-us/library/windows/apps/hh465372.aspx

I have tried a number of ways to correct your issue though and there seems to be a timing issue in play here. When not debugging, your above code (with or without a Promise completion function call like then or done) fails every time for me, no matter if you put your code in the ready, loaded, or activated event.

In my testing however, I was able to get this to work without the error by wrapping your launch function in a couple of different ways:

  1. With a timeout using setTimeout with a timeout of anything above 1 second
  2. With a Message Dialog using Windows.UI.Popups.MessageDialog

Both of which ending in your promise completion callback, with a call to window.close(); to exit the application.

Example using Eight.js for the messaging route: (seems the cleanest available solution, but obviously doesn't perform the launch in the background and isn't the most user friendly):

Eight.Message.confirmAsync("Send the email?", function (doSend) {
    if (!doSend) return;

    Email.SendNewEmail.sendEmail(emailaddress).done(function (e) {
        window.close();
    });
});

Note: I think either solution is hacky though, and I'm sure you'd agree. Neither one actually does the launch in the background. I can't find any documentation anywhere to support being able to do this without launching your application. To me this seems like a bug and I would try to open a technical support incident for a cleaner solution if you can. If not you might try the Windows Store Apps forums where some actual Microsoft people dwell.


Well you can use the then() of the launchUriAsync() to dispose the app:

Email.SendNewMail.sendEmail(emailaddress).then(function (success) {
    if (success) {
        window.close()
    } else {
        // Display error message
    }
});