Ćwiczenie z programowania w Firebase na iOS Swift

1. Omówienie

2efe6805ef369641.png

Witamy w usłudze Friendly Chat. Z tego ćwiczenia w Codelab dowiesz się, jak korzystać z platformy Firebase do tworzenia aplikacji na iOS. Wdrożycie klienta czatu i monitorowanie jego wydajności za pomocą Firebase.

Czego się nauczysz

  • Zezwalaj użytkownikom na logowanie się.
  • Synchronizuj dane za pomocą Bazy danych czasu rzeczywistego Firebase.
  • przechowywać pliki binarne w Pamięci Firebase.

Czego potrzebujesz

  • Xcode
  • CocoaPods
  • urządzenie testowe z systemem iOS 8.0 lub nowszym albo symulator.

Jak będziesz korzystać z tego samouczka?

Tylko przeczytać Przeczytać i wykonać ćwiczenia

Jak oceniasz tworzenie aplikacji na iOS?

Początkujący Średnio zaawansowany Zaawansowany

2. Pobieranie przykładowego kodu

Sklonuj repozytorium GitHub z poziomu wiersza poleceń.

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

3. Tworzenie aplikacji startowej

2f4c98d858c453fe.png

Aby utworzyć aplikację startową:

  1. W oknie terminala przejdź do katalogu android_studio_folder.pngios-starter/swift-starter z pobranego przykładowego kodu.
  2. Uruchom pod install --repo-update
  3. Otwórz plik FriendlyChatSwift.xcworkspace, aby otworzyć projekt w Xcode.
  4. Kliknij przycisk 98205811bbed9d74.pngUruchom.

Po kilku sekundach powinien pojawić się ekran główny Friendly Chat. Powinien pojawić się interfejs. Nie możesz jednak zalogować się, wysyłać ani odbierać wiadomości. Aplikacja przerwie działanie z wyjątkiem, dopóki nie wykonasz następnego kroku.

4. Tworzenie projektu w konsoli Firebase

Utwórz projekt

W konsoli Firebase kliknij Dodaj projekt.

Nazwij projekt FriendlyChat, a potem kliknij Utwórz projekt.

Zrzut ekranu z 2015-11-06 14:13:39.png

Uaktualnianie abonamentu Firebase

Aby korzystać z Cloud Storage dla Firebase, musisz mieć projekt Firebase w abonamentem Blaze (opłaty według wykorzystania), co oznacza, że jest on połączony z kontem rozliczeniowym Cloud.

Aby przenieść projekt na abonament Blaze:

  1. W konsoli Firebase wybierz uaktualnienie abonamentu.
  2. Wybierz pakiet Blaze. Postępuj zgodnie z instrukcjami wyświetlanymi na ekranie, aby połączyć konto rozliczeniowe Cloud z projektem.
    Jeśli w ramach tego przejścia na wyższy poziom abonamentu musisz utworzyć konto rozliczeniowe Cloud, konieczne może być powrót do procesu przejścia w konsoli Firebase, aby go dokończyć.

Łączenie aplikacji na iOS

  1. Na ekranie Przegląd projektu nowego projektu kliknij Dodaj Firebase do aplikacji na iOS.
  2. Wpisz identyfikator pakietu, np. „com.google.firebase.codelab.FriendlyChatSwift”.
  3. Wpisz identyfikator App Store jako „123456”.
  4. Kliknij Zarejestruj aplikację.

Dodawanie do aplikacji pliku GoogleService-Info.plist

Na drugim ekranie kliknij Pobierz plik GoogleService-Info.plist, aby pobrać plik konfiguracji zawierający wszystkie niezbędne metadane Firebase dla Twojej aplikacji. Skopiuj ten plik do swojej aplikacji i dodaj go do elementu docelowego FriendlyChatSwift.

Teraz możesz zamknąć wyskakujące okienko, klikając „x” w prawym górnym rogu. W ten sposób pominiesz kroki 3 i 4, ponieważ wykonasz je tutaj.

19d59efb213ddbdc.png

Importowanie modułu Firebase

Najpierw sprawdź, czy moduł Firebase został zaimportowany.

AppDelegate.swift, FCViewController.swift

import Firebase

Konfigurowanie Firebase w pliku AppDelegate

Aby skonfigurować podstawowe usługi Firebase z pliku plist, użyj metody „configure” w klasie FirebaseApp w ramach funkcji application:didFinishLaunchingWithOptions.

AppDelegate.swift

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

5. Identyfikowanie użytkowników

Używanie reguł do ograniczania dostępu do uwierzytelnionych użytkowników

Dodamy teraz regułę, która będzie wymagać uwierzytelnienia przed odczytaniem lub zapisaniem wiadomości. W tym celu dodajemy do obiektu danych wiadomości te reguły. W sekcji Baza danych w konsoli Firebase wybierz Realtime Database, a potem kliknij kartę Reguły. Następnie zaktualizuj reguły, aby wyglądały tak:

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

Więcej informacji o tym, jak to działa (w tym dokumentacji dotyczącej zmiennej „auth”) znajdziesz w dokumentacji dotyczącej zabezpieczeń Firebase.

Skonfiguruj interfejsy API uwierzytelniania

Zanim aplikacja będzie mogła uzyskiwać dostęp do interfejsów API uwierzytelniania Firebase w imieniu użytkowników, musisz ją włączyć.

  1. Otwórz konsolę Firebase i wybierz swój projekt.
  2. Kliknij Uwierzytelnianie.
  3. Wybierz kartę Metoda logowania.
  4. Ustaw przełącznik Google w pozycji włączonej (niebieskiej).
  5. W oknie, które się pojawi, kliknij Zapisz.

Jeśli w późniejszej części tego ćwiczenia pojawią się błędy z komunikatem „CONFIGURATION_NOT_FOUND”, wróć do tego kroku i sprawdź dokładnie swoją pracę.

Potwierdź zależność od Uwierzytelniania Firebase

Sprawdź, czy w pliku Podfile występują zależności funkcji uwierzytelniania Firebase.

Podfile

pod 'Firebase/Auth'

Skonfiguruj plik Info.plist na potrzeby logowania się przez Google.

Musisz dodać niestandardowy schemat URL do projektu XCode.

  1. Otwórz konfigurację projektu: kliknij dwukrotnie nazwę projektu w widoku drzewa po lewej stronie. W sekcji CELE wybierz swoją aplikację, a potem kliknij kartę Informacje i rozwiń sekcję Typy adresów URL.
  2. Kliknij przycisk + i dodaj schemat adresu URL dla odwróconego identyfikatora klienta. Aby znaleźć tę wartość, otwórz plik konfiguracji GoogleService-Info.plist i poszukaj klucza REVERSED_CLIENT_ID. Skopiuj wartość tego klucza i wklej ją w polu Schematy adresów URL na stronie konfiguracji. Pozostałe pola pozostaw puste.
  3. Po zakończeniu konfiguracja powinna wyglądać mniej więcej tak (ale z wartościami odpowiednimi dla Twojej aplikacji):

1b54d5bd2f4f1448.png

Ustawianie identyfikatora klienta na potrzeby logowania przez Google

Po skonfigurowaniu Firebase możemy użyć identyfikatora klienta, aby skonfigurować logowanie w Google w ramach metody „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
}

Dodawanie obsługi logowania

Gdy logowanie się w Google się powiedzie, użyj tego konta do uwierzytelnienia się w 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
      }
    }
  }

automatycznie logować użytkownika; Następnie dodaj do Firebase Auth odsłuchiwanie, aby umożliwić użytkownikowi dostęp do aplikacji po zalogowaniu. Usuń też listenera na końcu.

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)
    }
  }

Wyloguj się

Dodawanie metody wylogowywania

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)")
    }
  }

Testowanie czytania wiadomości jako zalogowany użytkownik

  1. Kliknij przycisk 98205811bbed9d74.pngUruchom.
  2. Powinieneś zostać natychmiast przekierowany na ekran logowania. Kliknij przycisk logowania w Google.
  3. Jeśli wszystko zadziała, powinieneś/powinnaś zobaczyć ekran wiadomości.

6. Aktywowanie Bazy danych czasu rzeczywistego

2efe6805ef369641.png

Importowanie wiadomości

konsoli Firebase wybierz element Baza danych na pasku nawigacyjnym po lewej stronie. W menu rozszerzonym bazy danych wybierz Importuj plik JSON. W katalogu friendlychat odszukaj plik initial_messages.json, wybierz go i kliknij przycisk Importuj. Spowoduje to zastąpienie wszystkich danych znajdujących się obecnie w Twojej bazie danych. Możesz też edytować bazę danych bezpośrednio, używając zielonego przycisku + i czerwonego przycisku x, aby dodawać i usuwać elementy.

20ccf4856b715b4c.png

Po zaimportowaniu baza danych powinna wyglądać tak:

f3e0367f1c9cd187.png

Potwierdź zależność od bazy danych Firebase

W bloku zależności w pliku Podfile sprawdź, czy uwzględniono plik Firebase/Database.

Podfile

pod 'Firebase/Database'

Synchroniz istniejące wiadomości

Dodaj kod, który zsynchronizuje nowo dodane wiadomości z interfejsem aplikacji.

Kod dodany w tej sekcji:

  • Inicjalizacja bazy danych Firebase i dodanie do niej odsłuchiwania zmian.
  • Zaktualizuj aplikację DataSnapshot, aby wyświetlić nowe wiadomości.

Zmodyfikuj metody „deinit”, „configureDatabase” i „tableView:cellForRow:indexPath:” klasy FCViewController. Zastąp je kodem zdefiniowanym poniżej:

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
  }

Testowanie synchronizacji wiadomości

  1. Kliknij przycisk 98205811bbed9d74.pngUruchom.
  2. Kliknij przycisk Zaloguj się, aby rozpocząć, aby otworzyć okno wiadomości.
  3. Dodaj nowe wiadomości bezpośrednio w konsoli Firebase, klikając zielony symbol + obok pozycji „wiadomości” i dodając obiekt o takiej postaci: f9876ffc8b316b14.png
  4. Sprawdź, czy są one widoczne w interfejsie czatu Friendly.

7. Wysyłanie wiadomości

Zaimplementuj funkcję wysyłania wiadomości

Przesyłanie wartości do bazy danych. Gdy używasz metody push do dodawania danych do Bazy danych czasu rzeczywistego Firebase, dodawane jest automatyczne identyfikator. Te automatycznie generowane identyfikatory są uporządkowane chronologicznie, co zapewnia, że nowe wiadomości będą dodawane w prawidłowej kolejności.

Zmodyfikuj metodę „sendMessage:” klasy FCViewController, zastępując ją kodem zdefiniowanym poniżej:

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)
  }

Testowanie wysyłania wiadomości

  1. Kliknij przycisk 98205811bbed9d74.pngUruchom.
  2. Kliknij Zaloguj się, aby otworzyć okno wiadomości.
  3. Wpisz wiadomość i kliknij Wyślij. Nowa wiadomość powinna być widoczna w interfejsie aplikacji i w konsoli Firebase.

8. Przechowywanie i odbieranie obrazów

Potwierdź zależność od usługi Pamięć Firebase

W bloku zależności w pliku Podfile sprawdź, czy uwzględniono plik Firebase/Storage.

Podfile

pod 'Firebase/Storage'

Konfigurowanie Cloud Storage dla Firebase

Oto jak skonfigurować Cloud Storage dla Firebase w projekcie Firebase:

  1. W panelu po lewej stronie konsoli Firebase rozwiń Kompilacja, a potem kliknij Storage.
  2. Kliknij Rozpocznij.
  3. Wybierz lokalizację domyślnego zasobnika Storage.
    Zasobniki w regionach US-WEST1, US-CENTRAL1 i US-EAST1 mogą korzystać z poziomu Always Free w Google Cloud Storage. Zasobniki w innych lokalizacjach podlegają cennikom i zasadom korzystania z Google Cloud Storage.
  4. Kliknij Rozpocznij w trybie testowym. Przeczytaj wyłączenie odpowiedzialności dotyczące reguł bezpieczeństwa.
    W dalszej części tego Codelab dodasz reguły bezpieczeństwa, które ochronią Twoje dane. Nie udostępniaj ani nie udostępniaj publicznie aplikacji bez dodania reguł bezpieczeństwa dla zasobnika Storage.
  5. Kliknij Utwórz.

Konfigurowanie FirebaseStorage

FCViewController.swift

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

Otrzymywanie obrazów w dotychczasowych wiadomościach

Dodaj kod, który pobiera obrazy z Pamięci Firebase.

Zmodyfikuj metodę „tableView: cellForRowAt indexPath:” klasy FCViewController. Zastąp ją kodem zdefiniowanym poniżej:

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. Wysyłanie wiadomości z obrazem

Wdrażanie funkcji przechowywania i wysyłania obrazów

Prześlij obraz od użytkownika, a potem zsynchronizuj adres URL jego magazynu z bazą danych, aby obraz był wysyłany w ramach wiadomości.

Zmodyfikuj metodę „imagePickerController: didFinishPickingMediaWithInfo:” w klasie FCViewController, zastępując ją kodem zdefiniowanym poniżej:

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])
      }
    }
  }

Testowanie wysyłania i odbierania wiadomości z obrazem

  1. Kliknij przycisk 98205811bbed9d74.pngUruchom.
  2. Kliknij Zaloguj się, aby otworzyć okno wiadomości.
  3. Kliknij ikonę „Dodaj zdjęcie”, aby wybrać zdjęcie. Nowa wiadomość z zdjęciem powinna być widoczna w interfejsie aplikacji i w konsoli Firebase.

10. Gratulacje!

Użyj Firebase do łatwego tworzenia aplikacji do czatu w czasie rzeczywistym.

Omówione zagadnienia

  • Baza danych czasu rzeczywistego
  • Logowanie sfederowane
  • Pamięć

Więcej informacji