[Windows 8] Utiliser les APIs de Google dans vos applications de type Windows Store
Google dispose de plusieurs services (type GMail, Calendrier, etc.) qui se trouvent être accessible à travers un ensemble d'’APIs cliente. Le problème, c’est que pour le moment, il n’existe pas d’APIs cliente pour Windows 8: nous allons donc voir comment contourner ce problème et profirer des services Google dans nos applications Windows 8!
Avant de commencer, il est nécessaire de se rendre sur le Dashboard Google (accessible ici: https://code.google.com/apis/console/) et de créer une nouvelle application. Ensuite, il faut se rendre dans la partie “Services” afin de sélectionner les services Google qui seront utilisés par votre application. Enfin, dans la partie “API Access”, il ne vous reste plus qu’à activer les fonctionnalités d’authentification OAuth 2.0 (attention, dans les paramètres, à bien spécifier que l’application est de type “Installed”) et noter les informations de Client ID, Client Secret et API Key:
Les APIs serveur de Google utilisent la technologie REST, ce qui simplifie grandement les échanges. Cependant, il est nécessaire de s’authentifier pour que cela fonctionne et c’est là que OAuth 2.0 entre en jeu.
Pour cette partie, nous avons la chance de pouvoir disposer du WebAuthenticationBroker qui va nous permettre de nous connecter à Google:
var googleUrl = "https://accounts.google.com/o/oauth2/auth?client_id=" + Uri.EscapeDataString(GoogleClientId) + "&redirect_uri=" + Uri.EscapeDataString(GoogleCallbackUrl) + "&response_type=code&scope=" + Uri.EscapeDataString("https://www.googleapis.com/auth/calendar"); var startUri = new Uri(googleUrl); // When using the desktop flow, the success code is displayed in the html title of this end uri var endUri = new Uri("https://accounts.google.com/o/oauth2/approval"); var result = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.UseTitle, startUri, endUri); if (result.ResponseStatus == WebAuthenticationStatus.Success) { // }
La variable googleUrl contient l’URL qui sera appelée par le broker (on remarque, dans les scopes, que l’on ne demande que l’accès à Google Calendar mais cela dépend de vos besoins).
Une fois l’authentification terminée, le broker nous renvoit un code, que nous devons utiliser pour récupérer un AccessToken (qui sera utilisé dans les requêtes envoyées):
var successCode = result.ResponseData; var code = successCode.Substring(successCode.IndexOf("=", StringComparison.CurrentCultureIgnoreCase) + 1); var token = await this.GetTokenAsync(code); if (token != null) { await this.GetCalendars(token.access_token); }
La méthode GetTokenAsync, qui prend le code et l’utilise pour récupérer un AccessToken, est définit ci-dessous:
private async Task<Token> GetTokenAsync(string code) { var httpClient = new HttpClient(); string postData = string.Format("client_id={0}&client_secret={1}&code={2}&redirect_uri={3}&grant_type=authorization_code", GoogleClientId, GoogleClientSecret, code, GoogleCallbackUrl); var stringContent = new StringContent(postData, Encoding.UTF8, "application/x-www-form-urlencoded"); var result = await httpClient.PostAsync("https://accounts.google.com/o/oauth2/token", stringContent); if (result.IsSuccessStatusCode) { var deserializer = new DataContractJsonSerializer(typeof(Token)); var data = (Token)deserializer.ReadObject(await result.Content.ReadAsStreamAsync()); return data; } return null; }
La classe Token, qui permet de représenter un token, peut être visualisée ci-dessous:
[DataContract] public class Token { [DataMember] public string access_token { get; set; } [DataMember] public string token_type { get; set; } [DataMember] public int expires_in { get; set; } [DataMember] public string refresh_token { get; set; } }
Il s’agit là de code “classique” lorsque l’on travaille avec OAuth. A noter, sur la classe Token, les propriétés ”expires_in” et “refresh_token” qui peuvent être utilisées pour rafraîchir l’AccessToken sans réafficher, à l’utilisateur, la popup de connexion à Google!
Une fois que nous avons obtenu ce fameux AccessToken, il ne reste plus qu’à l’utiliser, sur tous les appels que nous voulons faire aux APIs de Google, pour authentifier l’utilisateur. Pour cela, il suffit de le passer dans les Headers de la requête:
private async Task GetCalendars(string accessToken) { var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken); var content = await httpClient.GetAsync(string.Format("https://www.googleapis.com/calendar/v3/users/me/calendarList?fields=items(id%2Csummary)&key={0}", GoogleApiKey)); var result = await content.Content.ReadAsStringAsync(); }
Si on execute ce bout de code, on se rend compte qu’on arrive parfaitement à récupérer la liste des calendriers de l’utilisateur courant:
{ "items": [ { "id": "XXXXX@gmail.com", "summary": "Thomas LEBRUN" } ] }
Si l’on veut, par exemple, récupérer la liste des RDV de l’utilisateur, il suffit d’appeler la requête correspondante en passant, comme toujours, l’AccessToken dans les headers de la requête:
private async Task GetAppointments(string calendarId, string accessToken) { var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken); var content = await httpClient.GetAsync(string.Format("https://www.googleapis.com/calendar/v3/calendars/{0}/events?key={1}", Uri.EscapeDataString(calendarId), GoogleApiKey)); var result = await content.Content.ReadAsStringAsync(); }
Ce qui fonctionne parfaitement:
{ "kind": "calendar#events", "etag": "\"XXXXXXXXXXXXXXXXXXXXXXXXX\"", "summary": "Thomas LEBRUN", "updated": "2013-08-31T18:45:58.894Z", "timeZone": "Europe/Paris", "accessRole": "owner", "defaultReminders": [ { "method": "sms", "minutes": 30 }, { "method": "popup", "minutes": 30 } ], "items": [ { "kind": "calendar#event", "etag": "\"XXXXXXXXXXXXXXXXXXXX\"", "id": "XXXXXXXXXXXXXXX", "status": "confirmed", "htmlLink": "https://www.google.com/calendar/event?eid=XXXXXXXXXXXXXXX", "created": "2013-08-31T18:35:26.000Z", "updated": "2013-08-31T18:35:26.142Z", "summary": "Test Thomas", "creator": { "email": "XXXXX@gmail.com", "displayName": "Thomas Lebrun", "self": true }, "organizer": { "email": "XXXXX@gmail.com", "displayName": "Thomas Lebrun", "self": true }, "start": { "date": "2013-09-01" }, "end": { "date": "2013-09-02" }, "transparency": "transparent", "iCalUID": "XXXXXXXXXXXXXXX@google.com", "sequence": 0, "reminders": { "useDefault": false, "overrides": [ { "method": "email", "minutes": 10 }, { "method": "popup", "minutes": 20 } ] } }, { "kind": "calendar#event", "etag": "\"XXXXXXXXXXXXXXX\"", "id": "XXXXXXXXXXXXXXX", "status": "confirmed", "htmlLink": "https://www.google.com/calendar/event?eid=XXXXXXXXXXXXXXX", "created": "2013-08-31T18:45:58.000Z", "updated": "2013-08-31T18:45:58.828Z", "summary": "test test", "creator": { "email": "XXXXX@gmail.com", "displayName": "Thomas Lebrun", "self": true }, "organizer": { "email": "XXXXX@gmail.com", "displayName": "Thomas Lebrun", "self": true }, "start": { "date": "2013-08-28" }, "end": { "date": "2013-08-29" }, "transparency": "transparent", "iCalUID": "XXXXXXXXXX@google.com", "sequence": 0, "reminders": { "useDefault": true } } ] }
Ainsi, on constate que grâce au mélange du WebAuthenticationBroker, d’OAuth et de REST, l’accès aux APIs de Google vous est ouvert: n’hésitez plus et faîtes-vous plaisir !
Happy coding !
Commentaires