1. Przegląd
Witamy w ćwiczeniu FriendlyChat na iOS. Z tego ćwiczenia dowiesz się, jak utworzyć w pełni funkcjonalną aplikację do czatu w czasie rzeczywistym na iOS przy użyciu Firebase i nowoczesnych funkcji języka Swift, takich jak SwiftUI, Swift Concurrency i framework Observation.
Czego się nauczysz
- Zarządzanie stanem za pomocą nowoczesnej platformy Observation (
@Observable). - Uwierzytelnianie użytkowników za pomocą Uwierzytelniania Firebase.
- Synchronizowanie wiadomości na czacie w czasie rzeczywistym za pomocą Cloud Firestore.
- Przechowywanie i udostępnianie obrazów za pomocą Cloud Storage dla Firebase.
- Dostęp do interfejsów API Firebase za pomocą nowoczesnych funkcji Swift Concurrency.
Czego potrzebujesz
- Najnowsza wersja Xcode
- Symulator iOS lub fizyczne urządzenie testowe
- Konto Google do tworzenia projektów w Firebase i zarządzania nimi
2. Pobieranie przykładowego kodu
Sklonuj repozytorium GitHub z wiersza poleceń:
$ git clone https://github.com/firebase/codelab-friendlychat-ios
Repozytorium codelab-friendlychat-ios zawiera kilka przykładowych projektów:
ios-starter/swift-starter– początkowy projekt Xcode zawierający szkielet układu SwiftUI i komentarzeTODO, w których zaimplementujesz funkcje aplikacji za pomocą Firebase.ios/swift– ukończony projekt Xcode z gotową przykładową aplikacją.
3. Tworzenie aplikacji startowej
Utwórz i uruchom aplikację startową, aby zapoznać się z interfejsem:
- W Finderze lub Terminalu przejdź do katalogu
ios-starter/swift-starter. - Kliknij dwukrotnie
FriendlyChatSwift.xcodeproj, aby otworzyć projekt w Xcode. - Zwróć uwagę, że Xcode automatycznie rozwiązuje zależności menedżera pakietów Swift w tle (pobierając
firebase-ios-sdkw wersji 12 lub nowszej z GitHub). - Wybierz symulator iOS (np. iPhone 17 Pro) i kliknij przycisk Uruchom (cmd+R).
Po kilku sekundach pojawi się ekran logowania FriendlyChat. Na tym etapie przyciski logowania i kanały wiadomości są obiektami zastępczymi. W kolejnych krokach połączysz Firebase z aplikacją.
4. Konfigurowanie projektu w Firebase
Tworzenie nowego projektu w Firebase
- Zaloguj się w konsoli Firebase za pomocą konta Google.
- Kliknij przycisk, aby utworzyć nowy projekt, a następnie wpisz jego nazwę (np.
FriendlyChat).
- Kliknij Dalej.
- Jeśli pojawi się prośba, zapoznaj się z warunkami korzystania z Firebase i zaakceptuj je, a następnie kliknij Dalej.
- (Opcjonalnie) Włącz pomoc AI w konsoli Firebase (nazywaną „Gemini w Firebase”).
- W tym ćwiczeniu nie potrzebujesz Google Analytics, więc wyłącz tę opcję.
- Kliknij Utwórz projekt, poczekaj na jego utworzenie, a następnie kliknij Dalej.
Uaktualnianie abonamentu Firebase
Aby korzystać z Cloud Storage dla Firebase, Twój projekt w Firebase musi mieć abonament 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 kwalifikujesz się do otrzymania środków w wysokości 300 USD i bezpłatnego okresu próbnego konta rozliczeniowego Cloud.
- Jeśli wykonujesz to ćwiczenie w ramach wydarzenia, zapytaj organizatora, czy są dostępne środki do wykorzystania w Cloud.
Aby przenieść projekt na abonament Blaze, wykonaj te czynności:
- W konsoli Firebase kliknij, aby uaktualnić abonament.
- Wybierz abonament Blaze. Postępuj zgodnie z instrukcjami wyświetlanymi na ekranie, aby połączyć konto rozliczeniowe Cloud z projektem.
Jeśli w ramach tej aktualizacji musisz utworzyć konto rozliczeniowe Cloud, może być konieczne powrócenie do procesu aktualizacji w konsoli Firebase, aby go dokończyć.
Łączenie aplikacji na iOS
- Na ekranie „Opis projektu” kliknij ikonę iOS, aby uruchomić proces konfiguracji aplikacji.
- Wpisz identyfikator pakietu:
com.google.firebase.codelab.FriendlyChatSwift - Kliknij Zarejestruj aplikację.
Dodawanie pliku GoogleService-Info.plist do projektu Xcode
- Kliknij Pobierz GoogleService-Info.plist , aby zapisać plik konfiguracyjny.
- W Xcode przeciągnij pobrany plik
GoogleService-Info.plistdo głównej grupyFriendlyChatSwiftw nawigatorze projektu. - Gdy pojawi się prośba, upewnij się, że zaznaczone jest pole Skopiuj elementy w razie potrzeby , a wybrany jest cel
FriendlyChatSwift, a następnie kliknij Zakończ.
Konfigurowanie Firebase w FriendlyChatSwiftApp.swift
Na koniec zainicjuj Firebase za pomocą konfiguracji projektu, gdy uruchomi się aplikacja SwiftUI. Otwórz plik FriendlyChatSwiftApp.swift i zastąp obiekty zastępcze TODO elementami import FirebaseCore i FirebaseApp.configure():
import SwiftUI
import FirebaseCore
@main
struct FriendlyChatSwiftApp: App {
init() {
FirebaseApp.configure()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
5. Uwierzytelnianie użytkowników
Konfigurowanie uwierzytelniania w konsoli Firebase
Zanim zaczniesz uwierzytelniać użytkowników, musisz najpierw włączyć wybranego dostawcę uwierzytelniania w konsoli Firebase. W tym samouczku używamy uwierzytelniania za pomocą adresu e-mail i hasła:
- W konsoli Firebase otwórz Zabezpieczenia > Uwierzytelnianie, a następnie kliknij Rozpocznij.
- Kliknij kartę Metoda logowania.
- Kliknij Adres e-mail/hasło, kliknij przełącznik Włącz i kliknij Zapisz.
Zabezpieczanie Cloud Firestore za pomocą reguł uwierzytelniania
Następnie wymagaj, aby użytkownicy byli uwierzytelnieni przed odczytaniem lub zapisaniem wiadomości:
- W konsoli Firebase otwórz Bazy danych i pamięć masowa > Baza danych Firestore, a następnie kliknij Utwórz bazę danych.
- Wybierz lokalizację i kliknij Dalej.
- Kliknij Rozpocznij w trybie testowym i Utwórz.
- Kliknij kartę Reguły i zaktualizuj reguły zabezpieczeń do:
Te reguły umożliwiają każdemu uwierzytelnionemu użytkownikowi odczytywanie i zapisywanie wiadomości w bazie danych, co jest odpowiednie do celów edukacyjnych. Więcej informacji o regułach zabezpieczeń znajdziesz w dokumentacji reguł zabezpieczeń.rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /messages/{messageId} { allow read, write: if request.auth != null; } } } - Kliknij Opublikuj.
Obserwowanie stanu uwierzytelniania w UserViewModel.swift
W SwiftUI obserwowanie stanu uwierzytelniania Firebase w sposób reaktywny zapewnia płynne przełączanie interfejsu między ekranem logowania a interfejsem czatu.
Otwórz plik ViewModels/UserViewModel.swift i zastąp TODO w init() , aby obserwować zmiany stanu uwierzytelniania za pomocą AsyncSequence authStateChanges:
init() {
authTask = Task {
for await user in Auth.auth().authStateChanges {
self.user = user
}
}
}
Implementowanie logowania się, rejestracji i wylogowywania za pomocą Swift Concurrency
W pliku UserViewModel.swift zastąp pozostałe komentarze TODO nowoczesnymi metodami uwierzytelniania async/await:
func signIn(email: String, password: String) async {
errorMessage = nil
if email.isEmpty || password.isEmpty {
showError("Please enter both email and password.")
return
}
do {
try await Auth.auth().signIn(withEmail: email, password: password)
} catch {
showError(error.localizedDescription)
}
}
func signUp(email: String, password: String, displayName: String) async {
errorMessage = nil
if email.isEmpty || password.isEmpty {
showError("Please enter both email and password.")
return
}
do {
let result =
try await Auth.auth().createUser(withEmail: email, password: password)
let changeRequest = result.user.createProfileChangeRequest()
changeRequest.displayName = displayName.isEmpty ? email : displayName
try await changeRequest.commitChanges()
self.user = Auth.auth().currentUser
} catch {
showError(error.localizedDescription)
}
}
func updateDisplayName(_ displayName: String) async {
guard let currentUser = Auth.auth().currentUser else { return }
do {
let changeRequest = currentUser.createProfileChangeRequest()
changeRequest.displayName = displayName
try await changeRequest.commitChanges()
self.user = Auth.auth().currentUser
} catch {
showError(error.localizedDescription)
}
}
func signOut() {
do {
try Auth.auth().signOut()
} catch {
showError(error.localizedDescription)
}
}
Testowanie uwierzytelniania użytkowników
- W Xcode kliknij przycisk Uruchom.
- W symulatorze aplikacji kliknij Zarejestruj się, wpisz nazwę wyświetlaną, adres e-mail i hasło, a następnie kliknij ZAREJESTRUJ SIĘ.
- Powinno nastąpić automatyczne uwierzytelnienie i przejście do pustego ekranu wiadomości.
6. Odczytywanie z Cloud Firestore
Dodawanie przykładowych wiadomości w konsoli Firebase
Wypełnij bazę danych przykładowymi wiadomościami:
- W konsoli Firebase otwórz Baza danych Firestore i kliknij kartę Dane.
- Kliknij Rozpocznij kolekcję.
- W polu Identyfikator kolekcji wpisz
messages, a następnie kliknij Dalej. - Pozostaw ustawienie Identyfikator dokumentu na automatyczne generowanie (lub kliknij Automatyczny identyfikator).
- Dodaj do dokumentu te pola:
text(typ:string, wartość:Hello)displayName(typ:string, wartość:anonymous)
- Kliknij Zapisz.
- Opcjonalnie kliknij Dodaj dokument , aby dodać więcej przykładowych wiadomości.
Synchronizowanie wiadomości w FriendlyMessageViewModel.swift
W SwiftUI model @Observable steruje deklaratywnymi aktualizacjami interfejsu. Otwórz plik ViewModels/FriendlyMessageViewModel.swift i zaimplementuj startListening() oraz stopListening() za pomocą AsyncSequence snapshots:
func startListening() {
stopListening()
listenerTask = Task {
let db = Firestore.firestore()
do {
for try await snapshot in db.collection("messages").snapshots {
self.messages = snapshot.documents.compactMap { document in
try? document.data(as: FriendlyMessage.self)
}
}
} catch {
print("Error listening for messages: \(error)")
}
}
}
func stopListening() {
listenerTask?.cancel()
listenerTask = nil
messages.removeAll()
}
Jak SwiftUI renderuje i automatycznie przewija wiadomości
W pliku Views/ContentView.swift zobacz, jak ScrollViewReader i LazyVStack renderują dymki czatu i automatycznie przewijają do najnowszej wiadomości, gdy tylko zmieni się wartość messages.count:
ScrollViewReader { scrollViewReader in
ScrollView {
LazyVStack(spacing: 12) {
ForEach(messageViewModel.messages) { message in
FriendlyMessageView(friendlyMessage: message)
.id(message.id)
}
}
.padding(.horizontal)
.onChange(of: messageViewModel.messages.count) { _, count in
guard count > 0,
let lastId = messageViewModel.messages.last?.id else { return }
withAnimation(.easeInOut) {
scrollViewReader.scrollTo(lastId, anchor: .bottom)
}
}
}
}
Dzięki powiązaniu stanu bazy danych bezpośrednio ze stanem interfejsu za pomocą modelu widoku SwiftUI umożliwia kodowi aplikacji czyste mapowanie przejść na animacje. W następnym kroku zapiszesz dane w bazie danych z aplikacji, aby zobaczyć tę animację w działaniu.
7. Wysyłanie wiadomości
Implementowanie sendMessage za pomocą Swift Concurrency
Gdy dodasz dokument do kolekcji za pomocą addDocument(), Cloud Firestore wygeneruje unikalny identyfikator każdej wiadomości na czacie.
W pliku ViewModels/FriendlyMessageViewModel.swift zastąp TODO w sendMessage(text:imageUrl:) metodą async throws:
func sendMessage(text: String?, imageUrl: String?) async throws {
guard let currentUser = Auth.auth().currentUser else { return }
let message = FriendlyMessage(
text: text,
displayName: currentUser.displayName ?? currentUser.email ?? "Anonymous",
imageUrl: imageUrl,
userId: currentUser.uid
)
let db = Firestore.firestore()
_ = try db.collection("messages").addDocument(from: message)
}
Testowanie wysyłania wiadomości
- W Xcode kliknij przycisk Uruchom.
- Zaloguj się na konto.
- Wpisz wiadomość w dolnym polu tekstowym i kliknij ikonę Wyślij.
- Zobacz, jak wiadomość natychmiast pojawia się w symulatorze.
8. Przechowywanie i odbieranie obrazów
Konfigurowanie Cloud Storage dla Firebase
- W konsoli Firebase otwórz Bazy danych i pamięć masowa > Pamięć masowa, a następnie kliknij Rozpocznij.
- Kliknij Rozpocznij w trybie testowym i Dalej.
- Zaakceptuj domyślną lokalizację pamięci masowej i kliknij Gotowe.
Natywne wybieranie obrazów za pomocą SwiftUI PhotosPicker
Nowoczesny SwiftUI (iOS 16 lub nowszy) umożliwia natywne wybieranie zdjęć za pomocą PhotosPicker z import PhotosUI – nie są wymagane żadne mostki delegatów UIKit ani otoki UIImagePickerController.
W pliku Views/FooterView.swift zobacz, jak PhotosPicker wiąże wybrane obrazy:
PhotosPicker(selection: $selectedItem, matching: .images) {
Image(systemName: "photo.on.rectangle.angled")
.font(.system(size: 26))
.foregroundStyle(.blue)
.accessibilityLabel("Select photo")
}
.onChange(of: selectedItem) { _, newItem in
Task {
if let data = try? await newItem?.loadTransferable(type: Data.self) {
await uploadAndSendImage(data: data)
}
}
}
Implementowanie przesyłania obrazów
Gdy wybierzesz zdjęcie, prześlij dane obrazu do Cloud Storage i zapisz publiczny adres URL pobierania w Cloud Firestore.
W pliku Views/FooterView.swift zastąp TODO w uploadAndSendImage(data:):
private func uploadAndSendImage(data: Data) async {
guard let uid = Auth.auth().currentUser?.uid else { return }
isUploading = true
defer {
isUploading = false
selectedItem = nil
}
do {
let filename = "\(uid)/\(UUID().uuidString).jpg"
let storageRef =
Storage.storage().reference().child("images").child(filename)
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
_ = try await storageRef.putDataAsync(data, metadata: metadata)
let downloadURL = try await storageRef.downloadURL()
try await viewModel.sendMessage(
text: nil, imageUrl: downloadURL.absoluteString)
} catch {
print("Error uploading image: \(error.localizedDescription)")
}
}
Udostępnianie obrazów za pomocą Cloud Storage
W pliku Views/FriendlyMessageImageView.swift adresy URL obrazów są wczytywane asynchronicznie za pomocą Swift Concurrency i pakietu SDK Cloud Storage:
- Standardowe adresy URL pobierania HTTP/HTTPS są pobierane asynchronicznie za pomocą
URLSession. - Adresy URL Google Cloud Storage (np.
gs://...) są pobierane za pomocąStorage.storage().reference(forURL:).
Testowanie wiadomości z obrazami
- W Xcode kliknij przycisk Uruchom.
- Zaloguj się na konto.
- Kliknij ikonę Zdjęcie, wybierz obraz z biblioteki i zobacz, jak jest przesyłany i pojawia się na czacie.
9. Podsumowanie
Udało Ci się utworzyć aplikację do czatu w czasie rzeczywistym na iOS przy użyciu Swift i Firebase.
Czego się nauczysz
- Integracja menedżera pakietów Swift (SPM) z Xcode na potrzeby
firebase-ios-sdk. - Deklaratywne układy SwiftUI ,
PhotosPickeri automatyczne przewijanieScrollViewReader. - Swift Concurrency (
async/await) w uwierzytelnianiu, Cloud Firestore i Cloud Storage. - Uwierzytelnianie za pomocą adresu e-mail i hasła oraz uwierzytelnianie anonimowe z reaktywną obserwacją stanu.
- Cloud Firestore – nasłuchiwanie migawek w czasie rzeczywistym i automatyczne zapisywanie identyfikatorów.
- Cloud Storage dla Firebase – przesyłanie plików binarnych i publiczne adresy URL pobierania.