1. Przegląd
Witamy w samouczku Friendly Chat. Z tego ćwiczenia w Codelabs dowiesz się, jak tworzyć aplikacje na iOS przy użyciu platformy Firebase. Wdrożysz klienta czatu i będziesz monitorować jego wydajność za pomocą Firebase.
Czego się nauczysz
- Zezwalaj użytkownikom na logowanie się.
- Synchronizuj dane za pomocą Bazy danych czasu rzeczywistego Firebase.
- przechowywanie plików binarnych w Pamięci Firebase,
Czego potrzebujesz
- Xcode
- CocoaPods
- urządzenie testowe z systemem iOS 8.0 lub nowszym albo symulator;
Jak zamierzasz wykorzystać ten samouczek?
Jak oceniasz swoje doświadczenie w tworzeniu aplikacji na iOS?
2. Pobieranie przykładowego kodu
Sklonuj repozytorium GitHub z wiersza poleceń.
$ git clone https://github.com/firebase/codelab-friendlychat-ios
3. Tworzenie aplikacji startowej
Aby skompilować aplikację startową:
- W oknie terminala przejdź do katalogu
ios-starter/swift-starter
pobranego przykładowego kodu. - Uruchom
pod install --repo-update
- Otwórz plik FriendlyChatSwift.xcworkspace, aby otworzyć projekt w Xcode.
- Kliknij przycisk
Uruchom.
Po kilku sekundach powinien pojawić się ekran główny aplikacji Friendly Chat. Powinien pojawić się interfejs. Nie możesz się jednak zalogować ani wysyłać i odbierać wiadomości. Aplikacja zostanie przerwana z wyjątkiem, dopóki nie wykonasz następnego kroku.
4. Konfigurowanie projektu Firebase
Tworzenie nowego projektu Firebase
- Zaloguj się w konsoli Firebase, korzystając ze swojego konta Google.
- Kliknij przycisk, aby utworzyć nowy projekt, a potem wpisz jego nazwę (np.
FriendlyChat
).
- Kliknij Dalej.
- Po wyświetleniu monitu przeczytaj i zaakceptuj warunki usługi Firebase, a potem kliknij Dalej.
- (Opcjonalnie) Włącz w konsoli Firebase pomoc AI (nazywaną „Gemini w Firebase”).
- W tym samouczku nie potrzebujesz Google Analytics, więc wyłącz opcję Google Analytics.
- Kliknij Utwórz projekt, poczekaj, aż projekt zostanie udostępniony, a następnie kliknij Dalej.
Uaktualnianie abonamentu Firebase
Aby korzystać z Cloud Storage dla Firebase, Twój projekt Firebase musi być objęty abonamentem z płatnością według wykorzystania (Blaze), co oznacza, że jest połączony z kontem rozliczeniowym Cloud.
- Konto rozliczeniowe Cloud wymaga formy płatności, np. karty kredytowej.
- Jeśli dopiero zaczynasz korzystać z Firebase i Google Cloud, sprawdź, czy możesz otrzymać środki w wysokości 300 USD i bezpłatne konto rozliczeniowe Cloud.
- Jeśli wykonujesz te ćwiczenia w ramach wydarzenia, zapytaj organizatora, czy są dostępne środki w Google Cloud.
Aby przenieść projekt na abonament Blaze:
- W konsoli Firebase wybierz przejście na wyższy abonament.
- 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 abonament konieczne było utworzenie konta rozliczeniowego Cloud, może być konieczne powrócenie do procesu przejścia na wyższy abonament w konsoli Firebase, aby go dokończyć.
Łączenie aplikacji na iOS
- Na ekranie Przegląd projektu nowego projektu kliknij Dodaj Firebase do aplikacji na iOS.
- Wpisz identyfikator pakietu w formacie „
com.google.firebase.codelab.FriendlyChatSwift
”. - Wpisz identyfikator App Store w formacie „
123456
”. - Kliknij Zarejestruj aplikację.
Dodawanie pliku GoogleService-Info.plist do aplikacji
Na drugim ekranie kliknij Download GoogleService-Info.plist (Pobierz GoogleService-Info.plist), aby pobrać plik konfiguracyjny zawierający wszystkie niezbędne metadane Firebase dla Twojej aplikacji. Skopiuj ten plik do aplikacji i dodaj go do elementu docelowego FriendlyChatSwift.
Możesz teraz kliknąć „x” w prawym górnym rogu wyskakującego okienka, aby je zamknąć (pomijając kroki 3 i 4), ponieważ wykonasz te czynności tutaj.
Importowanie modułu Firebase
Zacznij od sprawdzenia, czy moduł Firebase
jest zaimportowany.
AppDelegate.swift, FCViewController.swift
import Firebase
Konfigurowanie Firebase w pliku AppDelegate
Użyj metody „configure” w FirebaseApp w funkcji application:didFinishLaunchingWithOptions, aby skonfigurować podstawowe usługi Firebase z pliku .plist.
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
Teraz dodamy regułę, która będzie wymagać uwierzytelniania przed odczytaniem lub zapisaniem jakichkolwiek 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 następnie 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 dokumentację zmiennej „auth”), znajdziesz w dokumentacji zabezpieczeń Firebase.
Konfigurowanie interfejsów 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ć.
- Otwórz konsolę Firebase i wybierz projekt.
- Wybierz Uwierzytelnianie.
- Wybierz kartę Metoda logowania.
- Ustaw przełącznik Google w pozycji włączonej (niebieskiej).
- W wyświetlonym oknie kliknij Zapisz.
Jeśli w dalszej części tego samouczka pojawią się błędy z komunikatem „CONFIGURATION_NOT_FOUND”, wróć do tego kroku i dokładnie sprawdź swoją pracę.
Potwierdź zależność od Uwierzytelniania Firebase
Sprawdź, czy w pliku Podfile
znajdują się zależności uwierzytelniania Firebase.
Podfile
pod 'Firebase/Auth'
Skonfiguruj plik Info.plist na potrzeby logowania przez Google.
Musisz dodać do projektu XCode niestandardowy schemat adresu URL.
- Otwórz konfigurację projektu: w widoku drzewa po lewej stronie kliknij dwukrotnie nazwę projektu. W sekcji CELE wybierz aplikację, a potem kliknij kartę Informacje i rozwiń sekcję Typy adresów URL.
- Kliknij przycisk +, a następnie dodaj schemat adresu URL dla odwróconego identyfikatora klienta. Aby znaleźć tę wartość, otwórz plik konfiguracyjny GoogleService-Info.plist i wyszukaj klucz REVERSED_CLIENT_ID. Skopiuj wartość tego klucza i wklej ją w polu Schematy URL na stronie konfiguracji. Pozostałe pola pozostaw puste.
- Po zakończeniu konfiguracja powinna wyglądać podobnie do tej poniżej (ale z wartościami specyficznymi dla Twojej aplikacji):
Ustawianie identyfikatora klienta na potrzeby logowania przez Google
Po skonfigurowaniu Firebase możemy użyć identyfikatora klienta do skonfigurowania logowania przez Google w metodzie „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 funkcji obsługi logowania
Gdy logowanie przez Google zakończy się powodzeniem, użyj konta do uwierzytelnienia 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 zalogować użytkownika; Następnie dodaj do Firebase Auth odbiornik, który po zalogowaniu się użytkownika umożliwi mu dostęp do aplikacji. Usuń detektor podczas wywoływania funkcji deinit.
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 odczytywania wiadomości jako zalogowany użytkownik
- Kliknij przycisk
Uruchom.
- Powinno nastąpić natychmiastowe przekierowanie na ekran logowania. Kliknij przycisk logowania przez Google.
- Jeśli wszystko przebiegło prawidłowo, powinna się otworzyć ekran wiadomości.
6. Aktywowanie Bazy danych czasu rzeczywistego
Importowanie wiadomości
W projekcie w konsoli Firebase wybierz element Baza danych na pasku nawigacyjnym po lewej stronie. W menu dodatkowym bazy danych wybierz Importuj JSON. Przejdź do pliku initial_messages.json
w katalogu friendlychat, 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 znaku + i czerwonego znaku x do dodawania i usuwania elementów.
Po zaimportowaniu baza danych powinna wyglądać tak:
Potwierdź zależność od bazy danych Firebase
W bloku zależności pliku Podfile
sprawdź, czy znajduje się w nim Firebase/Database
.
Podfile
pod 'Firebase/Database'
Synchronizowanie istniejących wiadomości
Dodaj kod, który synchronizuje nowo dodane wiadomości z interfejsem aplikacji.
Kod dodany w tej sekcji:
- Zainicjuj bazę danych Firebase i dodaj odbiornik, który będzie obsługiwać zmiany wprowadzane w bazie danych.
- Zaktualizuj aplikację
DataSnapshot
, aby wyświetlać nowe wiadomości.
Zmodyfikuj metody „deinit”, „configureDatabase” i „tableView:cellForRow indexPath:” w klasie FCViewController, zastępując 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
- Kliknij przycisk
Uruchom.
- Kliknij przycisk Zaloguj się, aby rozpocząć, aby przejść do okna wiadomości.
- Dodaj nowe wiadomości bezpośrednio w konsoli Firebase. Aby to zrobić, kliknij zielony symbol + obok pozycji „messages” i dodaj obiekt podobny do tego:
- Sprawdź, czy są widoczne w interfejsie Friendly-Chat.
7. Wysyłanie wiadomości
Wdrażanie funkcji wysyłania wiadomości
Przekazywanie wartości do bazy danych. Gdy używasz metody push do dodawania danych do Bazy danych czasu rzeczywistego Firebase, automatycznie dodawany jest identyfikator. Te wygenerowane automatycznie identyfikatory są sekwencyjne, co zapewnia dodawanie nowych wiadomości we właściwej kolejności.
Zmodyfikuj metodę „sendMessage:” w pliku 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
- Kliknij przycisk
Uruchom.
- Kliknij Zaloguj się, aby przejść do okna wiadomości.
- 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 Pamięci Firebase
W bloku zależności w pliku Podfile
sprawdź, czy jest uwzględniona zależność Firebase/Storage
.
Podfile
pod 'Firebase/Storage'
Konfigurowanie Cloud Storage dla Firebase
Aby skonfigurować Cloud Storage dla Firebase w projekcie Firebase:
- W panelu po lewej stronie konsoli Firebase rozwiń Kompilacja, a następnie wybierz Storage.
- Kliknij Rozpocznij.
- Wybierz lokalizację domyślnego zasobnika Storage.
Zasobniki w regionachUS-WEST1
,US-CENTRAL1
iUS-EAST1
mogą korzystać z poziomu „Zawsze bezpłatny” w Google Cloud Storage. W przypadku zasobników w innych lokalizacjach obowiązuje cennik i wykorzystanie Google Cloud Storage. - Kliknij Uruchom w trybie testowym. Przeczytaj wyłączenie odpowiedzialności dotyczące reguł bezpieczeństwa.
W dalszej części tego laboratorium dodasz reguły bezpieczeństwa, aby zabezpieczyć swoje dane. Nieudostępniaj aplikacji publicznie bez dodania reguł bezpieczeństwa do zasobnika Storage. - Kliknij Utwórz.
Konfigurowanie Firebase Storage
FCViewController.swift
func configureStorage() {
storageRef = Storage.storage().reference()
}
Otrzymywanie obrazów w istniejących wiadomościach
Dodaj kod, który pobiera obrazy z Pamięci Firebase.
Zmodyfikuj metodę „tableView: cellForRowAt indexPath:” w pliku FCViewController, zastępując 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 obrazami
Wdrażanie funkcji przechowywania i wysyłania obrazów
Prześlij obraz od użytkownika, a następnie zsynchronizuj adres URL przechowywania tego obrazu z bazą danych, aby obraz był wysyłany w wiadomości.
Zmodyfikuj metodę „imagePickerController: didFinishPickingMediaWithInfo:” w pliku 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 obrazami
- Kliknij przycisk
Uruchom.
- Kliknij Zaloguj się, aby przejść do okna wiadomości.
- Kliknij ikonę „Dodaj zdjęcie”, aby wybrać zdjęcie. Nowa wiadomość ze zdjęciem powinna być widoczna w interfejsie aplikacji i w konsoli Firebase.
10. Gratulacje!
Za pomocą Firebase możesz łatwo utworzyć aplikację do czatu w czasie rzeczywistym.
Omówione zagadnienia
- Baza danych czasu rzeczywistego
- Logowanie sfederowane
- Miejsce na dane