Contrairement à avant où nous pouvions soit coder manuellement les informations d'identification de connexion, telles que le nom d'utilisateur, dans l'application et vérifier que l'utilisateur a fourni les bonnes informations, soit stocker les informations d'identification dans une base de données locale appelée SQLite, de nos jours les applications Android agissent comme un sous-module pour les applications web, où les données stockées sur le serveur web en ligne sont utilisées dans les applications Android.
Les utilisateurs ont le choix entre utiliser une application web ou une application Android pour atteindre le même objectif, par conséquent, les données doivent être en temps réel lors de l'accès à l'application web ou à l'application Android.
Dans cet article, nous verrons comment se connecter sur Android en utilisant une API Rest. Pour ce faire, nous aurons besoin d'un serveur en ligne pour valider le nom d'utilisateur et le mot de passe, puis en fonction du résultat donné par l'API Rest, rediriger l'utilisateur.
Précédemment, nous avons discuté de la création d'une application de connexion simple sur Android, où nous vous avons montré comment créer des TextView, EditText et des boutons pour saisir des données dans l'application Android. Nous avons également montré comment collecter les données du fichier XML vers le fichier d'activité principale. De plus, nous avons discuté de la création d'une API Rest en PHP et également de la façon de tester l'API à l'aide de Postman.
Pour cet article, nous allons directement passer à la connexion de l'application Android avec l'API Rest et montrer comment envoyer et recevoir des données vers le serveur en utilisant la méthode Async task sur Android.
Pour rendre la référence plus claire, le code ci-dessous présente le fichier XML contenant la conception de l'écran de connexion.
Ce code démontre la manière de récupérer les informations du fichier XML dans le fichier Java.
// ...
EditText username, password;
Button login;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
username = (EditText) findViewById(R.id.username);
password = (EditText) findViewById(R.id.password);
login = (Button) findViewById(R.id.login);
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(username.getText().toString().equals("")){
Toast.makeText(getApplicationContext(), "Username cannot be blank", Toast.LENGTH_SHORT).show();
}else if(password.getText().toString().equals("")){
Toast.makeText(getApplicationContext(), "password cannot be blank", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(), "login method to proceed", Toast.LENGTH_SHORT).show();
}
}
});
}
Le code ci-dessous est le code de l'API REST développé en utilisant PHP et MySQL qui traitera les données envoyées par le code Android.
PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
throw new PDOException($e->getMessage(), (int)$e->getCode());
}
// Récupération des valeurs envoyées par l'application externe
$email = $_POST["email"];
$password = $_POST["password"];
// Requête pour vérifier si les valeurs correspondent à celles de la base de données
$stmt = $pdo->prepare("SELECT * FROM clients WHERE Email=:email AND Password=:password");
$stmt->execute(['email' => $email, 'password' => $password]);
$count = $stmt->rowCount();
// Affichage du message de succès ou d'erreur sous forme de tableau JSON
if ($count > 0) {
$json = array("status" => 200, "message" => "Success");
} else {
$json = array("status" => 400, "message" => "Error");
}
echo json_encode($json);
// Fermeture de la connexion à la base de données
$pdo = null;
?>
Ensuite, dans le fichier de manifeste, ajoutez la permission internet qui permettra à l'application d'envoyer et d'accéder aux données du serveur en ligne.
Le code complet du fichier manifeste est le suivant :
Ensuite, nous allons ajouter le code qui collecte le nom d'utilisateur et le mot de passe en utilisant la méthode AsyncTask.
- Tout d'abord, définissez la méthode qui sera appelée lorsque le bouton de connexion est cliqué. Par exemple, pour ce tutoriel, la méthode utilisée est Login().
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(username.getText().toString().equals("")){
Toast.makeText(getApplicationContext(), "Username cannot be blank", Toast.LENGTH_SHORT).show();
}else if(password.getText().toString().equals("")){
Toast.makeText(getApplicationContext(), "password cannot be blank", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(), "login method to proceed", Toast.LENGTH_SHORT).show();
Login lg = new Login(MainActivity.this);
lg.execute();
}
}
});
- Après avoir fermé la méthode onCreate, vous devrez maintenant implémenter la méthode Login et vous assurer qu'elle étend AsyncTask pour qu'elle puisse utiliser ses propriétés.
- L'AsyncTask a différentes parties et effectue ses activités dans un ordre synchrone, c'est-à-dire une à la fois.
Il a une méthode "onPreExecute" de pré-exécution qui informe l'utilisateur que le processus a commencé. À ce stade, la barre de progression est généralement affichée pour faire en sorte que l'utilisateur reste à cet endroit et attende le résultat.
La méthode "doInBackground" où vous définissez l'URL où vous voulez que les variables, c'est-à-dire le nom d'utilisateur et le mot de passe, soient envoyées, et également où vous ouvrez la connexion HTTP.
La méthode "onProgressUpdate" ne fait pas grand-chose d'autre que de mettre à jour la progression de la demande.
La méthode "onPostExecute" renvoie le résultat et c'est à ce moment-là que les décisions sont prises.
Le code ci-dessous montre le code java complet avec la connexion complète en utilisant REST API et la méthode de tâche asynchrone.
package com.maestrislyon.simpleloginpage;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
public class MainActivity extends AppCompatActivity {
EditText username, password;
Button login;
String userVar, passVar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
username = findViewById(R.id.username);
password = findViewById(R.id.password);
login = findViewById(R.id.login);
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
userVar = username.getText().toString();
passVar = password.getText().toString();
if (userVar.equals("")) {
Toast.makeText(getApplicationContext(), "Username cannot be blank", Toast.LENGTH_SHORT).show();
} else if (passVar.equals("")) {
Toast.makeText(getApplicationContext(), "password cannot be blank", Toast.LENGTH_SHORT).show();
} else {
//Toast.makeText(getApplicationContext(), "login method to proceed", Toast.LENGTH_SHORT).show();
Login lg = new Login(MainActivity.this);
lg.execute();
}
}
});
}
class Login extends AsyncTask {
AlertDialog alertDialog;
Context context;
ProgressDialog progressDialog;
Login(Context ctx) {
this.context = ctx;
}
@Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(context, "", "Logging you in... Please wait");
}
@Override
protected Integer doInBackground(String... params) {
String login_url = "http://temp.itds.fr/login_tst.php";
try {
URL url = new URL(login_url);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(10000);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
OutputStream os = httpURLConnection.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
String data = URLEncoder.encode("email", "UTF-8") + "=" + URLEncoder.encode(userVar, "UTF-8") + "&" +
URLEncoder.encode("password", "UTF-8") + "=" + URLEncoder.encode(passVar, "UTF-8");
bufferedWriter.write(data);
bufferedWriter.flush();
bufferedWriter.close();
os.close();
int responseCode = httpURLConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
StringBuilder response = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
response.append(line);
}
bufferedReader.close();
inputStream.close();
JSONObject jsonObject = new JSONObject(response.toString());
return jsonObject.getInt("status");
} else {
return HttpURLConnection.HTTP_BAD_REQUEST;
}
} catch (IOException | JSONException e) {
e.printStackTrace();
return HttpURLConnection.HTTP_BAD_REQUEST;
}
}
@Override
protected void onPostExecute(Integer status) {
progressDialog.dismiss();
if (status == HttpURLConnection.HTTP_OK) {
username.setText("");
password.setText("");
Toast.makeText(context, "Login successful", Toast.LENGTH_SHORT).show();
} else if (status == HttpURLConnection.HTTP_BAD_REQUEST) {
Toast.makeText(context, "Incorrect username or password", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Failed to connect to server. Please check your internet connection and try again.", Toast.LENGTH_LONG).show();
}
}
}
}
Des explications et des astuces
La classe AsyncTask : exécuter des tâches en arrière-plan
AsyncTask
est une classe fournie par Android qui permet d'exécuter des tâches de fond en arrière-plan tout en restant dans le fil d'exécution principal de l'application.
Dans le contexte du développement Android, l'utilisation d'AsyncTask
est courante pour effectuer des opérations qui peuvent prendre du temps et ne doivent pas bloquer l'interface utilisateur. Par exemple, une tâche de fond peut consister à télécharger des données à partir d'un serveur, à traiter des images ou à effectuer d'autres opérations qui ne doivent pas interrompre la réponse de l'interface utilisateur.
AsyncTask
fonctionne en exécutant trois méthodes principales : onPreExecute()
, doInBackground()
et onPostExecute()
.
La méthode onPreExecute()
est exécutée avant le démarrage de la tâche et peut être utilisée pour effectuer des initialisations nécessaires à la tâche.
La méthode doInBackground()
est exécutée dans un fil d'exécution séparé et est utilisée pour effectuer des tâches de fond qui peuvent prendre du temps. Cette méthode ne doit pas accéder à l'interface utilisateur.
Enfin, la méthode onPostExecute()
est exécutée après l'exécution de la tâche de fond et peut être utilisée pour mettre à jour l'interface utilisateur en fonction des résultats de la tâche.
En utilisant AsyncTask
, vous pouvez exécuter des tâches de fond de manière asynchrone, sans bloquer l'interface utilisateur, et mettre à jour l'interface utilisateur une fois que la tâche de fond est terminée.
La syntaxe des paramètres de type générique
La syntaxe des paramètres de type générique dans les chevrons '< >'
est utilisée pour déclarer les types de données que l'AsyncTask prend en entrée, qui sont utilisées dans les méthodes de l'AsyncTask (doInBackground(), onProgressUpdate(), onPostExecute()
, etc.).
Les types de données qui doivent être déclarées dans les chevrons sont :
- Params : Le type des paramètres que vous passez à la méthode
doInBackground()
. - Progress : Le type des informations de progression que vous passez à la méthode
onProgressUpdate()
. - Result : Le type du résultat renvoyé par la méthode
doInBackground()
et utilisé comme paramètre pour la méthodeonPostExecute()
.
La déclaration de type générique dans les chevrons '< >'
est similaire à la déclaration de paramètres de méthode entre parenthèses '()'
mais elle est spécifique à la déclaration de types génériques dans une classe.
C'est quoi AlertDialog ?
AlertDialog
est une boîte de dialogue prédéfinie dans Android qui permet d'afficher une fenêtre de dialogue avec un message et des boutons pour permettre à l'utilisateur de prendre une décision ou d'effectuer une action.
Dans le contexte de l'application, AlertDialog alertDialog
est une variable membre de la classe Login
qui est utilisée pour stocker l'instance de la boîte de dialogue qui sera affichée lors de la tentative de connexion. Cette boîte de dialogue est initialisée dans la méthode onPreExecute()
de la classe Login
, qui est appelée avant que la tâche d'arrière-plan ne soit exécutée. Cette boîte de dialogue sera fermée dans la méthode onPostExecute()
lorsque la tâche d'arrière-plan sera terminée.
L'utilisation d'une boîte de dialogue dans ce contexte est utile pour informer l'utilisateur que la connexion est en cours, afin de l'informer du statut de la connexion et de lui permettre de prendre les mesures appropriées en cas de problème. Cela peut améliorer l'expérience utilisateur en offrant une rétroaction rapide et claire sur les actions en cours.
C'est quoi Context ?
Context
est une classe abstraite de base pour les informations d'environnement global d'une application. Elle est utilisée pour accéder aux ressources et aux services du système d'exploitation Android, tels que les préférences partagées, les fichiers de ressources, etc.
Dans ce contexte, la variable Context
est utilisée pour définir le contexte de l'application qui sera utilisé pour créer et afficher des boîtes de dialogue (par exemple, l'objet AlertDialog
est créé en utilisant le contexte fourni). La variable est initialisée dans le constructeur de la classe Login
, et ensuite utilisée dans la méthode ProgressDialog.show()
pour afficher une boîte de dialogue de progression pendant que la requête de connexion est effectuée en arrière-plan.
C'est quoi ProgressDialog ?
ProgressDialog
est une boîte de dialogue qui affiche une barre de progression indiquant que l'application est occupée à effectuer une tâche. Dans ce contexte, il est utilisé pour afficher une boîte de dialogue de progression lors de la tentative de connexion au serveur, afin d'indiquer à l'utilisateur que l'application est en train de travailler.
La classe ProgressDialog
hérite de la classe AlertDialog
et peut être utilisée de la même manière pour afficher une boîte de dialogue modale, avec un titre et un message personnalisés, ainsi qu'une icône et une barre de progression pour afficher la progression d'une tâche en cours. La boîte de dialogue est fermée automatiquement lorsque la tâche est terminée.
Pour créer une instance de ProgressDialog
, on peut utiliser le constructeur ProgressDialog(Context context)
. Le paramètre context
est utilisé pour créer la boîte de dialogue avec le thème approprié, en fonction du contexte de l'application. Ensuite, on peut utiliser les méthodes setMessage(String message)
et setTitle(String title)
pour personnaliser le titre et le message de la boîte de dialogue, et la méthode setCancelable(boolean cancelable)
pour spécifier si la boîte de dialogue peut être annulée en cliquant sur le bouton retour ou non.
Dans le code de l'exemple, ProgressDialog
est utilisé pour afficher une boîte de dialogue modale avec le message "Logging you in... Please wait", pour indiquer à l'utilisateur que la connexion est en cours. La boîte de dialogue est créée dans la méthode onPreExecute()
de la classe Login
, puis affichée à l'utilisateur. Enfin, la boîte de dialogue est fermée automatiquement lorsque la tâche est terminée, dans la méthode onPostExecute()
de la classe Login
.
Le constructeur Login()
La ligne de code Login(Context ctx) { this.context = ctx; }
est le constructeur de la classe interne Login
, qui étend la classe AsyncTask
. Cette ligne permet d'initialiser le contexte (Context
) de l'activité principale (la classe MainActivity
) dans laquelle l'objet Login
est créé.
En effet, le contexte est une référence à l'environnement dans lequel s'exécute une application Android, qui fournit un accès à des ressources et des services tels que des fichiers, des bases de données, des widgets d'interface utilisateur, etc.
Dans ce cas, le contexte est utilisé pour créer une boîte de dialogue de progression qui s'affichera pendant la connexion à la base de données pour informer l'utilisateur de l'avancement de l'opération. En assignant this.context = ctx
, le constructeur Login
stocke le contexte de l'activité principale dans la variable context
de l'objet Login
, qui peut ensuite être utilisée pour créer la boîte de dialogue de progression.
La méthode onPreExecute()
La méthode onPreExecute()
est une méthode protégée (méthode membre) de la classe AsyncTask qui est appelée avant le début du traitement asynchrone. Cette méthode est exécutée sur le thread principal (UI thread) et est souvent utilisée pour initialiser l'interface utilisateur avant de commencer la tâche asynchrone.
Dans l'exemple de code que nous avons vu précédemment, la méthode onPreExecute()
est utilisée pour afficher un dialogue de progression pour informer l'utilisateur que la connexion est en cours. En d'autres termes, cette méthode est utilisée pour effectuer toutes les opérations qui doivent être effectuées avant l'exécution de la tâche asynchrone, comme l'affichage d'une barre de progression, l'affichage d'un message à l'utilisateur, etc.
La méthode doInBackground()
La méthode doInBackground
est une méthode importante de la classe AsyncTask
qui permet d'exécuter des opérations longues en arrière-plan. Elle est exécutée dans un thread différent du thread principal, pour éviter de bloquer l'interface utilisateur.
Dans le contexte de l'application, la méthode doInBackground
est utilisée pour exécuter la requête HTTP de connexion à la base de données distante. Cette méthode utilise la classe HttpURLConnection
pour se connecter au serveur, envoyer les données d'identification (nom d'utilisateur et mot de passe) et recevoir la réponse du serveur.
La méthode renvoie un entier qui représente le statut de la requête : HTTP_OK
(200) si la requête est réussie, HTTP_BAD_REQUEST
(400) si les informations d'identification sont incorrectes, ou une autre valeur si la connexion au serveur échoue. Cette valeur est retournée à la méthode onPostExecute
, qui effectue des actions en fonction du statut de la requête.
Vous pouvez retrouver tous les noms de variables, les codes d'état HTTP ainsi qu'une description détaillée de la classe HttpURLConnection dans la documentation officielle de Java disponible à l'adresse suivante : docs.oracle.com.
BufferedWriter : flux de sortie
bufferedWriter
est un objet de la classe BufferedWriter
qui permet d'écrire des données caractère par caractère dans un flux de sortie. Dans ce contexte, bufferedWriter
est utilisé pour écrire les données de requête HTTP dans la connexion de sortie (httpURLConnection.getOutputStream()
).
Plus précisément, après avoir ouvert la connexion HTTP, l'objet BufferedWriter
est utilisé pour écrire les données de la requête POST en utilisant la méthode write
avec la chaîne de caractères encodée au format UTF-8. Ensuite, la méthode flush
est appelée pour forcer l'écriture des données dans le flux de sortie avant de fermer le bufferedWriter
avec la méthode close
.
La classe JSONObject
jsonObject
est une instance de la classe JSONObject
de la bibliothèque org.json
. Cette classe est utilisée pour manipuler des objets JSON, c'est-à-dire des données structurées dans un format de texte clair qui peut être facilement lu et compris par les humains et les ordinateurs. Dans ce contexte, la réponse du serveur est lue comme une chaîne de caractères et est convertie en un objet JSON à l'aide de la méthode new JSONObject(response.toString())
.
Une fois converti en objet JSON, on peut accéder à ses éléments à l'aide des méthodes fournies par la classe JSONObject
. Par exemple, jsonObject.getInt("status")
permet d'extraire la valeur associée à la clé "status"
dans l'objet JSON. Dans ce cas précis, la valeur est utilisée pour déterminer si l'opération de login a réussi ou échoué.
Pour récupérer la valeur associée à la clé "message" dans cet objet JSON, vous pouvez utiliser la méthode getString()
de l'objet JSONObject
en passant la clé "message" comme paramètre :
String message = jsonObject.getString("message");
Cette méthode renverra la valeur associée à la clé "message" en tant que chaîne de caractères.