1. Omówienie
Witamy na szkoleniu z programowania na temat przyjaznego czatu. Z tego ćwiczenia w Codelabs dowiesz się, jak używać platformy Firebase do tworzenia aplikacji na iOS. Zaimplementujesz klienta czatu i będziesz monitorować jego skuteczność za pomocą Firebase.
Czego się nauczysz
- Zezwalaj użytkownikom na logowanie się.
- Synchronizowanie danych przy użyciu Bazy danych czasu rzeczywistego Firebase.
- Przechowuj pliki binarne w Firebase Storage.
Czego potrzebujesz
- Xcode
- CocoaPods
- urządzenia testowego z systemem iOS 8.0 lub nowszym albo symulatorem
Jak wykorzystasz ten samouczek?
Jak oceniasz swoje doświadczenia z tworzeniem aplikacji na iOS?
2. Pobieranie przykładowego kodu
Skopiuj repozytorium GitHub z poziomu wiersza poleceń.
$ git clone https://github.com/firebase/codelab-friendlychat-ios
3. Utwórz aplikację startową
Aby utworzyć aplikację startową:
- W oknie terminala przejdź do katalogu
ios-starter/swift-starter
z pobranego przykładowego kodu - Uruchom
pod install --repo-update
- Otwórz plik friendChatSwift.xcworkspace, by otworzyć projekt w Xcode.
- Kliknij przycisk Uruchom.
Po kilku sekundach powinien wyświetlić się ekran główny znajomego czatu. Powinien się wyświetlić interfejs. Nie możesz się jednak zalogować, wysyłać ani odbierać wiadomości. Aplikacja zostanie przerwana w wyjątku, dopóki nie wykonasz kolejnego kroku.
4. Utwórz projekt w konsoli Firebase
Utwórz projekt
W konsoli Firebase wybierz Dodaj projekt.
Wywołaj projekt FriendlyChat
, a następnie kliknij Utwórz projekt.
Łączenie aplikacji na iOS
- Na ekranie „Przegląd projektu” nowego projektu kliknij Add Firebase to your iOS app (Dodaj Firebase do swojej aplikacji na iOS).
- Wpisz identyfikator pakietu w postaci „
com.google.firebase.codelab.FriendlyChatSwift
”. - Wpisz „
123456
” jako identyfikator App Store. - Kliknij Zarejestruj aplikację.
Dodaj plik GoogleService-Info.plist do aplikacji
Na drugim ekranie kliknij Download GoogleService-Info.plist, aby pobrać plik konfiguracyjny zawierający wszystkie metadane Firebase niezbędne dla Twojej aplikacji. Skopiuj ten plik do aplikacji i dodaj go do środowiska docelowego friendlyChatSwift.
Klikamy „x”, w prawym górnym rogu wyskakującego okienka, aby je zamknąć (pomiń kroki 3 i 4), ponieważ będziesz wykonywać te czynności tutaj.
Zaimportuj moduł Firebase
Najpierw sprawdź, czy moduł Firebase
został zaimportowany.
AppDelegate.swift, FCViewController.swift
import Firebase
Konfigurowanie Firebase w AppDelegate
Polecenie „Konfiguruj” w FirebaseApp w funkcji application:didFinishLaunchingWithOptions, aby skonfigurować podstawowe usługi Firebase z poziomu 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
Dodamy regułę wymagającą uwierzytelnienia przed odczytaniem lub zapisem jakichkolwiek wiadomości. W tym celu dodajemy poniższe reguły do obiektu danych wiadomości. W sekcji Baza danych w konsoli Firebase wybierz Baza danych czasu rzeczywistego i kliknij kartę Reguły. Następnie zmień 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
Aby aplikacja miała 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 Authentication (Uwierzytelnianie).
- Wybierz kartę Metoda logowania.
- Ustaw przełącznik Google w pozycji włączonej (niebieski).
- W wyświetlonym oknie kliknij Zapisz.
Jeśli w dalszej części tego ćwiczenia w Codelabs wystąpi błąd i pojawi się komunikat „CONFIGURATION_NOT_FOUND”, wróć do tego kroku i dokładnie sprawdź swoją pracę.
Potwierdź zależność Uwierzytelniania Firebase
Potwierdź, że w pliku Podfile
istnieją zależności Uwierzytelniania Firebase.
Plik 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: kliknij dwukrotnie nazwę projektu w widoku drzewa po lewej stronie. Wybierz swoją aplikację w sekcji CELE, kliknij kartę Informacje i rozwiń sekcję Typy adresów URL.
- Kliknij przycisk + i dodaj schemat adresu URL dla odwrotnego identyfikatora klienta. Aby znaleźć tę wartość, otwórz plik konfiguracyjny GoogleService-Info.plist i odszukaj 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ć mniej więcej tak (ale z wartościami specyficznymi dla aplikacji):
Ustawianie identyfikatora klienta na potrzeby Logowania przez Google
Po skonfigurowaniu Firebase możemy użyć identyfikatora klienta, aby skonfigurować Logowanie przez Google w polu „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 modułu obsługi logowania
Jeśli logowanie przez Google przebiegło pomyślnie, użyj konta, aby uwierzytelnić 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 loguj użytkownika. Następnie dodaj detektor do Uwierzytelniania Firebase, aby po zalogowaniu się użytkownik mógł korzystać z aplikacji. I usuń 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 Wylogowywanie się
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)")
}
}
Przetestuj czytanie wiadomości jako zalogowany użytkownik
- Kliknij przycisk Uruchom.
- Powinien natychmiast wyświetlić się ekran logowania. Kliknij przycisk Logowanie przez Google.
- Jeśli wszystko zadziałało poprawnie, powinien wyświetlić się ekran z wiadomościami.
6. Aktywuj bazę danych czasu rzeczywistego
Importowanie wiadomości
W projekcie w konsoli Firebase na pasku nawigacyjnym po lewej stronie wybierz element Baza danych. W rozszerzonym menu bazy danych wybierz Importuj plik JSON. Przejdź do pliku initial_messages.json
w katalogu friendchat, wybierz go i kliknij przycisk Importuj. Spowoduje to zastąpienie wszystkich danych znajdujących się obecnie w bazie danych. Możesz też bezpośrednio edytować bazę danych, używając zielonych + i czerwonych X do dodawania i usuwania elementów.
Po zaimportowaniu bazy danych Twoja baza danych powinna wyglądać tak:
Potwierdź zależność bazy danych Firebase
Sprawdź, czy w bloku zależności pliku Podfile
znajduje się parametr Firebase/Database
.
Plik Podfile
pod 'Firebase/Database'
Synchronizowanie istniejących wiadomości
Dodaj kod, który synchronizuje nowo dodane wiadomości z interfejsem aplikacji.
Kod, który dodasz w tej sekcji:
- Zainicjuj bazę danych Firebase i dodaj detektor, aby obsługiwać zmiany wprowadzone w bazie danych.
- Zaktualizuj aplikację
DataSnapshot
, aby wyświetlały się nowe wiadomości.
Zmodyfikuj parametry „deinit”, „configureDatabase” i „tableView:cellForRow indexPath:” kontrolera FCViewController: Metody; zastąp 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.
- Dodawaj nowe wiadomości bezpośrednio w konsoli Firebase, klikając zielony symbol + obok „wiadomości”. i dodaj obiekt taki jak ten:
- Sprawdź, czy pojawiają się w interfejsie przyjaznego czatu.
7. Wysyłanie wiadomości
Implementowanie funkcji Wyślij wiadomość
Przekazywanie wartości do bazy danych. Gdy dodasz dane do Bazy danych czasu rzeczywistego Firebase za pomocą metody push, zostanie dodany automatyczny identyfikator. Identyfikatory są generowane automatycznie, dzięki czemu nowe wiadomości są dodawane w odpowiedniej kolejności.
Zmodyfikuj parametr „sendMessage:” kontrolera FCViewController ; zastąp 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.
- Napisz wiadomość i kliknij Wyślij. Nowa wiadomość powinna być widoczna w UI aplikacji i w konsoli Firebase.
8. Przechowywanie i odbieranie obrazów
Potwierdź zależność miejsca na dane w Firebase
Sprawdź, czy w bloku zależności instancji Podfile
uwzględniono tag Firebase/Storage
.
Plik Podfile
pod 'Firebase/Storage'
Aktywowanie usługi Firebase Storage w panelu
Otwórz konsolę Firebase i potwierdź, że pamięć masowa została włączona, korzystając z adresu „gs://PROJECTID.appspot.com”. domena
Jeśli widzisz okno aktywacji, kliknij „ROZPOCZNIJ”. aby aktywować ją z regułami domyślnymi.
Skonfiguruj FirebaseStorage
FCViewController.swift,
func configureStorage() {
storageRef = Storage.storage().reference()
}
Odbieranie obrazów w istniejących wiadomościach
Dodaj kod pobierający obrazy z Firebase Storage.
Zmodyfikuj w obiekcie FCViewController wartość „tableView: mobileForRowAt indexPath:” ; zastąp 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. Wyślij wiadomości graficzne
Wdróż przechowywanie i wysyłanie obrazów
Prześlij obraz od użytkownika, a następnie zsynchronizuj adres URL pamięci tego obrazu z bazą danych, aby ten obraz był wysyłany w treści wiadomości.
Zmodyfikuj parametr „imagePickerController: didFinishPickingMediaWithInfo” kontrolera FCViewController: ; zastąp 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 graficznych
- Kliknij przycisk Uruchom.
- Kliknij Zaloguj się, aby przejść do okna wiadomości.
- Kliknij „Dodaj zdjęcie”. aby wybrać zdjęcie. Nowa wiadomość ze zdjęciem powinna być widoczna w interfejsie aplikacji i konsoli Firebase.
10. Gratulacje!
Udało Ci się wykorzystać Firebase, aby łatwo stworzyć aplikację do obsługi czatu w czasie rzeczywistym.
Omówione zagadnienia
- Baza danych czasu rzeczywistego
- Logowanie sfederowane
- Pamięć