"Les cours de neeko.fr"

Retour en haut

Android et les web-services

Android et les web-services

Se connecter au monde extérieur

Définition d'un web-service

Certaines applications fonctionnent sans avoir besoin de connection internet.

D'autres se connectent à des serveurs pour étendre certaines de leurs fonctionnalités.

Le service appellé peut-être développé directement pour l'application, ou être mis à disposition pour n'importe quelle application.

Voici quelques fonctionnalités que peuvent apporter les web-services :

Il existe de nombreux web-services ouverts au public, on parle aussi d'API. Ils nécessitent souvent l'obtention d'une clé.

  • Facebook : http://developers.facebook.com/
  • Twitter : https://dev.twitter.com/docs
  • Google Geocoding : https://developers.google.com/maps/documentation/geocoding/
  • Google Reverse Geocoding : https://developers.google.com/maps/documentation/geocoding/#ReverseGeocoding
  • World Weather Online : http://developer.worldweatheronline.com/documentation
  • Paypal : https://developer.paypal.com/
  • ...
  • Le protocole des Web-Services

    S'il est possible de se connecter directement à un serveur avec le protocole de son choix, c'est le protocole HTTP qui est le plus souvent utilisé. C'est le même qui est utilisé sur internet, lorsqu'un navigateur se connecte à un site internet.

    Quand un navigateur se connecte à un site internet, le serveur lui renvoie la plupart du temps du contenu HTML, que le navigateur est capable de traiter pour afficher la page voulue, avec des images et une mise en page particulière.

    Lorsque notre application se connectera à un serveur, elle recevra du contenu sous différente forme, qui lui faudra décoder puis utiliser.

    Le protocole HTTP

    Ce sont les mêmes serveurs qui permettent d'acceder à leur donnée en HTML (pour le navigateur web), et en XML ou en JSON pour les applications.

    Le principe du protocole HTTP est le suivant :

  • Le client crée une requete HTTP, avec une URL. Cette URL contient le protocole http, le nom du serveur, et quelques paramètres.
  • Le client envoie sa requete à travers le réseau, et le serveur la recoit.
  • Le serveur traite alors sa demande, qui peut correspondre à la construction d'une page, à l'inscription d'un utilisateur, ou encore une transaction bancaire, par exemple.
  • Le serveur réponds alors en renvoyant un code, ainsi que des données au client. Ces données sont dans un format au choix du serveur : binaire, texte, XML, JSON... Le code de retour est un standard HTTP qui permet de savoir si la requête est un succes ou un echec.
  • Le client recoit alors, quelque temps après, la réponse du serveur.
  • Le client traite alors le contenu de la réponse, de la maniere necessaire selon le service.
  • Un client HTTP avec une application Android

    Voici un client HTTP minimal avec Android, permettant de récuperer la réponse du serveur sous forme de chaine de caractère.

    L'application doit avoir la permission de se connecter à internet. Il faut donc ajouter cette permission dans le fichier AndroidManifest (dans la balise manifest).

    <uses-permission android:name="android.permission.INTERNET" />

    Voici un web-service "maison" très simple :

    http://nee.free.fr/testApi/test.php -> répondra "Hello, world"

    http://nee.free.fr/testApi/test.php?name=Boby -> répondra "Hello, Boby"

    try { //construction de la requete HTTP HttpUriRequest request = new HttpGet("http://nee.free.fr/testApi/test.php"); //Initialise le client HTTP HttpClient httpClient = new DefaultHttpClient(); //Envoi la requete et recoit la reponse HttpResponse response = httpClient.execute(request); //traitement du code de la reponse int responseCode = response.getStatusLine().getStatusCode(); System.out.println("http code: " + responseCode); //si ce n'est pas un code d'erreur... if (responseCode < 400) { //recupere le contenu de la réponse String content = EntityUtils.toString(response.getEntity()); System.out.println("http content: " + content); } } catch (Exception e) { System.out.println("Il y a eu un probleme: " + e); }

    Exercice :

    Réaliser une application qui utilise ce web-service.

    L'application affichera le message reçu, ou un message d'erreur générique en cas de problème.

    Etapes :

    Les limites du format texte

    Le fait de recevoir la réponse dans un format non structuré limite le nombre de données que je peux récupérer.

    Dans la réalité, il est souvent necessaire d'avoir une réponse plus pratique à manipuler.

    On utilise la plupart du temps des formats simples comme le XML ou le JSON pour structurer notre réponse, et du coup pouvoir passer plus d'informations.

    Ces formats sont standards, et permettent de structurer n'importe quel type de donnée.

    Le JSON

    JSON (JavaScript Object Notation) est un format texte qui permet de structurer de maniere légère des données. C'est une alternative au format XML.

    Il structure les données liste (pour une série de données) ou en objet (pour un dictionnaire clé/valeur). Ces structures peuvent être combinées.

    Exemple d'objet :

    { "nom": "Bob", "mail": "bob@cnam.fr", "age": 54 }

    Exemple de liste :

    [ "Bob", "John", "Jack" ]

    Exemple de liste d'objets :

    [ { "nom": "Bob", "mail": "bob@cnam.fr", "age": 54 }, { "nom": "John", "mail": "john@cnam.fr", "age": 12 }, { "nom": "Jack", "mail": "jackiedu13@cnam.fr", "age": 43 } ]

    Exemple concret :

    { "data": { "current_condition": [ { "cloudcover": "0", "humidity": "36", "localObsDateTime": "2013-04-15 02:47 PM", "observation_time": "12:47 PM", "precipMM": "0.0", "pressure": "1023", "temp_C": "23", "temp_F": "73", "visibility": "10", "weatherCode": "113", "weatherDesc": [ { "value": "Sunny" } ], "weatherIconUrl": [ { "value": "http://www.worldweatheronline.com/sunny.png" } ], "winddir16Point": "W", "winddirDegree": "270", "windspeedKmph": "11", "windspeedMiles": "7" } ], "nearest_area": [ { "areaName": [ { "value": "Aix" } ], "country": [ { "value": "France" } ], "latitude": "43.533", "longitude": "5.433", "population": "0", "region": [ { "value": "Provence-Alpes-Cote D'azur" } ], "weatherUrl": [ { "value": "http://www.worldweatheronline.com/FR.aspx" } ] } ] } }

    JSON et Android

    Android inclut des outils pour traiter le JSON : les classes JSONObject et JSONArray.

    A partir d'un objet String, on peut parcourir la structure JSON grace à ces objets.

    Attention, lorsque l'on tente de traiter une réponse JSON, on s'attends à une structure particulière. Le serveur peut, pour de nombreuses raisons, nous renvoyer des données que l'on attends pas. Il faut donc penser à traiter les cas d'erreurs pour éviter que notre application se crashe.

    Exemple simple :

    Voici un exemple de réponse d'un web-service :

    { "message": "Hello, Bob !", "name": "Bob", "datation": { "date": "16-04-2013", "horaire": "19:30:54" } }

    En utilisant le code du client Http minimal :

    //recupere le contenu de la réponse String content = EntityUtils.toString(response.getEntity()); //a partir de la chaine de caractere, on peut parcourir le JSON... JSONObject racine = new JSONObject(content); String message = racine.getString("message"); String nom = racine.getString("name"); //...puis decendre dans la structure JSONObject datation = racine.getJSONObject("datation"); String date = datation.getString("date"); String horaire = datation.getString("horaire"); System.out.println("Message : " + message + ", date : " + date + ", heure : " + horaire);

    Message : Hello, world !, date : 16-04-2013, heure : 19:33:52

    Exemple sur les données de "World Weather Online"

    A partir du JSON du web-service "World Weather Online" (www.worldweatheronline.com/free-weather.aspx) :

    { "data": { "current_condition": [ { "cloudcover": "0", "humidity": "36", "localObsDateTime": "2013-04-15 02:47 PM", "observation_time": "12:47 PM", "precipMM": "0.0", "pressure": "1023", "temp_C": "23", "temp_F": "73", "visibility": "10", "weatherCode": "113", "weatherDesc": [ { "value": "Sunny" } ], "weatherIconUrl": [ { "value": "http://www.worldweatheronline.com/sunny.png" } ], "winddir16Point": "W", "winddirDegree": "270", "windspeedKmph": "11", "windspeedMiles": "7" } ], "nearest_area": [ { "areaName": [ { "value": "Aix" } ], "country": [ { "value": "France" } ], "latitude": "43.533", "longitude": "5.433", "population": "0", "region": [ { "value": "Provence-Alpes-Cote D'azur" } ], "weatherUrl": [ { "value": "http://www.worldweatheronline.com/FR.aspx" } ] } ] } }

    Pour récupérer la température en degré Celsius :

    On voit qu'elle se trouve dans data/current_condition/0/temp_C.

    Il y a 2 niveaux d'objets (data, current_condition), puis un tableau contenant un seul élément, et enfin la propriété (temp_C)

    //recupere le contenu de la réponse String content = EntityUtils.toString(response.getEntity()); //a partir de la chaine de caractere, on peut parcourir le JSON... JSONObject racine = new JSONObject(content); JSONObject data = racine.getJSONObject("data"); //data JSONArray conditions = data.getJSONArray("current_condition"); //les elements de current_condition JSONObject firstCondition = conditions.getJSONObject(0); //le premier (et seul) element du tableau int temperature = firstCondition.getInt("temp_C"); //on a notre valeur!

    Une autre option plus compacte (sur une seule ligne) :

    int temperature = json.getJSONObject("data") .getJSONArray("current_condition") .getJSONObject(0) .getInt("temp_C");

    Pour récupérer l'information de la ville :

    On voit qu'elle se trouve dans data/nearest_area/0/areaName/0/value.

    Il y a 2 niveaux d'objets (data, nearest_area), puis un tableau contenant un seul élément, un tableau (areaName) contenant un seul élément et enfin l'objet contenant la propriété (value)

    //recupere le contenu de la réponse String content = EntityUtils.toString(response.getEntity()); //a partir de la chaine de caractere, on peut parcourir le JSON... JSONObject racine = new JSONObject(content); JSONObject data = racine.getJSONObject("data"); //data JSONArray nearestAreas = data.getJSONArray("nearest_area"); //les elements de nearest_area JSONObject firstArea = nearestAreas.getJSONObject(0); //le premier (et seul) element du tableau JSONArray areaNames = firstArea.getJSONArray("areaName"); JSONObject firstAreaName = areaNames.getJSONObject(0); //le premier (et seul) element du tableau String city = firstAreaName.getString("value"); //on a notre valeur!

    Une autre option plus compacte (sur une seule ligne) :

    String ville = json.getJSONObject("data") .getJSONArray("nearest_area") .getJSONObject(0) .getJSONArray("areaName") .getJSONObject(0) .getString("value");

    Pour récupérer la "description" de la prévision :

    On voit qu'elle se trouve dans data/current_condition/0/weatherDesc/0/value.

    //recupere le contenu de la réponse String content = EntityUtils.toString(response.getEntity()); //a partir de la chaine de caractere, on peut parcourir le JSON... JSONObject racine = new JSONObject(content); JSONObject data = racine.getJSONObject("data"); //data JSONArray conditions = data.getJSONArray("current_condition"); //les elements de current_condition JSONObject firstCondition = conditions.getJSONObject(0); //le premier (et seul) element du tableau JSONArray description = firstCondition.getJSONArray("weatherDesc"); JSONObject firstDescription = description.getJSONObject(0); String description = firstDescription.getString("value"); //on a notre valeur!

    Une autre option plus compacte (sur une seule ligne) :

    int temperature = json.getJSONObject("data") .getJSONArray("current_condition") .getJSONObject(0) .getJSONArray("weatherDesc") .description.getJSONObject(0) .getString("value");

    Exercice :

    Réaliser une application qui utilise le web-service JSON de test : http://nee.free.fr/testApi/test.php?format=json.

    L'application affichera le message reçu, ainsi que la date et l'horaire, ou un message d'erreur générique en cas de problème.

    Etapes :

    Exercice :

    Réaliser une application qui utilise le web-service de météo (worldweatheronline.com).

    Adresse de la documentation de l'API : http://developer.worldweatheronline.com/io-docs

    Exemple de positions :

    Clef pour les tests au CNAM (limité à 3 requetes par seconde et 500 par jour) : wrxysf4jz4e8prtapychkkk8

    Les pictos se trouvent dans une archive à télécharger : nee.free.fr/testApi/pictoMeteo.zip

    Exemple de requete complète pour Aix :

    http://api.worldweatheronline.com/free/v1/weather.ashx ?q=43.529742,5.447427 &format=json &includelocation=yes &key=wrxysf4jz4e8prtapychkkk8

    Cahier des charges

    Composition de l'application:

    Etapes :

    Annnexe :

    Modifier la taille d'un TextView

    Ajouter l'attribut dans le XML

    android:textAppearance="?android:attr/textAppearanceLarge"

    Gérer les images dans les "resources"

    Récuperer une image existante (qui se trouve dans res/drawable***/monfichier.png)

    int pointeurVersMonImage = R.drawable.monfichier;

    Afficher un "drawable" dans une ImageView

    monImageView.setImageResource(R.drawable.monfichier); //ou monImageView.setImageResource(pointeurVersMonImage);

    Les codes du webservice :
  • 113 : image "sunny.png" et commentaire "Soleil"
  • 116 ou 119 : image "cloudy.png" et commentaire "Nuageux"
  • tous les autres codes : image "rainy.ong" et commentaire "vous devriez demenager dans le sud"