Atelier de programmation Firebase iOS Swift

1. Présentation

2efe6805ef369641.png

Bienvenue dans l'atelier de programmation Friendly Chat. Dans cet atelier de programmation, vous allez apprendre à utiliser la plate-forme Firebase pour créer des applications iOS. Vous allez implémenter un client de chat et surveiller ses performances à l'aide de Firebase.

Points abordés

  • Autoriser les utilisateurs à se connecter.
  • Synchroniser des données à l'aide de Firebase Realtime Database
  • Stockez les fichiers binaires dans Firebase Storage.

Prérequis

  • Xcode
  • CocoaPods
  • Un appareil de test équipé d'iOS 8.0 ou version ultérieure, ou un simulateur

Comment allez-vous utiliser ce tutoriel ?

Je vais le lire uniquement Je vais le lire et effectuer les exercices

Comment évalueriez-vous votre niveau en matière de création d'applications iOS ?

Débutant Intermédiaire Expert

2. Obtenir l'exemple de code

Clonez le dépôt GitHub à partir de la ligne de commande.

$ git clone https://github.com/firebase/codelab-friendlychat-ios

3. Compiler l'application de démarrage

2f4c98d858c453fe.png

Pour compiler l'application de démarrage :

  1. Dans une fenêtre de terminal, accédez au répertoire android_studio_folder.pngios-starter/swift-starter à partir de l'exemple de code téléchargé.
  2. Exécuter pod install --repo-update
  3. Ouvrez le fichier FriendlyChatSwift.xcworkspace pour ouvrir le projet dans Xcode.
  4. Cliquez sur le bouton 98205811bbed9d74.pngExécuter.

L'écran d'accueil de Friendly Chat devrait s'afficher après quelques secondes. L'UI devrait s'afficher. Toutefois, vous ne pouvez pas vous connecter, ni envoyer ni recevoir de messages pour le moment. L'application s'arrêtera avec une exception jusqu'à ce que vous effectuiez l'étape suivante.

4. Configurer un projet Firebase

Créer un projet Firebase

  1. Connectez-vous à la console Firebase à l'aide de votre compte Google.
  2. Cliquez sur le bouton pour créer un projet, puis saisissez un nom de projet (par exemple, FriendlyChat).
  3. Cliquez sur Continuer.
  4. Si vous y êtes invité, lisez et acceptez les Conditions d'utilisation de Firebase, puis cliquez sur Continuer.
  5. (Facultatif) Activez l'assistance IA dans la console Firebase (appelée "Gemini dans Firebase").
  6. Pour cet atelier de programmation, vous n'avez pas besoin de Google Analytics. Désactivez donc l'option Google Analytics.
  7. Cliquez sur Créer un projet, attendez que votre projet soit provisionné, puis cliquez sur Continuer.

Mettre à niveau votre forfait Firebase

Pour utiliser Cloud Storage pour Firebase, votre projet Firebase doit être associé à un compte de facturation Cloud et utiliser le forfait Blaze avec paiement à l'usage.

  • Un compte de facturation Cloud nécessite un mode de paiement, comme une carte de crédit.
  • Si vous débutez avec Firebase et Google Cloud, vérifiez si vous êtes éligible à un crédit de 300$et à un compte de facturation Cloud pour l'essai sans frais.
  • Si vous effectuez cet atelier de programmation dans le cadre d'un événement, demandez à l'organisateur si des crédits Cloud sont disponibles.

Pour passer à la formule Blaze, procédez comme suit :

  1. Dans la console Firebase, sélectionnez Passer à une formule supérieure.
  2. Sélectionnez le forfait Blaze. Suivez les instructions à l'écran pour associer un compte de facturation Cloud à votre projet.
    Si vous avez dû créer un compte de facturation Cloud lors de cette mise à niveau, vous devrez peut-être revenir au processus de mise à niveau dans la console Firebase pour la finaliser.

Associer votre application iOS

  1. Dans l'écran "Présentation du projet" de votre nouveau projet, cliquez sur Ajouter Firebase à votre application iOS.
  2. Saisissez l'ID du bundle au format com.google.firebase.codelab.FriendlyChatSwift.
  3. Saisissez l'ID App Store au format 123456.
  4. Cliquez sur Register App (Enregistrer l'application).

Ajouter le fichier GoogleService-Info.plist à votre application

Sur le deuxième écran, cliquez sur Download GoogleService-Info.plist (Télécharger GoogleService-Info.plist) pour télécharger un fichier de configuration contenant toutes les métadonnées Firebase nécessaires pour votre application. Copiez ce fichier dans votre application et ajoutez-le à la cible FriendlyChatSwift.

Vous pouvez maintenant cliquer sur le "x" en haut à droite de la fenêtre pop-up pour la fermer, en ignorant les étapes 3 et 4, car vous allez les effectuer ici.

19d59efb213ddbdc.png

Importer le module Firebase

Commencez par vous assurer que le module Firebase est importé.

AppDelegate.swift, FCViewController.swift

import Firebase

Configurer Firebase dans AppDelegate

Utilisez la méthode "configure" dans FirebaseApp à l'intérieur de la fonction application:didFinishLaunchingWithOptions pour configurer les services Firebase sous-jacents à partir de votre fichier .plist.

AppDelegate.swift

  func application(_ application: UIApplication, didFinishLaunchingWithOptions
      launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  FirebaseApp.configure()
  GIDSignIn.sharedInstance().delegate = self
  return true
}

5. Identifier les utilisateurs

Utiliser des règles pour limiter l'accès aux utilisateurs authentifiés

Nous allons maintenant ajouter une règle pour exiger l'authentification avant de lire ou d'écrire des messages. Pour ce faire, nous ajoutons les règles suivantes à l'objet de données des messages. Dans la section "Base de données" de la console Firebase, sélectionnez "Realtime Database", puis cliquez sur l'onglet "Règles". Mettez ensuite à jour les règles pour qu'elles se présentent comme suit :

{
  "rules": {
    "messages": {
      ".read": "auth != null",
      ".write": "auth != null"
    }
  }
}

Pour en savoir plus sur le fonctionnement de cette fonctionnalité (y compris la documentation sur la variable "auth"), consultez la documentation sur la sécurité de Firebase.

Configurer les API d'authentification

Pour que votre application puisse accéder aux API Firebase Authentication au nom de vos utilisateurs, vous devez l'activer.

  1. Accédez à la console Firebase et sélectionnez votre projet.
  2. Sélectionnez Authentification.
  3. Sélectionnez l'onglet Méthode de connexion.
  4. Activez le bouton Google (bleu).
  5. Cliquez sur Enregistrer dans la boîte de dialogue qui s'affiche.

Si vous rencontrez des erreurs plus tard dans cet atelier de programmation et que le message "CONFIGURATION_NOT_FOUND" s'affiche, revenez à cette étape et vérifiez votre travail.

Confirmer la dépendance Firebase Auth

Vérifiez que les dépendances Firebase Authentication existent dans le fichier Podfile.

Podfile

pod 'Firebase/Auth'

Configurez votre fichier Info.plist pour Google Sign-In.

Vous devrez ajouter un schéma d'URL personnalisé à votre projet Xcode.

  1. Ouvrez la configuration de votre projet : double-cliquez sur le nom du projet dans l'arborescence de gauche. Sélectionnez votre application dans la section "CIBLES", puis l'onglet "Infos" et développez la section "Types d'URL".
  2. Cliquez sur le bouton + et ajoutez un schéma d'URL pour votre ID client inversé. Pour trouver cette valeur, ouvrez le fichier de configuration GoogleService-Info.plist et recherchez la clé REVERSED_CLIENT_ID. Copiez la valeur de cette clé et collez-la dans la zone "Schémas d'URL" de la page de configuration. Laissez les autres champs vides.
  3. Une fois terminée, votre configuration doit ressembler à ce qui suit (mais avec vos valeurs spécifiques à l'application) :

1b54d5bd2f4f1448.png

Définir le clientID pour Se connecter avec Google

Une fois Firebase configuré, nous pouvons utiliser le clientID pour configurer la connexion Google dans la méthode "didFinishLaunchingWithOptions:".

AppDelegate.swift

  func application(_ application: UIApplication, didFinishLaunchingWithOptions
      launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  FirebaseApp.configure()
  GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
  GIDSignIn.sharedInstance().delegate = self
  return true
}

Ajouter le gestionnaire de connexion

Une fois la connexion avec Google réussie, utilisez le compte pour vous authentifier auprès de Firebase.

AppDelegate.swift

  func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
    if let error = error {
      print("Error \(error)")
      return
    }

    guard let authentication = user.authentication else { return }
    let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
                                                      accessToken: authentication.accessToken)
    Auth.auth().signIn(with: credential) { (user, error) in
      if let error = error {
        print("Error \(error)")
        return
      }
    }
  }

Connectez automatiquement l'utilisateur. Ajoutez ensuite un écouteur à Firebase Auth pour permettre à l'utilisateur d'accéder à l'application une fois la connexion établie. Supprimez l'écouteur lors de la désinitialisation.

SignInViewController.swift

  override func viewDidLoad() {
    super.viewDidLoad()
    GIDSignIn.sharedInstance().uiDelegate = self
    GIDSignIn.sharedInstance().signInSilently()
    handle = Auth.auth().addStateDidChangeListener() { (auth, user) in
      if user != nil {
        MeasurementHelper.sendLoginEvent()
        self.performSegue(withIdentifier: Constants.Segues.SignInToFp, sender: nil)
      }
    }
  }

  deinit {
    if let handle = handle {
      Auth.auth().removeStateDidChangeListener(handle)
    }
  }

Se déconnecter

Ajouter la méthode de déconnexion

FCViewController.swift

  @IBAction func signOut(_ sender: UIButton) {
    let firebaseAuth = Auth.auth()
    do {
      try firebaseAuth.signOut()
      dismiss(animated: true, completion: nil)
    } catch let signOutError as NSError {
      print ("Error signing out: \(signOutError.localizedDescription)")
    }
  }

Tester la lecture des messages en tant qu'utilisateur connecté

  1. Cliquez sur le bouton 98205811bbed9d74.pngExécuter.
  2. Vous devriez être immédiatement redirigé vers l'écran de connexion. Appuyez sur le bouton de connexion Google.
  3. Si tout s'est bien passé, vous devriez être redirigé vers l'écran de messagerie.

6. Activer Realtime Database

2efe6805ef369641.png

Importer des messages

Dans votre projet de la console Firebase, sélectionnez l'élément Base de données dans la barre de navigation de gauche. Dans le menu à développer de la base de données, sélectionnez Importer le fichier JSON. Accédez au fichier initial_messages.json dans le répertoire friendlychat, sélectionnez-le, puis cliquez sur le bouton Importer. Toutes les données actuellement présentes dans votre base de données seront remplacées. Vous pouvez également modifier directement la base de données en utilisant le signe + vert et la croix rouge pour ajouter et supprimer des éléments.

20ccf4856b715b4c.png

Une fois votre base de données importée, elle devrait se présenter comme suit :

f3e0367f1c9cd187.png

Confirmer la dépendance de la base de données Firebase

Dans le bloc de dépendances du fichier Podfile, vérifiez que Firebase/Database est inclus.

Podfile

pod 'Firebase/Database'

Synchroniser les messages existants

Ajoutez du code qui synchronise les messages nouvellement ajoutés à l'UI de l'application.

Le code que vous ajoutez dans cette section :

  • Initialisez la base de données Firebase et ajoutez un écouteur pour gérer les modifications apportées à la base de données.
  • Mettez à jour DataSnapshot pour que les nouveaux messages s'affichent.

Modifiez les méthodes "deinit", "configureDatabase" et "tableView:cellForRow indexPath:" de votre FCViewController en les remplaçant par le code défini ci-dessous :

FCViewController.swift

  deinit {
    if let refHandle = _refHandle {
      self.ref.child("messages").removeObserver(withHandle: _refHandle)
    }
  }


  func configureDatabase() {
    ref = Database.database().reference()
    // Listen for new messages in the Firebase database
    _refHandle = self.ref.child("messages").observe(.childAdded, with: { [weak self] (snapshot) -> Void in
      guard let strongSelf = self else { return }
      strongSelf.messages.append(snapshot)
      strongSelf.clientTable.insertRows(at: [IndexPath(row: strongSelf.messages.count-1, section: 0)], with: .automatic)
    })
  }


  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // Dequeue cell
    let cell = self.clientTable.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath)
    // Unpack message from Firebase DataSnapshot
    let messageSnapshot = self.messages[indexPath.row]
    guard let message = messageSnapshot.value as? [String: String] else { return cell }
    let name = message[Constants.MessageFields.name] ?? ""
    let text = message[Constants.MessageFields.text] ?? ""
    cell.textLabel?.text = name + ": " + text
    cell.imageView?.image = UIImage(named: "ic_account_circle")
    if let photoURL = message[Constants.MessageFields.photoURL], let URL = URL(string: photoURL),
        let data = try? Data(contentsOf: URL) {
      cell.imageView?.image = UIImage(data: data)
    }
    return cell
  }

Tester la synchronisation des messages

  1. Cliquez sur le bouton 98205811bbed9d74.pngExécuter.
  2. Cliquez sur le bouton Se connecter pour commencer afin d'accéder à la fenêtre de messages.
  3. Ajoutez de nouveaux messages directement dans la console Firebase en cliquant sur le symbole + vert à côté de l'entrée "messages" et en ajoutant un objet comme celui-ci : f9876ffc8b316b14.png
  4. Vérifiez qu'ils s'affichent dans l'UI Friendly Chat.

7. Envoyer des messages

Implémenter Send Message

Transférez les valeurs vers la base de données. Lorsque vous utilisez la méthode push pour ajouter des données à Firebase Realtime Database, un ID automatique est ajouté. Ces ID générés automatiquement sont séquentiels, ce qui garantit que les nouveaux messages seront ajoutés dans le bon ordre.

Modifiez la méthode "sendMessage:" de votre FCViewController en la remplaçant par le code défini ci-dessous :

FCViewController.swift

  func sendMessage(withData data: [String: String]) {
    var mdata = data
    mdata[Constants.MessageFields.name] = Auth.auth().currentUser?.displayName
    if let photoURL = Auth.auth().currentUser?.photoURL {
      mdata[Constants.MessageFields.photoURL] = photoURL.absoluteString
    }

    // Push data to Firebase Database
    self.ref.child("messages").childByAutoId().setValue(mdata)
  }

Tester l'envoi de messages

  1. Cliquez sur le bouton 98205811bbed9d74.pngExécuter.
  2. Cliquez sur Se connecter pour accéder à la fenêtre de messages.
  3. Saisissez un message et appuyez sur Envoyer. Le nouveau message devrait être visible dans l'UI de l'application et dans la console Firebase.

8. Stocker et recevoir des images

Confirmer la dépendance de Firebase Storage

Dans le bloc de dépendances du Podfile, vérifiez que Firebase/Storage est inclus.

Podfile

pod 'Firebase/Storage'

Configurer Cloud Storage for Firebase

Voici comment configurer Cloud Storage for Firebase dans votre projet Firebase :

  1. Dans le panneau de gauche de la console Firebase, développez Créer, puis sélectionnez Stockage.
  2. Cliquez sur Commencer.
  3. Sélectionnez un emplacement pour votre bucket Storage par défaut.
    Les buckets situés dans les régions US-WEST1, US-CENTRAL1 et US-EAST1 peuvent profiter du niveau"Toujours sans frais" pour Google Cloud Storage. Les buckets situés dans toutes les autres régions sont soumis aux tarifs et à l'utilisation de Google Cloud Storage.
  4. Cliquez sur Démarrer en mode test. Lisez la clause de non-responsabilité concernant les règles de sécurité.
    Dans une étape ultérieure de cet atelier de programmation, vous ajouterez des règles de sécurité pour protéger vos données. Ne distribuez ni n'exposez publiquement une application sans ajouter de règles de sécurité pour votre bucket Storage.
  5. Cliquez sur Créer.

Configurer Firebase Storage

FCViewController.swift

  func configureStorage() {
    storageRef = Storage.storage().reference()
  }

Recevoir des images dans des messages existants

Ajoutez du code qui télécharge des images depuis Firebase Storage.

Modifiez la méthode "tableView: cellForRowAt indexPath:" de votre FCViewController en la remplaçant par le code défini ci-dessous :

FCViewController.swift

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // Dequeue cell
    let cell = self.clientTable .dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath)
    // Unpack message from Firebase DataSnapshot
    let messageSnapshot: DataSnapshot! = self.messages[indexPath.row]
    guard let message = messageSnapshot.value as? [String:String] else { return cell }
    let name = message[Constants.MessageFields.name] ?? ""
    if let imageURL = message[Constants.MessageFields.imageURL] {
      if imageURL.hasPrefix("gs://") {
        Storage.storage().reference(forURL: imageURL).getData(maxSize: INT64_MAX) {(data, error) in
          if let error = error {
            print("Error downloading: \(error)")
            return
          }
          DispatchQueue.main.async {
            cell.imageView?.image = UIImage.init(data: data!)
            cell.setNeedsLayout()
          }
        }
      } else if let URL = URL(string: imageURL), let data = try? Data(contentsOf: URL) {
        cell.imageView?.image = UIImage.init(data: data)
      }
      cell.textLabel?.text = "sent by: \(name)"
    } else {
      let text = message[Constants.MessageFields.text] ?? ""
      cell.textLabel?.text = name + ": " + text
      cell.imageView?.image = UIImage(named: "ic_account_circle")
      if let photoURL = message[Constants.MessageFields.photoURL], let URL = URL(string: photoURL),
          let data = try? Data(contentsOf: URL) {
        cell.imageView?.image = UIImage(data: data)
      }
    }
    return cell
  }

9. Envoyer des messages contenant des images

Implémenter le stockage et l'envoi d'images

Importez une image de l'utilisateur, puis synchronisez l'URL de stockage de cette image avec la base de données afin qu'elle soit envoyée dans le message.

Modifiez la méthode "imagePickerController: didFinishPickingMediaWithInfo:" de votre FCViewController en la remplaçant par le code défini ci-dessous :

FCViewController.swift

  func imagePickerController(_ picker: UIImagePickerController,
    didFinishPickingMediaWithInfo info: [String : Any]) {
      picker.dismiss(animated: true, completion:nil)
    guard let uid = Auth.auth().currentUser?.uid else { return }

    // if it's a photo from the library, not an image from the camera
    if #available(iOS 8.0, *), let referenceURL = info[UIImagePickerControllerReferenceURL] as? URL {
      let assets = PHAsset.fetchAssets(withALAssetURLs: [referenceURL], options: nil)
      let asset = assets.firstObject
      asset?.requestContentEditingInput(with: nil, completionHandler: { [weak self] (contentEditingInput, info) in
        let imageFile = contentEditingInput?.fullSizeImageURL
        let filePath = "\(uid)/\(Int(Date.timeIntervalSinceReferenceDate * 1000))/\((referenceURL as AnyObject).lastPathComponent!)"
        guard let strongSelf = self else { return }
        strongSelf.storageRef.child(filePath)
          .putFile(from: imageFile!, metadata: nil) { (metadata, error) in
            if let error = error {
              let nsError = error as NSError
              print("Error uploading: \(nsError.localizedDescription)")
              return
            }
            strongSelf.sendMessage(withData: [Constants.MessageFields.imageURL: strongSelf.storageRef.child((metadata?.path)!).description])
          }
      })
    } else {
      guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
      let imageData = UIImageJPEGRepresentation(image, 0.8)
      let imagePath = "\(uid)/\(Int(Date.timeIntervalSinceReferenceDate * 1000)).jpg"
      let metadata = StorageMetadata()
      metadata.contentType = "image/jpeg"
      self.storageRef.child(imagePath)
        .putData(imageData!, metadata: metadata) { [weak self] (metadata, error) in
          if let error = error {
            print("Error uploading: \(error)")
            return
          }
          guard let strongSelf = self else { return }
          strongSelf.sendMessage(withData: [Constants.MessageFields.imageURL: strongSelf.storageRef.child((metadata?.path)!).description])
      }
    }
  }

Tester l'envoi et la réception de messages contenant des images

  1. Cliquez sur le bouton 98205811bbed9d74.pngExécuter.
  2. Cliquez sur Se connecter pour accéder à la fenêtre de messages.
  3. Cliquez sur l'icône "Ajouter une photo" pour choisir une photo. Le nouveau message avec la photo devrait être visible dans l'UI de l'application et dans la console Firebase.

10. Félicitations !

Vous avez utilisé Firebase pour créer facilement une application de chat en temps réel.

Points abordés

  • Realtime Database
  • Connexion fédérée
  • Stockage

En savoir plus