uri scheme

How to connect your Windows Phone 8 & 8.1 app to Yammer

In my recent project UniShare I also added Yammer, because some of users asked for it and we use it also at Telefónica.

This post is all about how to connect you Yammer. First, we need to prepare our app. Five steps are needed for preparation.

First, we need an uri scheme to launch our app. To add an uri scheme, right click on the WMAppManifest.xml and click on ‘Open With…’ and select ‘XML (Text) Editor with Encoding’. After the ‘Tokens’ section, add your custom uri scheme within the ‘Extensions’ tag, for example:

      <Protocol Name="yourapp-yammercallback" NavUriFragment="encodedLaunchUri=%s" TaskID="_default" />

Next step is to add a proper UriMapper:

public class UriMapper : UriMapperBase
{
    public override Uri MapUri(Uri uri)
    {
        if (uri.ToString().Contains("yourapp-yammercallback"))
        {
            string decodedUri = HttpUtility.UrlDecode(uri.ToString());

            int redirectUriIndex = decodedUri.IndexOf("yourapp-yammercallback");
            string redirectParams = new Uri(decodedUri.Substring(redirectUriIndex)).Query;
            // Map the OAuth response to the app page
            return new Uri("/MainPage.xaml" + redirectParams, UriKind.Relative);
        }

        else return uri;
    }
}

If you want to learn more about uri schemes, you can read my blog post here.

The third step is to generate your app on Yammer to get your Tokens. Open https://www.yammer.com/client_applications, click on ‘Register New App’ and fill in the form:

Screenshot (354)

After clicking on continue, click on ‘Basic Info’ and add your uri scheme in the field ‘Redirect Uri’ and click on ‘Save’.

Screenshot (356)

The fourth step starts with downloading the Yammer oAuth SDK for Windows Phone from Github. Open the solution and built all projects. After that, you can close the solution. Go back into your project, and right click on ‘References’, followed by ‘Add Reference’. Browse to the folder ‘\WPYammer-oauth-sdk-demo-master\windows-phone-oauth-sdk-demo-master\Yammer.OAuthSDK\Bin\Release’ and add the file with the name ‘Yammer.OAuthSDK.dll’.

The last step is to add your keys and the redirect uri in your app’s resource dictionary:

<model:OAuthClientInfo xmlns:model="clr-namespace:Yammer.OAuthSDK.Model;assembly=Yammer.OAuthSDK" x:Key="MyOAuthClientInfo"
    ClientId="your client id" 
    ClientSecret="your client secret" 
    RedirectUri="yourapp-yammercallback" />

Now that our app is prepared, we can finally launch the oAuth process. First, we need to read our values from our app’s resource dictionary. Add this to the constructor to do so:

YammerClientId = App.MyOAuthClientInfo.ClientId;
YammerClientSecret = App.MyOAuthClientInfo.ClientSecret;
YammerCallbackUri = App.MyOAuthClientInfo.RedirectUri;

To kick the user out to the oAuth process, which happens in the phone’s browser, just add these two lines to your starting event (for example a button click event).

OAuthUtils.LaunchSignIn(YammerClientId, YammerCallbackUri);
App.Current.Terminate();

You might notice the app gets terminated. We have to do this because only this way, the uri scheme we added earlier can do its work. If the app is not terminated, the values cannot be passed into our app. Technically, it would also be possible to use the WebAuthenticationBroker on 8.1 for this. Sadly, the Yammer authorization pages do not work well with the WAB. The best way to use it with this library, is to kick the user to the browser.

Once we are receiving the values of the authentication, we can continue the authentication process to get the final access token. Add this code to your OnNavigatedTo event:

ShowProgressIndicator("connecting to Yammer...");

if (NavigationContext.QueryString.ContainsKey(Constants.OAuthParameters.Code) && NavigationContext.QueryString.ContainsKey(Constants.OAuthParameters.State) && e.NavigationMode != NavigationMode.Back)
{
    OAuthUtils.HandleApprove(
        YammerClientId,
        YammerClientSecret,
        NavigationContext.QueryString[Constants.OAuthParameters.Code],
        NavigationContext.QueryString[Constants.OAuthParameters.State],
        onSuccess: () =>
        {
            GetYammerCurrentUserData();
        }, onCSRF: () =>
        {
            MessageBox.Show("Please contact us via the 'help & support' page.", "Invalid redirect", MessageBoxButton.OK);
        }, onErrorResponse: errorResponse =>
        {
            Dispatcher.BeginInvoke(() => MessageBox.Show(errorResponse.OAuthError.ToString(), "Invalid operation", MessageBoxButton.OK));
            HideProgressIndicator();
        }, onException: ex =>
        {
            Dispatcher.BeginInvoke(() => MessageBox.Show(ex.ToString(), "Unexpected error", MessageBoxButton.OK));
            HideProgressIndicator();
        }
    );
}
// "Deny"
else if (NavigationContext.QueryString.ContainsKey(Constants.OAuthParameters.Error) && e.NavigationMode != NavigationMode.Back)
{
    string error, errorDescription;
    error = NavigationContext.QueryString[Constants.OAuthParameters.Error];
    NavigationContext.QueryString.TryGetValue(Constants.OAuthParameters.ErrorDescription, out errorDescription);

    string msg = string.Format("error: {0}\nerror_description:{1}", error, errorDescription);
    MessageBox.Show(msg, "Error", MessageBoxButton.OK);

    if (NavigationContext.QueryString != null)
    {
        string[] NavigationKeys = NavigationContext.QueryString.Keys.ToArray();
        ClearNavigationContext(NavigationKeys);
    }

    OAuthUtils.DeleteStoredToken();

}

With this, you are handling all errors and events properly. If the call ends successfully, we are finally able to get our user’s data:

public void GetYammerCurrentUserData()
{
    ShowProgressIndicator("connecting to Yammer...");

    var baseUrl = new Uri("https://www.yammer.com/api/v1/users/current.json", UriKind.Absolute);

    OAuthUtils.GetJsonFromApi(baseUrl,
        onSuccess: response =>
        {
            //do something with the result (json string)

            HideProgressIndicator();

        }, onErrorResponse: errorResponse =>
        {
            Dispatcher.BeginInvoke(() =>
            {
                MessageBox.Show(errorResponse.OAuthError.ToString(), "Invalid operation", MessageBoxButton.OK);
                HideProgressIndicator();

            });
        }, onException: ex =>
        {
            Dispatcher.BeginInvoke(() =>
            {
                MessageBox.Show(ex.ToString(), "Unexpected error", MessageBoxButton.OK);
                HideProgressIndicator();

            });
        }
    );
}

As you can see above, the result is a json string that contains the current user’s data. You can either create a class/model to deserialize the values or use anonymous deserialization methods.

One important point: you cannot publish your app outside your home network until it got approved as a global app by Yammer. I am waiting for nearly two weeks now for UniShare to get approved and hope it will become available for all soon.

As always, I hope this post is helpful for some of you.

Happy coding!

Posted by msicc in Archive, 1 comment

[Updated] NFC Toolkit uri schemes

app2app_nfctoolkit

If you are following me, you might have noticed that uri schemes actually are playing a big role in my Windows Phone apps. (read more)

NFC Toolkit, one of my main projects, offers now also the possibility to interact with your apps.

One of the unique features of NFC Toolkit is profiles. Profiles are designed to open up to 5 settings pages in a row (as directly setting them is not possible because of OS restrictions). At the end of a profile, an extra from within the app or another app can be launched.

In Phase I, NFC Toolkit enables other developers to add their custom uri association/scheme to the list of launchable apps in profiles.

Here is how the uri needs to be formatted to work:

"nfctoolkit:addmyapp?appname=<yourappnamehere>&urischeme=<yoururischemehere>"

I will add more uri associations with the next updates and update this post with them.

[Update 2]

Starting with version 0.9.8.1 of NFC Toolkit, I added new uri schemes to enable you to write data on NFC tags. Here is the list of possible writing records:

  • website record:
"nfctoolkit:writetag?type=smartposter&url=<url>&title=<title of the website>&languagecode=<two letter lang code (standard: en)>"
  •   text record:
"nfctoolkit:writetag?type=text&content=<your text here>&languagecode=<two letter lang code (standard: en)>"
  • send mail record:
"nfctoolkit:writetag?type=mail&mailaddress=<mailaddress>&mailsubject=<mailsubject>&mailbody=<mailbody>"
  •  settings page:
//supported pages: flight mode, cellular, WiFi, Bluetooth, location, lock screen
"nfctoolkit:writetag?type=settings&page=<settings page name as listed above>"
  •  launch system app:
//supported pages: 
//"Alarm", "background tasks", "brightness settings", "Bing Vision", "Calculator", "Calendar", "call history", 
//"Camera", "Data Sense", "date + time settings", "ease of access", "find my phone", "Games", "Help+Tips", 
//"Internet Explorer", "internet sharing", "keyboard settings", "kid's corner settings", "language + region settings", 
//"Maps",  "Messaging", "Music+Videos", "Office", "OneNote", "People", "Phone", "phone information", "Photos", 
//"Rooms", "SIM Applications", "Start", "Store", "theme settings", "Wallet"
"nfctoolkit:writetag?type=sysapp&name=<system app name as listed above>"
  •  launch any app by name or publisher name:
//launches the store page search in NFC Toolkit and searches for the app/publisher
"nfctoolkit:writetag?type=launchapp&appname=<app name or publisher name>"

On top of that, I added an uri scheme that allows a plain launch of NFC Toolkit:

"nfctoolkit:home"

I updated my custom uri scheme test app as well for you. Download it here: CustomUriSchemeTestApp

Happy coding everyone!

 

 

 

Posted by msicc in Archive, 5 comments

A simple approach to remove QueryStrings from NavigationContext on Windows Phone

QuerystringsRemove

Like most of you know, I am currently adding a lot of new features to my NFC Toolkit for Windows Phone.

Today, my coding session is all about uri schemes again. I successfully added some new uri schemes that you will be able to use soon.

However, if you start an app via an uri scheme, you will have  QueryStrings in your NavigationContext on the desired ApplicationPage. If a user continues to use your app, navigates away from the launched page and back to it, the code based on your QueryStrings will be called again.

As I am a daily Windows Phone user by myself, I know this is somewhat annoying. So I searched for a solution. I first thought about removing entries in the BackStack, but that would need a lot of code if you are running an application that has more than two pages – you’ll need to add methods to check if you are coming from an uri scheme, clear the BackStack, pass the parameters to the next page, get back to your MainPage, check the parameters again. Totally unusable in my opinion.

The NavigationContext.QueryString property has a Remove() method as I found out while researching a bit more – that’s what I am using now to get the result I want – make the app running like it was launched normally without uri scheme after the action has taken place.

I found some examples that are using the method in the  OnNavigatedTo() event. I don’t think that’s the right way, as I often happen to have some more code in this event, and it will probably break other functionality. I am using the OnNavigatedFrom() event.

Add this lines of code for every QueryString you want to remove (depending on your method structure, it is ok to remove only the QueryString you rely on in your further code, additional parameters can be still there ):

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
   if (NavigationContext.QueryString.ContainsKey("key1"))
   {
      NavigationContext.QueryString.Remove("key1");                                
   }
   if (NavigationContext.QueryString.ContainsKey("key2"))
   {
       NavigationContext.QueryString.Remove("key2");
   }            
   base.OnNavigatedFrom(e);
}

This way, if you are navigating to another page in your app or even if the user uses the Windows Button, the corresponding QueryString will be removed – and your users are able to use the app as they would have launch it without an uri scheme.

However, that’s not all. When your app get’s Tombstoned, the UriMapper will map the uri scheme again on Activation – not what you might want. To get around this, I use a simple Boolean, set it to true when I am coming back from Tombstoning:

private void Application_Activated(object sender, ActivatedEventArgs e)
{
    if (!e.IsApplicationInstancePreserved)
    {
        wasTombstoned = true;  
    }
}

Now the only thing you will need to to is to add

&& App.wasTombstoned == false

as second argument to your QueryString clause – that’s it!

I am not sure if this is a good approach or not, but it works. It allows you to launch your uri scheme, and enables the user to use your app after that as it would have been launched normally. If you have other ways to get the same result, feel free to leave a comment below.

Otherwise, I hope this post is helpful for some of you.

Happy coding!

Posted by msicc in Archive, 5 comments

Add your app: List of uri associations for Windows Phone

While development of my NFC Toolkit, I came to the point where I needed to launch apps from my code.

On Windows Phone, this is only possible via custom uri association and needs to be implemented by the developer of an app.

If you want your app to be launchable from other apps, you need to implement a custom uri assocation like descriebed here in the MSDN Documentation.

Users are demanding often apps to be launched from other apps – it is not much work to do, so I recommend you are implementing those features into your app(s). Over time,  your app will be getting more recognition amongst users of other apps and improves the user experience a lot.

To make it easier for everyone of us, please add your app here: http://developer.nokia.com/Community/Wiki/URI_Association_Schemes_List

Let’s make this list a basic resocurce for everyone of us!

Until then, happy coding!

Posted by msicc in Archive, 3 comments