I. Prérequis▲
- Être un développeur Android.
- Être capable de créer un service web si vous ne l'avez jamais fait auparavant, ce tutoriel vous sera d'une grande utilité (lien : https://netbeans.org/kb/docs/websvc/jax-ws.html).
- La bibliothèque Ksoap2 à télécharger ici : https://code.google.com/p/ksoap2-android/source/browse/m2-repo/com/google/code/ksoap2-android/ksoap2-android-assembly/3.4.0/ksoap2-android-assembly-3.4.0-jar-with-dependencies.jar.
- Enfin, un service web disponible et fonctionnel.
II. Téléchargement de la bibliothèque KSOAP2▲
Si je le présente ici, c'est parce que cela m'avait coûté des heures et des heures ce téléchargement et que je voudrais vous éviter de justesse cette peine.
Pour commencer, cliquez ici (https://code.google.com/p/ksoap2-android/source/browse/m2-repo/com/google/code/ksoap2-android/ksoap2-android-assembly/3.4.0/ksoap2-android-assembly-3.4.0-jar-with-dependencies.jar) et vous serez directement redirigé vers la page de téléchargement (ce qui vous évite en fait de fouiller tout le web avant d'y atterrir).
Ensuite, dans la page qui sera affichée, rendez-vous dans la partie le plus à droite et sous File info, faites un clic droit sur le lien View raw file et choisissez dans le menu contextuel qui s'affiche « enregistrer sous… ». Le fichier sera téléchargé et disponible dans votre emplacement de téléchargement.
III. Présentation du service web▲
J'ai créé un service web simple n'ayant qu'une seule méthode qui calcule la moyenne de trois nombres entiers (int) qui lui sont passés en paramètres et qui retourne un décimal (float) comme résultat de ce calcul. Cette méthode se présente comme suit :
2.
3.
4.
5.
6.
7.
/**
* Web service operation
*/
@WebMethod
(
operationName =
"calculMoyenne"
)
public
float
calculMoyenne
(
@WebParam
(
name =
"a"
) int
a, @WebParam
(
name =
"b"
) int
b, @WebParam
(
name =
"c"
) int
c) {
return
(
float
) (
a +
b +
c) /
3
;
}
Quand vous allez créer le service web que vous voudrez consommer plus tard (depuis votre client Android), veillez retenir les informations suivantes :
- L'URL du service web à consommer : celle qui vous permettra d'atteindre les méthodes que vous allez appeler (les services) ;
- Le namespace : le nom du package dans lequel le fichier représentant votre service web est défini. Je ne vais pas entrer dans le détail, mais c'est hyper important ;
- Le nom de la méthode à évoquer : trop simple à deviner n'est-ce pas ? Ce n'est rien d'autre que le nom de la méthode (ou des méthodes) du service web que vous allez appeler (consommer) depuis le client Android ;
- Et pour finir, les noms de tous les paramètres que demande la méthode : il faut faire très attention à la casse.
Toutes ces informations dans mon cas se présentent de la manière suivante :
- URL : http://192.168.43.5:8080/WSCalcul/Calculs?WSDL ;
- NAMESPACE : http://webservice.tutows.com/ ;
- METHODNAME : calculMoyenne ;
- PARAMETRES : a, b, c.
IV. Les carottes étant cuites, passons à l'acte▲
Maintenant, tout étant prêt, nous allons passer à l'écriture de notre client Android. Suivez attentivement les étapes ci-dessous et tout vous sera facile.
IV-A. Ajout la bibliothèque KSaop2 téléchargée dans le classPath de notre projet▲
Créer un nouveau projet Android (comme vous en avez l'habitude d'ailleurs), copier KSaop2 de son emplacement et la coller dans le dossier libs de votre projet.
IV-B. Création l'interface graphique de l'application (activity_main.xml)▲
Elle aura trois zones de texte qui permettront chacune la saisie d'un nombre, un bouton dans lequel nous allons appeler le service web et un label en dessous du bouton pour affichage du résultat. Elle se présente comme suit :
Voici le code ayant permis d'aboutir à cette fin :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
<LinearLayout
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
xmlns
:
tools
=
"http://schemas.android.com/tools"
android
:
layout_width
=
"match_parent"
android
:
layout_height
=
"match_parent"
android
:
orientation
=
"vertical"
android
:
paddingBottom
=
"@dimen/activity_vertical_margin"
android
:
paddingLeft
=
"@dimen/activity_horizontal_margin"
android
:
paddingRight
=
"@dimen/activity_horizontal_margin"
android
:
paddingTop
=
"@dimen/activity_vertical_margin"
tools
:
context
=
"com.abara.tutows.MainActivity"
>
<EditText
android
:
id
=
"@+id/txt_nombre1"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
layout_marginTop
=
"10dp"
android
:
ems
=
"10"
android
:
hint
=
"Premier nombre"
android
:
inputType
=
"number"
/>
<EditText
android
:
id
=
"@+id/txt_nombre2"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
layout_marginTop
=
"10dp"
android
:
ems
=
"10"
android
:
hint
=
"Deuxième nombre"
android
:
inputType
=
"number"
/>
<EditText
android
:
id
=
"@+id/txt_nombre3"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
layout_marginTop
=
"10dp"
android
:
ems
=
"10"
android
:
hint
=
"Troisième nombre"
android
:
inputType
=
"number"
/>
<Button
android
:
id
=
"@+id/btn_calculer"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
layout_marginTop
=
"10dp"
android
:
text
=
"Calculer"
android
:
textStyle
=
"italic"
android
:
typeface
=
"serif"
/>
<TextView
android
:
id
=
"@+id/lbl_resultat"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
layout_marginTop
=
"20dp"
android
:
ellipsize
=
"end"
android
:
singleLine
=
"true"
android
:
textColor
=
"#FF0000"
android
:
textSize
=
"20sp"
android
:
textStyle
=
"italic|bold"
android
:
typeface
=
"serif"
/>
</LinearLayout>
IV-C. Code métier (MainActivity.java)▲
Je vais directement dans le but du sujet qui concerne l'écriture du code du bouton « calculer » qui appelle le service web, récupère le résultat et l'affiche sur écran.
Pour commencer, nous rappelons que l'objectif est de consommer un service web ayant une méthode qui permet de calculer et renvoyer la moyenne de trois nombres entiers que nous aurions passés en paramètres. Nous avons déjà toutes les informations primordiales pour atteindre notre objectif à savoir :
- l'URL du service web (au fait l'adresse de son fichier wsdl) ;
- son namespace (qui n'est rien d'autre que le nom du package dans lequel la classe représentant notre service web est définie, suivi du caractère « / ») ;
- le nom de la méthode (c'est elle qui fera le calcul de la moyenne) ;
- les noms de tous les paramètres formels de la méthode ci-dessus (respecter la casse).
Ce qui nous amène à déclarer les constantes suivantes :
2.
3.
4.
final
String URL =
"http://192.168.43.5:8080/WSTuto/Calculs?WSDL"
;
final
String NAMESPACE =
"http://webservice.tutows.com/"
;
final
String METHODNAME =
"calculMoyenne"
;
final
String [] PARAMETRES =
{
"a"
, "b"
, "c"
}
;
Pour éviter d'écrire plusieurs lignes, j'ai regroupé tous les paramètres dans un tableau. Croyez-moi, ce ne sera pas compliqué par la suite pour accéder à chacun d'entre eux.
N.B. En guise d'exemple j'ai utilisé les chaînes de caractères en dur. Cette pratique n'est pas recommandée dans un projet réel.
IV-D. Préparation de la requête▲
Nous allons commencer par créer un objet SoapObject pour préparer la requête à envoyer au serveur. Nous allons passer dans son constructeur le namespace (le premier paramètre requis), ainsi que le nom de la méthode à évoquer (deuxième paramètre).
SoapObject requete =
new
SoapObject
(
NAMESPACE, METHODNAME);
Ensuite, nous allons passer les paramètres à la méthode que nous souhaitons appeler. Pour passer ces paramètres, nous allons faire appel à la méthode addProperty() de l'objet requete que nous avons créé précédemment autant de fois que le nombre de paramètres à renseigner.
2.
3.
4.
5.
6.
7.
try
{
requete.addProperty
(
parametres[0
], Integer.parseInt
(
txt_nombre1.getText
(
).toString
(
)));
requete.addProperty
(
parametres[1
], Integer.parseInt
(
txt_nombre2.getText
(
).toString
(
)));
requete.addProperty
(
parametres[2
], Integer.parseInt
(
txt_nombre3.getText
(
).toString
(
))) ;
}
catch
(
Exception e){
Log.e
(
"MainActivity"
, e.getMessage
(
));
}
Les valeurs des paramètres sont bien renseignées, notre requête est bel et bien prête.
IV-E. Création de l'enveloppe▲
Maintenant, nous allons créer une enveloppe que nous allons utiliser pour envoyer notre requête au serveur, mais aussi à travers laquelle nous traiterons le résultat que le serveur nous aurait renvoyé. Cet objet permet les échanges entre le client Android et le serveur (service web).
SoapSerializationEnvelope enveloppe =
new
SoapSerializationEnvelope
(
SoapEnvelope.VER11);
La construction de cet objet demande un entier dans le constructeur représentant la version du SOAP que le service web utilise. Dans mon cas, c'est la version 1.1, c'est pourquoi j'ai choisi la valeur SoapEnvelope.VER11.
Nous allons à présent configurer l'enveloppe que nous venons de créer en passant la requête qu'elle doit véhiculer.
enveloppe.setOutputSoapObject
(
requete);
N.B. Si votre service web est créé en .NET, vous serez dans l'obligation de le signaler dans votre enveloppe avant d'envoyer la requête au serveur pour assurer la compatibilité avec ce qui semble être l'encodage par défaut pour .Net -Services, sinon ça ne marchera pas. Pour ce faire, ajouter simplement la ligne ci-dessous :
enveloppe.dotNet =
true
;
IV-F. Envoi de la requête au serveur▲
Pour envoyer la requête contenue dans l'enveloppe, nous allons premièrement construire un objet qui fera le transport et lui passer l'URL de notre service web en paramètre de son constructeur. L'exécution de la requête sera faite dans un thread séparé (dans le code complet, j'ai créé une méthode dans laquelle j'ai placé cette exécution, ensuite j'ai utilisé l'AnsycTast pour l'appeler dans un thread séparé).
HttpTransportSE http_transport =
new
HttpTransportSE
(
URL);
Ensuite, exécutons la requête en appelant la méthode call(...) du httpTransportSE. Nous allons lui passer comme paramètres :
- un String (SoapAction), qui est la concaténation du « namespace » et du nom de la méthode à évoquer ;
- une enveloppe (SoapSerializationEnvelope).
http_transport.call
(
NAMESPACE +
METHODNAME, enveloppe);
IV-G. Récupération du résultat▲
Pour récupérer le résultat renvoyé par le serveur, nous allons procéder de la manière suivante :
- tout d'abord, du fait qu'il s'agit d'un résultat de type primitif, nous allons créer un objet de type SoapPrimitive dans lequel nous allons mettre le résultat obtenu de l'enveloppe en appelant la méthode getResponse().
SoapPrimitive reponse =
(
SoapPrimitive)enveloppe.getResponse
(
);
- ensuite, nous allons caster ce résultat en float. float resultat_float = Float.parseFloat(reponse.toString());.
Nous pouvons résumer l'envoi de la requête et la réception du résultat par (à appeler dans un thread séparé) :
2.
3.
4.
5.
6.
7.
8.
9.
try
{
//Envoi de la requête
http_transport.call
(
NAMESPACE +
METHODNAME, enveloppe);
//Récupération du résultat et traitement
SoapPrimitive reponse =
(
SoapPrimitive)enveloppe.getResponse
(
);
resultat_float =
Float.parseFloat
(
reponse.toString
(
));
}
catch
(
Exception e) {
Log.e
(
"Erreur lors de l'envoi de la requête : "
, e.getMessage
(
));
}
IV-H. Code Complet▲
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
// Déclaration des variables et objets de l'interface graphique
EditText txt_nombre1;
EditText txt_nombre2;
EditText txt_nombre3;
Button btn_calculer;
TextView lbl_resultat;
ProgressDialog progression;
// Préparation des données pour le service web
final
String URL =
"http://192.168.43.5:8080/WSTuto/Calculs?WSDL"
;
final
String NAMESPACE =
"http://webservice.tutows.com/"
;
final
String METHODNAME =
"calculMoyenne"
;
final
String [] PARAMETRES =
{
"a"
, "b"
, "c"
}
;
// Inflation des composants graphiques
txt_nombre1 =
(
EditText)findViewById
(
id.txt_nombre1);
txt_nombre2 =
(
EditText)findViewById
(
id.txt_nombre2);
txt_nombre3 =
(
EditText)findViewById
(
id.txt_nombre3);
lbl_resultat =
(
TextView)findViewById
(
id.lbl_resultat);
btn_calculer =
(
Button)findViewById
(
id.btn_calculer);
// Méthode dans laquelle nous appelons le service web et récupérons le résultat renvoyé par ce dernier
public
float
executionRequete
(
String url, String namespace, String methodName, String [] parametres){
float
resultat_float =
0
f;
//Préparation de la requête
SoapObject requete =
new
SoapObject
(
namespace, methodName);
//Renseignement des valeurs des paramètres
try
{
requete.addProperty
(
parametres[0
], Integer.parseInt
(
txt_nombre1.getText
(
).toString
(
)));
requete.addProperty
(
parametres[1
], Integer.parseInt
(
txt_nombre2.getText
(
).toString
(
)));
requete.addProperty
(
parametres[2
], Integer.parseInt
(
txt_nombre3.getText
(
).toString
(
))) ;
}
catch
(
Exception e) {
Log.e
(
"MainActivity"
, e.getMessage
(
));
}
//Création de l'enveloppe
SoapSerializationEnvelope enveloppe =
new
SoapSerializationEnvelope
(
SoapEnvelope.VER11);
//Ajout de la requête dans l'enveloppe
enveloppe.setOutputSoapObject
(
requete);
//Envoi de la requête et traitement du résultat
HttpTransportSE http_transport =
new
HttpTransportSE
(
url);
try
{
http_transport.call
(
namespace +
methodName, enveloppe);
SoapPrimitive reponse =
(
SoapPrimitive)enveloppe.getResponse
(
);
resultat_float =
Float.parseFloat
(
reponse.toString
(
));
}
catch
(
Exception e) {
Log.e
(
"Erreur lors de l'envoi de la requête : "
, e.getMessage
(
));
}
//Retourner le résultat du calcul
return
resultat_float;
}
// Classe qui étend AsyncTask pour l'exécution séparée
private
class
AppelWs extends
AsyncTask<
String, String, Float>{
@Override
protected
void
onPreExecute
(
) {
// TODO Auto-generated method stub
progression =
new
ProgressDialog
(
MainActivity.this
);
progression.setTitle
(
"Appel au service web"
);
progression.show
(
);
}
@Override
protected
void
onProgressUpdate
(
String... values) {
// TODO Auto-generated method stub
progression.setMessage
(
values[0
]);
}
@Override
protected
Float doInBackground
(
String... params) {
publishProgress
(
"Calcul en cours..."
);
float
r =
executionRequete
(
URL, NAMESPACE, METHODNAME, PARAMETRES);
return
r;
}
@Override
protected
void
onPostExecute
(
Float result) {
// Affichage du résultat dans le textView et disparition de la //progressDialog
lbl_resultat.setText
(
"La moyenne donne : "
+
result);
progression.dismiss
(
);
}
}
// Gestion du clic sur le bouton pour appeler le service web et afficher le résultat du calcul
btn_calculer.setOnClickListener
(
new
View.OnClickListener
(
) {
@Override
public
void
onClick
(
View v){
AppelWs ws =
new
AppelWs
(
);
ws.execute
(
);
}
}
);
V. Conclusion▲
Nous venons d'apprendre à consommer simplement et d'une grande facilité un service web depuis un client Android en se servant de la bibliothèque Ksoap2. Certes, ce n'était qu'une introduction, mais je vous assure que nous avons fait un très grand pas pour appréhender les concepts les plus avancés. Dans les prochains tutoriels, nous verrons comment exploiter un peu plus cette bibliothèque pour des opérations complexes telles que l'interrogation d'une base de données, la mise à jour… Bref, nous verrons comment traiter les données de type complexe (les objets).
Entre temps, vous remarques et suggestions me feront énormément plaisir et contribueront à l'amélioration de ce tutoriel.
VI. Remerciements▲
- Je tiens à remercier premièrement Feanorin de m'avoir donné le courage de rédiger cet article, de m'aider à avoir mon espace de rédaction et surtout pour la relecture technique de ce tutoriel. Grand merci à toi.
- Je remercie aussi Mickael Baron pour le temps qu'il a consacré pour la relecture technique de ce tutoriel malgré ses multiples occupations. Il m'a été d'un guide important tout au long de rédaction et correction de ce tutoriel, mais aussi dans la mise sous format developpez.com.
- Je ne pouvais pas oublier de remercier Grunk, lui qui n'a pas hésité de relire ce tutoriel que je lui avais demandé une relecture technique et qui m'a apporté des remarques constructives qui ont abouti à la présentation du code complet du petit projet d'essai mettant en évidence tout ce que nous avons appris ici.
- Je remercie au finish claudeLELOUP de sa disponibilité pour que ce tutoriel bénéficie d'une correction orthographique adéquate.