Comment construire un backend pour une application Android ?

Back4app Android App Cover

Dans cet article, nous parlerons d’Android, l’un des systèmes d’exploitation les plus populaires. Nous examinerons les avantages et les inconvénients du développement Android, les options de backend pour les applications mobiles et nous vous apprendrons à créer votre propre backend mobile.

Principaux enseignements

  • La domination d’Android: Android, en tant que système d’exploitation à code source ouvert, équipe environ 70 % des appareils mobiles et compte plus de trois milliards d’utilisateurs actifs.
  • Options de backend pour les applications: Pour les applications mobiles, les développeurs peuvent opter pour l’infrastructure en tant que service (IaaS), la plateforme en tant que service (PaaS) ou le backend en tant que service (BaaS).
  • Etapes pour construire votre backend: Nous fournirons un tutoriel détaillé sur la façon de créer un backend Android en utilisant une plateforme BaaS et le code source à la fin de l’article.

Qu’est-ce qu’Android ?

Android est un système d’exploitation libre et gratuit basé sur Linux. Il a été principalement conçu pour les appareils mobiles tels que les smartphones et les tablettes, mais il est désormais également utilisé pour les téléviseurs intelligents, les systèmes embarqués, les consoles de jeu, etc.

Le développement d’Android a commencé en 2003 par Android Inc. L’entreprise souhaitait initialement créer un système d’exploitation pour les appareils photo numériques, mais elle s’est rapidement orientée vers le développement d’un système d’exploitation mobile afin d’atteindre un marché plus large.

En 2005, la société a été rachetée par Google avec ses employés. La première version d’Android est sortie en 2008.

Bien qu’Android soit un logiciel libre, la plupart des appareils mobiles utilisent la version propriétaire de Google. Cette version est préinstallée avec des logiciels tels que Google Chrome, YouTube, Google TV et Gmail.

En raison des grandes options de personnalisation d’Android, de nombreux fabricants transforment également Android pour mieux représenter leur entreprise. C’est pourquoi OnePlus Android est très différent de Pixel Android.

Android est le système d’exploitation le plus populaire depuis 2013. Il est utilisé par environ 70 % des appareils mobiles et compte plus de trois milliards d’utilisateurs actifs mensuels.

En outre, le Google Play Store vous donne accès à plus de trois millions d’applications mobiles. Poursuivez votre lecture pour apprendre à créer un backend pour une application Android.

Avantages du développement Android

Examinons quelques-uns des avantages du développement pour Android.

Plate-forme croisée

En développant pour Android, vous pouvez cibler une large gamme d’appareils. Cela inclut les téléphones portables, les wearables, les smart TV, les consoles de jeu, etc. Si vous savez coder une application mobile, vous n’aurez aucun mal à développer une application pour wearable ou smart TV.

Un marché énorme

Comme indiqué précédemment, Android détient une part de marché plus importante (70 %) que celle d’iOS (30 %). En développant des applications Android, vous pourrez automatiquement accéder à un public plus large.

De plus, les applications Android sont connues pour leur faible investissement et leur retour sur investissement élevé. Contrairement à iOS, il n’y a pas non plus de frais de développement annuels.

Personnalisation

Les appareils Android sont hautement personnalisables par rapport à d’autres systèmes d’exploitation. Ils vous permettent de modifier pratiquement tout ce que vous pouvez imaginer.

En outre, Android vous permet d’intégrer facilement votre application à d’autres services tiers.

Communauté

Android est soutenu par une vaste communauté de développeurs de logiciels libres. De plus, il est livré avec de nombreux outils conviviaux pour les développeurs, tels qu’Android Studio, ADB et Logcat, qui vous permettent de coder facilement des applications.

Si vous êtes bloqué, il existe plusieurs plateformes où vous pouvez trouver de l’aide, notamment GitHub, StackOverflow, Reddit et d’autres communautés centrées sur Android.

Limites du développement Android

Voici quelques-uns des inconvénients du développement Android.

Sécurité

Android est moins sûr qu’iOS et ne suit pas de protocoles de sécurité stricts. Android étant un logiciel libre, des failles de sécurité sont détectées chaque semaine. Les pirates ont donc la possibilité d’exploiter ces failles avant qu’elles ne soient corrigées.

Les appareils Android peuvent également être rootés pour obtenir un accès de superutilisateur. Bien que cela rende votre appareil plus puissant, c’est également risqué car cela désactive certaines mesures de sécurité intégrées.

Complexité

Les appareils Android sont de formes et de tailles différentes, ce qui est certes une bonne chose, mais peut constituer un inconvénient majeur lorsqu’il s’agit de développer des applications Android pour plusieurs types d’appareils.

Pour que votre application soit compatible avec le plus grand nombre d’appareils possible, vous devrez intégrer la conception réactive, tenir compte du matériel des différents appareils, etc.

Applications Premium

Les applications premium ont moins de succès sur le Google Play Store que sur l’App Store. Ce n’est un secret pour personne que les utilisateurs d’Android ont tendance à dépenser moins pour les applications que les utilisateurs d’iOS. Si vous travaillez sur une application “premium”, considérez Android comme votre deuxième choix.

Options de backend pour les applications Android

Quel est le meilleur backend pour une application Android ? Les backends pour les applications mobiles peuvent être hébergés sur votre propre infrastructure ou déployés sur des services en nuage. Les modèles d’informatique dématérialisée les plus populaires pour les backends mobiles sont les suivants :

  1. Infrastructure en tant que service (IaaS)
  2. Plate-forme en tant que service (PaaS)
  3. Backend en tant que service (BaaS)

Chaque option couvre différentes couches d’abstraction, comme le montre l’image ci-dessous.

Couches d'abstraction IaaS vs PaaS vs BaaS

Examinons chaque option en détail pour vous aider à choisir le modèle de cloud le plus adapté à vos applications dorsales.

Infrastructure en tant que service (IaaS)

L’infrastructure en tant que service (IaaS) est le modèle d’informatique en nuage le moins abstrait. Dans ce modèle, le fournisseur offre aux utilisateurs des ressources virtualisées, telles que des serveurs, des réseaux, des systèmes de stockage et d’exploitation, par le biais d’API de haut niveau ou de tableaux de bord intuitifs.

L’avantage de l’IaaS est qu’il donne aux utilisateurs un contrôle total sur l’ensemble de leur infrastructure. L’IaaS est le modèle le plus souple et le plus évolutif, mais aussi le plus difficile à gérer. Si vous choisissez cette option, vous aurez probablement besoin d’un ou deux administrateurs système.

Quelques exemples d’IaaS sont Amazon Web Services, Google Cloud Platform et Azure.

Plate-forme en tant que service (PaaS)

La plateforme en tant que service (PaaS) est un modèle d’informatique en nuage conçu pour aider les utilisateurs à développer, gérer et déployer des applications.

Outre la fourniture d’une infrastructure, le PaaS s’accompagne d’outils conviviaux permettant de développer, de personnaliser et de tester des applications.

En utilisant le PaaS, vous pourrez vous concentrer sur votre logiciel et l’expérience utilisateur sans vous soucier de l’infrastructure sous-jacente.

En outre, le PaaS veille à ce que votre application évolue à la demande, s’occupe des sauvegardes, etc. Les inconvénients du PaaS sont un niveau de contrôle plus faible, un risque de verrouillage du fournisseur et des coûts comparativement plus élevés.

Les plateformes PaaS les plus populaires sont Heroku, Render et Digital Ocean App Platform.

Backend en tant que service (BaaS)

Le Backend as a Service (BaaS) automatise la partie backend du développement en fournissant une solution backend complète.

Les fonctionnalités BaaS comprennent la gestion des utilisateurs, les bases de données, l’authentification, les intégrations sociales, les notifications push, les API, les SDK, etc.

Le BaaS offre tous les avantages de l’IaaS et du PaaS tout en proposant des fonctionnalités supplémentaires. Les équipes qui utilisent le BaaS ont tendance à sortir leurs produits plus rapidement, à réduire les coûts d’ingénierie et à créer de meilleurs logiciels.

Les inconvénients du BaaS sont un niveau de contrôle et de personnalisation plus faible et la possibilité d’un verrouillage du fournisseur pour les plateformes non open-source.

Parmi les exemples de BaaS, on peut citer Back4app, AWS Amplify et Firebase.

Comment créer un backend pour une application Android ?

Dans cette section de l’article, nous allons voir comment construire une application backend basée sur Back4app et s’y connecter à partir d’une application Android.

Conditions préalables

Qu’est-ce que Back4app ?

Back4app est une excellente plateforme pour construire des backends pour des applications modernes et accélérer le processus de développement.

Il est bien équipé avec des fonctionnalités utiles côté serveur telles que la gestion des utilisateurs, les bases de données en temps réel, les intégrations sociales, les fonctions Cloud Code, les notifications push, les API, et bien plus encore !

En utilisant Back4app, vous serez en mesure de délocaliser une grande partie du travail de backend et de vous concentrer sur les aspects critiques de votre application et d’accélérer le développement du backend d’une application Android.

Vous n’aurez pas besoin de vous occuper de l’infrastructure sous-jacente de votre backend, du serveur backend, de la mise à l’échelle, de la maintenance, etc.

Plus important encore, Back4app offre un niveau gratuit qui est idéal pour expérimenter et tester la plateforme. Au fur et à mesure que votre application grandit, vous pouvez passer à un plan premium moyennant un abonnement mensuel.

Introduction du projet

Dans cet article, nous allons créer une simple application de notes. L’application permettra aux utilisateurs d’ajouter, d’éditer et de supprimer des notes. Les notes seront stockées dans la base de données de Back4app et manipulées via Parse SDK.

Nous utiliserons le langage de programmation Kotlin pour construire l’application. Pour l’interface utilisateur, nous utiliserons Jetpack Compose – la boîte à outils moderne d’Android pour construire des interfaces natives.

Back4app Android Notes App

Créer l’application Back4app

La première étape pour développer un backend pour une application Android est de créer un compte Back4app. Si vous n’en avez pas, inscrivez-vous.

Lorsque vous vous connectez à votre compte Back4app, vous êtes redirigé vers la vue des applications. Cliquez sur “Créer une nouvelle application” pour initialiser le processus de création d’application.

Back4app Construire une nouvelle application

La plateforme Back4app propose deux solutions :

  1. Backend as a Service (BaaS) – solution backend robuste
  2. Conteneurs en tant que service (CaaS) – plate-forme de gestion des conteneurs (en particulier des applications web)

Étant donné que nous construisons un backend pour une application mobile, nous opterons pour le “Backend as a Service”.

Solution BaaS de Back4app

Donnez à votre application un nom agréable et informatif, sélectionnez “NoSQL” comme base de données et cliquez sur “Créer”. C’est une étape importante pour déployer un backend pour une application Android.

Back4app prendra un peu de temps pour préparer tout ce qui est nécessaire à votre application. Cela inclut la base de données, la gestion des utilisateurs, la mise à l’échelle, les configurations, etc. Une fois que votre application est prête, vous serez redirigé vers la vue de la base de données de votre application.

Vue de la base de données de Back4app

Conception de la base de données

Passons maintenant à la conception de la base de données. C’est une étape nécessaire pour développer un backend pour une application Android.

Puisque nous construisons une simple application de notes, nous n’aurons besoin que d’une seule classe. Cliquez sur “Créer une classe”, nommez-la Note, activez “Lecture et écriture publiques”, et cliquez sur “Créer une classe et ajouter des colonnes”.

Back4app Créer une classe de base de données

Ensuite, ajoutez les trois champs suivants à la classe nouvellement créée :

+-------------+-------------+--------------------+----------+
| Data type   | Name        | Default value      | Required |
+-------------+-------------+--------------------+----------+
| String      | icon        | <leave blank>      | yes      |
+-------------+-------------+--------------------+----------+
| String      | title       | <leave blank>      | yes      |
+-------------+-------------+--------------------+----------+
| String      | content     | <leave blank>      | yes      |
+-------------+-------------+--------------------+----------+

Enfin, cliquez sur le bouton “Ajouter une ligne” et alimentez votre base de données avec quelques données d’exemple. Si vous n’avez pas d’idées, vous pouvez également importer ce dumping de données.

Back4app alimente la base de données

Voilà, c’est tout pour le backend.

Code Frontend

Dans cette section de l’article, nous allons démarrer une nouvelle application Android, configurer un ViewModel, implémenter l’interface utilisateur, installer et configurer Parse SDK, et enfin récupérer les données de la base de données en temps réel Back4app.

Projet Init

Comme indiqué dans la section des conditions préalables, les étapes suivantes nécessitent l’installation d’Android Studio. Si vous ne l’avez pas encore, téléchargez-le.

Commencez par ouvrir Android Studio et cliquez sur le bouton “Nouveau projet”.

Index d'Android Studio

Sélectionnez ensuite “Activité vide” comme modèle de projet et cliquez sur “Suivant”.

Pour créer votre projet, vous devez fournir un nom et un nom de paquetage. Je vous suggère d’utiliser AndroidApp comme nom de votre projet et le nom de domaine inversé comme paquetage de votre projet.

Une fois que vous avez tout configuré, cliquez sur “Terminer” pour créer le projet.

Paramètres du projet Android Studio

Android Studio prendra environ deux minutes pour préparer tout ce qui est nécessaire. Cela inclut la création de la structure du fichier du projet, la configuration de Gradle, l’installation des dépendances, etc.

Une fois que votre projet est prêt, utilisez l’explorateur pour naviguer jusqu’à MainActivity.kt et remplacez son contenu :

// app/src/main/java.<your_package_name>/MainActivity.kt

package <your.package.name>

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background,
                ) {
                    Text(text = "Back4app rocks!", fontSize = 18.sp)
                }
            }
        }
    }
}

Veillez à toujours remplacer par le nom de votre paquet.

Enfin, essayez de lancer l’application en cliquant sur le bouton vert de lecture ou sur les touches Shift + F10 de votre clavier. Si tout se passe bien, l’émulateur devrait démarrer et vous devriez voir le message Back4app rocks à l’écran.

Première application Android

Modèle de vue

Pour gérer l’état global de notre application, nous utiliserons un ViewModel. Mais avant cela, nous devons créer une classe de données Note avec les mêmes attributs que celle de notre base de données Back4app.

Créez une classe de données nommée Note :

// app/src/main/java.<your_package_name>/Note.kt

package <your.package.name>

data class Note(
    var objectId: String? = null,
    var icon: String,
    var title: String,
    var content: String,
) {
    companion object {
        fun generateObjectId(): String {
            val chars = ('a'..'z') + ('A'..'Z') + ('0'..'9')
            return (1..10).map { chars.random() }.joinToString("")
        }
    }
}
  1. Nous avons défini la méthode statique generateObjectId() pour générer des identifiants d’objets de type Parse.
  2. objectId est nullable puisque nous supposerons plus tard que si objectId == null, l’objet n’a pas encore été sauvegardé dans la base de données.

Ensuite, créez une classe AppViewModel avec le contenu suivant :

// app/src/main/java.<your_package_name>/AppViewModel.kt

package <your.package.name>

import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel

class AppViewModel : ViewModel() {
    val notes: MutableState<Map<String, Note>> = mutableStateOf(mapOf(
        "7IggsqFAKt" to Note(
            objectId = "7IggsqFAKt",
            icon = "\uD83D\uDE80",
            title = "Deploy app",
            content = "Go ahead and deploy your backend to Back4app.",
        ),
        "eFRNm0hTat" to Note(
            objectId = "eFRNm0hTat",
            icon = "\uD83C\uDFA8",
            title = "Design website",
            content = "Design the website for the conference.",
        ),
        "uC7hTQmG5F" to Note(
            objectId = "uC7hTQmG5F",
            icon = "\uD83D\uDC42",
            title = "Attend meeting",
            content = "Attend meeting with the team to discuss the conference.",
        ),
    ))

    companion object {
        @Volatile
        private var instance: AppViewModel? = null

        fun getInstance(): AppViewModel {
            return instance ?: synchronized(this) {
                instance ?: AppViewModel().also { instance = it }
            }
        }
    }
}
  1. Nous avons utilisé l’état mutable de Compose pour déclencher des mises à jour de l’interface utilisateur en cas de modification des données.
  2. Le MutableState contient une carte d' identifiants d'objetset de notes, que nous avons remplie avec des données.
  3. Pour s’assurer qu’il n’y a qu’une seule instance d’AppViewModel, nous avons utilisé le modèle singleton.

Nous pouvons maintenant accéder à l’instance AppViewModel dans nos activités via AppViewModel.getInstance().

Activité principale

Remplacez le contenu de MainActivity.kt par le code suivant pour afficher les notes :

// app/src/main/java.<your_package_name>/MainActivity.kt

package <your.package.name>

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
    private val viewModel = AppViewModel.getInstance()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val context = this as Context

        setContent {
            MainActivityContent(
                viewModel = viewModel,
                onNoteListItemClick = {
                    // TODO: Open note edit form
                },
                onNoteAddClick = {
                    // TODO: Open note create form
                },
            )
        }
    }
}

@Composable
fun MainActivityContent(
    viewModel: AppViewModel,
    onNoteListItemClick: (note: Note) -> Unit,
    onNoteAddClick: () -> Unit,
) {
    val notes = viewModel.notes.value
    MaterialTheme {
        Scaffold(
            topBar = { TopAppBar(title = { Text("My Notes") }) },
            floatingActionButton = {
                ExtendedFloatingActionButton(
                    onClick = { onNoteAddClick() },
                    icon = { Icon(Icons.Filled.Add, contentDescription = "Add") },
                    text = { Text("Add") }
                )
            },
        ) { contentPadding ->
            Box(modifier = Modifier.padding(contentPadding)) {
                NoteList(notes, onNoteListItemClick = { onNoteListItemClick(it) })
            }
        }
    }
}

@Composable
fun NoteListItem(note: Note, onNoteListItemClick: (note: Note) -> Unit) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = { onNoteListItemClick(note) })
            .padding(16.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Text(text = note.icon, fontSize = 32.sp, modifier = Modifier.size(48.dp))
        Spacer(modifier = Modifier.width(8.dp))
        Column {
            Text(text = note.title, fontSize = 18.sp)
            Spacer(modifier = Modifier.height(4.dp))
            Text(
                text = note.content,
                fontSize = 14.sp,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis,
            )
        }
    }
}

@Composable
fun NoteList(notes: Map<String, Note>, onNoteListItemClick: (note: Note) -> Unit) {
    LazyColumn {
        items(notes.entries.toList()) { (_, note) ->
            NoteListItem(note = note, onNoteListItemClick = onNoteListItemClick)
        }
    }
}
  1. Les notes sont maintenant extraites du modèle AppViewModel.
  2. Au lieu de définir les événements de clic dans les composables, nous les avons transmis en tant qu’arguments.
  3. Nous avons utilisé Compose pour concevoir l’interface utilisateur. Pour la rendre plus fluide, nous avons incorporé MaterialTheme à la mise en page de Scaffold.

Si vous reconstruisez l’application maintenant, vous devriez voir la liste des notes “codées en dur” à l’écran.

Back4app Notes App List

Formulaire de note Activité

Dans cette section, nous allons ajouter une nouvelle activité qui permettra aux utilisateurs d’ajouter et de modifier des notes.

Commencez par créer une nouvelle classe nommée FormActivity avec le contenu suivant :

// app/src/main/java.<your_package_name>/FormActivity.kt

package <your.package.name>

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.Button
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp

class FormActivity : ComponentActivity() {
    private val viewModel = AppViewModel.getInstance()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val objectId = intent.getStringExtra("objectId")
        val note = if (objectId !== null) viewModel.notes.value[objectId] else null

        setContent {
            FormActivityContent(
                note,
                onNoteAddClick = { icon: String, title: String, content: String ->
                    if (note !== null) return@FormActivityContent
                    val newNote = Note(
                        icon = icon,
                        title = title,
                        content = content,
                    )
                    newNote.objectId = Note.generateObjectId()
                    viewModel.notes.value += (newNote.objectId!! to newNote)
                    finish()
                },
                onNoteSaveClick = { icon: String, title: String, content: String ->
                    if (note === null) return@FormActivityContent
                    val updatedNote = note.copy()
                    updatedNote.icon = icon
                    updatedNote.title = title
                    updatedNote.content = content
                    viewModel.notes.value += (updatedNote.objectId!! to updatedNote)
                    finish()
                },
                onNoteDeleteClick = {
                    if (note === null) return@FormActivityContent
                    viewModel.notes.value = viewModel.notes.value.filter {
                        it.value.objectId != note.objectId
                    }
                    finish()
                },
            )
        }
    }
}

@Composable
fun FormActivityContent(
    note: Note?,
    onNoteAddClick: (icon: String, title: String, content: String) -> Unit,
    onNoteSaveClick: (icon: String, title: String, content: String) -> Unit,
    onNoteDeleteClick: () -> Unit,
) {
    MaterialTheme {
        Scaffold(
            topBar = {
                TopAppBar(title = { Text(note?.let { "Edit Note" } ?: ("Add Note")) })
            },
            floatingActionButton = {
                if (note !== null) {
                    ExtendedFloatingActionButton(
                        onClick = { onNoteDeleteClick() },
                        icon = { Icon(Icons.Filled.Delete, "Delete") },
                        text = { Text("Delete") },
                    )
                }
            },
        ) { contentPadding ->
            Box(modifier = Modifier.padding(contentPadding)) {
                NoteForm(note = note, onNoteSave = { icon, title, content ->
                    if (note === null) {
                        onNoteAddClick(icon, title, content)
                    } else {
                        onNoteSaveClick(icon, title, content)
                    }
                })
            }
        }
    }
}

@Composable
fun NoteForm(
    note: Note?,
    onNoteSave: (icon: String, title: String, content: String) -> Unit
) {
    var icon by remember { mutableStateOf(TextFieldValue(note?.icon ?: "")) }
    var title by remember { mutableStateOf(TextFieldValue(note?.title ?: "")) }
    var content by remember { mutableStateOf(TextFieldValue(note?.content ?: "")) }
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        TextField(
            label = { Text(text = "Icon") },
            value = icon,
            onValueChange = { icon = it },
            modifier = Modifier.fillMaxWidth()
        )
        Spacer(modifier = Modifier.height(16.dp))
        TextField(
            label = { Text(text = "Title") },
            value = title,
            onValueChange = { title = it },
            modifier = Modifier.fillMaxWidth()
        )
        Spacer(modifier = Modifier.height(16.dp))
        TextField(
            label = { Text(text = "Content") },
            value = content,
            onValueChange = { content = it },
            modifier = Modifier.fillMaxWidth()
        )
        Spacer(modifier = Modifier.height(16.dp))
        Button(
            onClick = { onNoteSave(icon.text, title.text, content.text) },
            Modifier.fillMaxWidth()
        ) {
            Text(text = "Save")
        }
    }
}
  1. Ce formulaire est utilisé pour ajouter et modifier des notes. Pour déterminer l’action, nous comparons objectId == null. Dans le cas de null, il s’agit d’une action d’ajout, sinon d’une action d’édition.
  2. Si objectId !== null, nous récupérons la note dans l’état et remplissons le formulaire.
  3. Pour que MutableState fonctionne correctement, nous devions considérer son contenu comme immuable. C’est pourquoi nous avons parfois copié le contenu au lieu de le modifier.
  4. Nous avons géré l’état du formulaire Compose via mutableStateOf().

Ensuite, enregistrez la FormActivity au bas de l’application dans AndroidManifest.xml :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application>
        <!-- ... -->
        <activity android:name=".FormActivity"/>
    </application>

</manifest>

Enfin, créez un nouvel Intent sur onNoteListItemClick et onNoteAddClick dans MainActivity.kt:

// app/src/main/java.<your_package_name>/MainActivity.kt

class MainActivity : ComponentActivity() {
    // ...

    override fun onCreate(savedInstanceState: Bundle?) {
        // ...

        setContent {
            MainActivityContent(
                viewModel = viewModel,
                onNoteListItemClick = {
                    // triggers the edit action, since `objectId` is provided
                    val intent = Intent(context, FormActivity::class.java)
                    intent.putExtra("objectId", it.objectId)
                    context.startActivity(intent)
                },
                onNoteAddClick = {
                    // triggers the add action, since no `objectId` is present
                    val intent = Intent(context, FormActivity::class.java)
                    context.startActivity(intent)
                },
            )
        }
    }
}

N’oubliez pas d’importer l’intention en haut du fichier :

import android.content.Intent

Si vous reconstruisez l’application, vous remarquerez que nous avons maintenant une application fonctionnelle. L’application nous permet d’ajouter des notes, de les modifier et de les supprimer.

Le seul problème est que le redémarrage de l’application réinitialise son état (aux notes “codées en dur”).

Dans la section suivante, nous allons connecter l’application au backend Back4app. Cela nous permettra de conserver l’état et de le synchroniser entre plusieurs appareils.

Aperçu de l'édition de l'application Android Notes

Installer le SDK Parse

Comme vous le savez peut-être, Back4app est basé sur la plateforme Parse. Si nous voulons interagir avec la base de données de Back4app ou Back4app en général, nous devons installer le SDK Parse.

Commencez par ajouter le dépôt JitPack à settings.gradle :

// settings.gradle

pluginManagement {
    repositories {
        // ...
        maven { url "https://jitpack.io" }
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        // ...
        maven { url "https://jitpack.io" }
    }
}

Ensuite, ajoutez le SDK Android Parse au build.gradle de l’application :

// app/build.gradle

dependencies {
    // ...
    implementation "com.github.parse-community.Parse-SDK-Android:parse:4.2.0"
}

Synchroniser les paramètres Gradle et s’assurer qu’il n’y a pas d’erreurs.

Configurer Parse SDK

Pour vous connecter au backend de Back4app, vous devrez fournir à Parse SDK votre identifiant d’application et votre clé client. Pour obtenir ces informations, naviguez dans votre application Back4app et sélectionnez “App Settings > Security & Keys” dans la barre latérale.

Ajoutez-les ensuite à votre strings.xml comme suit :

<!-- app/src/main/res/values/strings.xml -->

<resources>
    <string name="app_name">back4app-android-app</string>
    <string name="back4app_server_url">https://parseapi.back4app.com/</string>
    <string name="back4app_app_id">your_parse_app_id</string>
    <string name="back4app_client_key">your_parse_client_key</string>
</resources>

Veillez à remplacer your_parse_app_id et your_parse_client_key par vos identifiants.

Ensuite, modifiez votre AndroidManifest.xml pour activer l’accès à Internet et joindre les métadonnées d’identification :

<!-- app/src/main/AndroidManifest.xml -->

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- these two permissions enable internet access -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />

    <application>
        <!-- ... -->

        <!-- newly added metadata -->
        <meta-data
            android:name="com.parse.SERVER_URL"
            android:value="@string/back4app_server_url" />
        <meta-data
            android:name="com.parse.APPLICATION_ID"
            android:value="@string/back4app_app_id" />
        <meta-data
            android:name="com.parse.CLIENT_KEY"
            android:value="@string/back4app_client_key" />
    </application>

</manifest>

La dernière chose à faire est d’initialiser Parse. Pour s’assurer que Parse est initialisé avant toute activité, nous allons créer une nouvelle classe nommée App, qui hérite de la classe Application.

Créez App.kt et initialisez Parse comme suit :

// app/src/main/java/<your_package_name>/App.kt

package <your.package.name>

import android.app.Application
import com.parse.Parse

class App : Application() {
    override fun onCreate() {
        super.onCreate()

        Parse.initialize(
            Parse.Configuration.Builder(this)
                .applicationId(getString(R.string.back4app_app_id))
                .clientKey(getString(R.string.back4app_client_key))
                .server(getString(R.string.back4app_server_url))
                .build()
        )
    }
}

Enregistrez ensuite la classe App dans AndroidManifest.xml :

<!-- app/src/main/AndroidManifest.xml -->

<application
    android:name=".App"
    ...
>
    <!-- ... -->
</application>

Reconstruisez l’application une fois de plus et vérifiez dans la fenêtre Logcat s’il y a des erreurs. S’il n’y a pas d’erreurs, la connexion à Back4app a réussi.

Charger les notes de Back4app

La dernière chose qu’il nous reste à faire avant de terminer notre application est de charger les notes de la base de données de Back4app et de voir comment utiliser Parse en pratique.

Commencez par naviguer vers le modèle AppViewModel. Supprimez les données de la carte et ajoutez le bloc init:

// app/src/main/java/<your_package_name>/AppViewModel.kt

package <your.package.name>

import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel

class AppViewModel : ViewModel() {
    val notes: MutableState<Map<String, Note>> = mutableStateOf(mapOf())

    init {
        val query = com.parse.ParseQuery.getQuery<com.parse.ParseObject>("Note")
        query.orderByDescending("createdAt")
        query.findInBackground { notes, e ->
            if (e == null) {
                for (parseNote in notes) {
                    val note = Note(
                        objectId = parseNote.objectId,
                        icon = parseNote.getString("icon")!!,
                        title = parseNote.getString("title")!!,
                        content = parseNote.getString("content")!!,
                    )
                    this.notes.value += (note.objectId!! to note)
                }
            } else {
                println("Error: ${e.message}")
            }
        }
    }

    companion object {
        // ...
    }
}

Ce code utilise Parse SDK pour récupérer les notes dans les bases de données, les transformer en classe de données Note et les enregistrer dans la carte.

Ensuite, ajoutez les trois méthodes suivantes à Note :

// app/src/main/java/<your_package_name>/Note.kt

package <your.package.name>

import com.parse.ParseObject
import com.parse.ParseQuery

data class Note(
    var objectId: String? = null,
    var icon: String,
    var title: String,
    var content: String,
) {
    fun addToParse(callback: (objectId: String) -> Unit) {
        if (objectId !== null) throw Exception("Note is already saved to Parse!")

        val parseNote = ParseObject("Note")
        parseNote.put("icon", icon)
        parseNote.put("title", title)
        parseNote.put("content", content)

        parseNote.saveInBackground {
            if (it !== null) throw Exception("Error: ${it.message}")
            objectId = parseNote.objectId
            callback(parseNote.objectId)
        }
    }

    fun updateToParse(callback: (objectId: String) -> Unit) {
        if (objectId === null) throw Exception("Note hasn't been saved to Parse yet!")

        val query = ParseQuery.getQuery<ParseObject>("Note")
        val parseNote = query.get(objectId)
        parseNote.put("icon", icon)
        parseNote.put("title", title)
        parseNote.put("content", content)

        parseNote.saveInBackground {
            if (it !== null) throw Exception("Error: ${it.message}")
            callback(parseNote.objectId)
        }
    }

    fun deleteFromParse(callback: () -> Unit) {
        if (objectId === null) throw Exception("Note hasn't been saved to Parse yet!")

        val query = ParseQuery.getQuery<ParseObject>("Note")
        val parseNote = query.get(objectId)
        parseNote.deleteInBackground {
            if (it !== null) throw Exception("Error: ${it.message}")
            callback()
        }
    }
}
  1. addToParse() ajoute une nouvelle note au serveur Parse avec ses détails. En cas de succès, elle stocke l’identifiant unique de la note et notifie la fin de l’opération.
  2. updateToParse() met à jour les informations d’une note existante sur le serveur Parse. En cas de succès, elle signale qu’elle a terminé après avoir effectué les modifications.
  3. deleteFromParse() supprime une note sauvegardée sur le serveur Parse. En cas de succès, elle confirme la suppression lorsqu’elle est terminée.

Enfin, modifiez les méthodes de clic dans FormActivity pour invoquer les méthodes nouvellement définies :

// app/src/main/java/<your_package_name>/NoteFormActivity.kt

class FormActivity : ComponentActivity() {
    // ...

    override fun onCreate(savedInstanceState: Bundle?) {
        // ...

        setContent {
            FormActivityContent(
                note,
                onNoteAddClick = { icon: String, title: String, content: String ->
                    if (note !== null) return@FormActivityContent
                    val newNote = Note(
                        icon = icon,
                        title = title,
                        content = content,
                    )
                    newNote.addToParse {
                        viewModel.notes.value += (it to newNote)
                        finish()
                    }
                },
                onNoteSaveClick = { icon: String, title: String, content: String ->
                    if (note === null) return@FormActivityContent
                    val updatedNote = note.copy()
                    updatedNote.icon = icon
                    updatedNote.title = title
                    updatedNote.content = content
                    updatedNote.updateToParse {
                        viewModel.notes.value += (it to updatedNote)
                        finish()
                    }
                },
                onNoteDeleteClick = {
                    if (note === null) return@FormActivityContent
                    viewModel.notes.value = viewModel.notes.value.filter {
                        it.value.objectId != note.objectId
                    }
                    note.deleteFromParse {
                        finish()
                    }
                },
            )
        }
    }
}

C’est tout !

L’application est maintenant complètement fonctionnelle et synchronisée avec le backend de Back4app. Essayez de jouer avec l’application en changeant les données et en vérifiant si les changements sont reflétés dans la vue de la base de données.

Conclusion

Dans cet article, nous avons réussi à construire un backend mobile et à nous y connecter depuis notre application Android. Nous avons utilisé la solution BaaS de Back4app pour le backend, et sur le frontend, nous avons utilisé Kotlin avec Jetpack Compose.

Vous devriez maintenant avoir une bonne compréhension du fonctionnement des backends mobiles et être en mesure de construire le vôtre. Voir le code source final sur le repo back4app-android-app.


Leave a reply

Your email address will not be published.