Maintenant que vous savez correctement authentifier vos utilisateurs sur votre application Android en passant par votre Backend Firebase, nous allons passer à l'étape supérieure en récupérant/sauvegardant du contenu distant se trouvant... sur Firebase, bien évidemment !
Hein ? Je ne comprends pas tout là ! Pourquoi mon application Android aurait-elle besoin de sauvegarder du contenu en ligne ?
Eh bien déjà car cette dernière ne peut PAS tout stocker, bien évidemment !
Et puis parce que vous allez sans doute, en fonction de votre projet, vouloir partager entre les utilisateurs plusieurs ressources (images, données, vidéos, etc...) ou tout simplement permettre à un même utilisateur de retrouver ses propres données sur tous ses périphériques (téléphone portable, tablette(s), etc...).
D'où l'intérêt de disposer d'un Backend, et dans notre cas, Firebase.
Stockez les données
Ah d'accord, c'est super en fait d'avoir un Backend ! En plus, je suppose qu'avec Firebase, je n'aurais qu'à faire quelque chose comme saveData()
et pouf... tout est synchronisé ?
Alors non, faut pas pousser quand même !
En fait, nos données seront sauvegardées de manière structurée dans une base de données, comme toutes les données numériques d'ailleurs. Nous verrons un peu plus tard comme réaliser cela sur notre application Android.
Firestore est donc une base de données NoSQL, hébergée sur le cloud de Google (Firebase) et orientée Documents. Ce type de base de données est principalement structuré en trois éléments :
La donnée brute (DATA) : Elle représente, comme son nom l'indique, la donnée brute que vous souhaitez sauvegarder, comme par exemple un entier (Int), une chaîne de caractères (String), une valeur booléenne (Boolean), etc... Tous les types supportés sont dans la documentation.
Le document (DOCUMENT) : Les données brutes (DATA) ne peuvent être sauvegardées au hasard et n'importe où. Elles sont donc obligatoirement rattachées à un Document, sous forme de propriétés/champs. Par exemple, le Document "Philippe" sera composé de plusieurs champs (DATA) : lastname (String), firstname (String), age (int), etc..
La collection (COLLECTION) : Permet d'organiser sous forme de liste les documents. En effet, une Collection va contenir un ou plusieurs Documents. Dans notre cas, une Collection pourrait s'appeler "users" et contenir des Documents comme "Philippe", "Luc", "Ambroise", etc...
Organisez les données
Comme vous l'aurez compris, avant de pouvoir sauvegarder des données sur Firestore, il va falloir les structurer au modèle NoSQL orienté Documents.
Mais pourquoi ? Firebase ne peut pas le faire automatiquement ?
Eh non, et heureusement !
Pour notre mini-application FirebaseOC, nous souhaitons :
indiquer pour chaque utilisateur si ce dernier est un mentor ;
créer trois chats de conversation indépendants traitant de sujets différents (Android, Firebase et Bug) ;
afficher dans ces chats des messages (de nos utilisateurs) avec du texte et des images (avec la date d'envoi de chaque message).
Afin d'organiser cela dans Firestore, nous avons possiblement le choix entre 3 architectures selon la documentation. Bien évidemment, vous êtes libres d'en implémenter plusieurs à la fois.
Dans notre cas, nous allons faire un mix des architectures "Subcollections" et "Root-level Collections" afin d'organiser au maximum nos données.
Ainsi, pour notre projet FirebaseOC et ses besoins, voici la manière dont j'ai choisi d'organiser notre base de données.
Implémentez les données sur Android
Maintenant que nous avons trouvé la manière dont nous allons structurer nos données dans notre base de données Firestore, nous allons créer dans notre projet les modèles (classes JAVA) correspondants. Vous allez voir, c'est relativement simple !
En fait, nous avons besoin de créer uniquement les classes qui contiennent des données (DATA) donc des champs, ici Message et User.
Reprenez donc votre application FirebaseOC. Avant toute chose, nous allons installer le module Firestore de la librairie Firebase-UI. Pour cela, modifiez le fichier build.gradle.
Fichier build.gradle :
dependencies {
...
implementation 'com.google.firebase:firebase-firestore'
}
Une fois la librairie installée, créez un package models/ et à l'intérieur, deux classes correspondantes à nos modèles, User.java et Message.java.
Classe User.java :
public class User {
private String uid;
private String username;
private Boolean isMentor;
@Nullable
private String urlPicture;
public User() { }
public User(String uid, String username, @Nullable String urlPicture) {
this.uid = uid;
this.username = username;
this.urlPicture = urlPicture;
this.isMentor = false;
}
// --- GETTERS ---
public String getUid() { return uid; }
public String getUsername() { return username; }
@Nullable
public String getUrlPicture() { return urlPicture; }
public Boolean getIsMentor() { return isMentor; }
// --- SETTERS ---
public void setUsername(String username) { this.username = username; }
public void setUid(String uid) { this.uid = uid; }
public void setUrlPicture(@Nullable String urlPicture) { this.urlPicture = urlPicture; }
public void setIsMentor(Boolean mentor) { isMentor = mentor; }
}
Explications : Cette classe est très simple puisqu'elle représente notre utilisateur. Je n'explique pas tous les champs, qui se trouvent être plutôt explicites !
Pourquoi doit-on créer une classe pour stocker des informations relatives à nos utilisateurs, sachant que l'on peut déjà les récupérer via le produit "Authentication" de Firebase ?
Bonne question !
Tout simplement car Firebase a fait le choix de sécuriser l'accès en lecture/écriture des informations stockées dans le produit "Authentication" relatives aux utilisateurs. Ainsi, vous ne pourrez pas faire de FirebaseAuth.getInstance().getAllUsers()
ou modifier de manière poussée et personnalisée un utilisateur.
Le but affiché est de vous protéger vous, mais aussi vos utilisateurs. Mais cela n'est pas grave et vous laisse plutôt une totale liberté pour implémenter une gestion personnalisée de vos utilisateurs en base de données. Et en tant que développeur, on adore être flexibles et libres de nos mouvements !
Classe Message.java :
public class Message {
private String message;
private Date dateCreated;
private User userSender;
private String urlImage;
public Message() { }
public Message(String message, User userSender) {
this.message = message;
this.userSender = userSender;
}
public Message(String message, String urlImage, User userSender) {
this.message = message;
this.urlImage = urlImage;
this.userSender = userSender;
}
// --- GETTERS ---
public String getMessage() { return message; }
@ServerTimestamp public Date getDateCreated() { return dateCreated; }
public User getUserSender() { return userSender; }
public String getUrlImage() { return urlImage; }
// --- SETTERS ---
public void setMessage(String message) { this.message = message; }
public void setDateCreated(Date dateCreated) { this.dateCreated = dateCreated; }
public void setUserSender(User userSender) { this.userSender = userSender; }
public void setUrlImage(String urlImage) { this.urlImage = urlImage; }
}
Créez la base de données
Pour créer la base de données, c'est très simple, rendez vous dans votre console et sélectionnez le menu Firestore puis cliquez sur "Créer une base de données" :
Vous allez devoir choisir dans un premier temps les règles de sécurité pour votre base de données. Vous pouvez sélectionner l'une ou l'autre des solutions, nous allons dans tous les cas les modifier par la suite.
Vous allez ensuite devoir sélectionner l'emplacement de votre base de données. A notre échelle, cela n'a pas un très grand impact, mais l'idéal est de choisir le serveur le plus proche de vous (et de vos utilisateurs). J'ai donc choisi celui situé en Europe de l'ouest.
Cliquez ensuite sur "Activer" afin de créer votre base de données.
Sécurisez l'accès à la base de données
Afin de sécuriser l'accès à votre base de données, Firebase vous propose de créer des règles d'accès. Par exemple, dans notre cas nous souhaitons faire en sorte que l'accès en écriture et en lecture de nos principales Collections soit restreint aux seuls utilisateurs authentifiés.
Pour cela, une fois dans le menu Firestore, rendez-vous sur l'onglet "Rules" et renseignez les règles suivantes :
Explications : Nous avons ici créé une règle d'accès simple afin de comprendre la manière dont Firebase sécurise l'accès à notre base de données Firestore.
service
permet d'indiquer le service à sécuriser, ici Firestore.match
permet de créer une règle (ou un ensemble de règles) qui sera déclenchée quand l'utilisateur interrogera la ressource définie juste après.allow
permet de créer une méthode qui autorisera des actions en lecture ou en écriture. Ce qui n'est pas explicitement autorisé sera refusé.
Pour notre projet, nous autorisons seulement les utilisateurs authentifiés à écrire ou lire les Documents de notre Collection chats via la condition if request.auth != null
. Concernant la manipulation de la Collection users, nous autorisons seulement les utilisateurs à lire et modifier leur propre document via la condition if request.auth.uid == userId
.
Bon allez, trêve de théorie, on passe dès le prochain chapitre à la pratique. C'est parti !
En résumé
Les bases de données Firebase sont en NoSQL.
Il existe différents moyens d'organiser ses données en NoSQL (Data imbriquées, Sous-collections, Collections racines...)
Utilisez des modèles afin de représenter vos données au sein de votre application.