1. Panoramica
Ti diamo il benvenuto nel codelab Friendly Chat. In questo codelab imparerai a utilizzare la piattaforma Firebase per creare applicazioni per iOS. Implementerai un client di chat e ne monitorerai il rendimento utilizzando Firebase.
Cosa imparerai a fare
- Consenti agli utenti di accedere.
- Sincronizza i dati utilizzando Firebase Realtime Database.
- Archiviare file binari in Firebase Storage.
Che cosa ti serve
- Xcode
- CocoaPods
- Un dispositivo di test con iOS 8.0 o versioni successive o un simulatore
Come utilizzerai questo tutorial?
Come valuteresti la tua esperienza di creazione di app per iOS?
2. recupera il codice campione
Clona il repository GitHub dalla riga di comando.
$ git clone https://github.com/firebase/codelab-friendlychat-ios
3. Crea l'app iniziale
Per creare l'app iniziale:
- In una finestra del terminale, vai alla directory
ios-starter/swift-starter
dal download del codice campione. - Esegui
pod install --repo-update
- Apri il file FriendlyChatSwift.xcworkspace per aprire il progetto in Xcode.
- Fai clic sul pulsante
Esegui.
Dopo qualche secondo dovrebbe apparire la schermata Home di Friendly Chat. Dovrebbe apparire l'interfaccia utente. Tuttavia, a questo punto non puoi accedere, inviare o ricevere messaggi. L'app verrà interrotta con un'eccezione finché non completi il passaggio successivo.
4. Configura un progetto Firebase
Crea un nuovo progetto Firebase
- Accedi alla console Firebase utilizzando il tuo Account Google.
- Fai clic sul pulsante per creare un nuovo progetto, quindi inserisci un nome per il progetto (ad esempio
FriendlyChat
).
- Fai clic su Continua.
- Se richiesto, leggi e accetta i termini di Firebase, quindi fai clic su Continua.
- (Facoltativo) Attiva l'assistenza AI nella console Firebase (denominata "Gemini in Firebase").
- Per questo codelab non hai bisogno di Google Analytics, quindi disattiva l'opzione Google Analytics.
- Fai clic su Crea progetto, attendi il provisioning del progetto, poi fai clic su Continua.
Esegui l'upgrade del piano tariffario Firebase
Per utilizzare Cloud Storage for Firebase, il tuo progetto Firebase deve essere incluso nel piano tariffario con pagamento a consumo (Blaze), il che significa che è collegato a un account di fatturazione Cloud.
- Un account di fatturazione Cloud richiede un metodo di pagamento, ad esempio una carta di credito.
- Se non hai mai utilizzato Firebase e Google Cloud, verifica se hai diritto a un credito di 300$e a un account Cloud Billing di prova senza costi.
- Se stai svolgendo questo codelab nell'ambito di un evento, chiedi all'organizzatore se sono disponibili crediti Cloud.
Per eseguire l'upgrade del progetto al piano Blaze:
- Nella console Firebase, seleziona l'opzione per eseguire l'upgrade del piano.
- Seleziona il piano Blaze. Segui le istruzioni sullo schermo per collegare un account di fatturazione Cloud al tuo progetto.
Se hai dovuto creare un account di fatturazione Cloud nell'ambito di questo upgrade, potresti dover tornare al flusso di upgrade nella console Firebase per completarlo.
Collegare l'app per iOS
- Nella schermata Panoramica del progetto del nuovo progetto, fai clic su Aggiungi Firebase alla tua app per iOS.
- Inserisci l'ID bundle come "
com.google.firebase.codelab.FriendlyChatSwift
". - Inserisci l'ID App Store come "
123456
". - Fai clic su Registra app.
Aggiungere il file GoogleService-Info.plist all'app
Nella seconda schermata, fai clic su Scarica GoogleService-Info.plist per scaricare un file di configurazione che contiene tutti i metadati Firebase necessari per la tua app. Copia il file nell'applicazione e aggiungilo al target FriendlyChatSwift.
Ora puoi fare clic sulla "x" nell'angolo in alto a destra del popup per chiuderlo, saltando i passaggi 3 e 4, perché li eseguirai qui.
Importa il modulo Firebase
Inizia assicurandoti che il modulo Firebase
sia importato.
AppDelegate.swift, FCViewController.swift
import Firebase
Configura Firebase in AppDelegate
Utilizza il metodo "configure" in FirebaseApp all'interno della funzione application:didFinishLaunchingWithOptions per configurare i servizi Firebase sottostanti dal file .plist.
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance().delegate = self
return true
}
5. Identificare gli utenti
Utilizzare le regole per limitare l'accesso agli utenti autenticati
Ora aggiungeremo una regola per richiedere l'autenticazione prima di leggere o scrivere qualsiasi messaggio. A questo scopo, aggiungiamo le seguenti regole all'oggetto dati dei messaggi. Nella sezione Database della console Firebase, seleziona Realtime Database e poi fai clic sulla scheda Regole. Poi aggiorna le regole in modo che abbiano questo aspetto:
{
"rules": {
"messages": {
".read": "auth != null",
".write": "auth != null"
}
}
}
Per ulteriori informazioni su come funziona (inclusa la documentazione sulla variabile "auth"), consulta la documentazione sulla sicurezza di Firebase.
Configura le API di autenticazione
Prima che la tua applicazione possa accedere alle API Firebase Authentication per conto dei tuoi utenti, devi abilitarla
- Vai alla console Firebase e seleziona il tuo progetto.
- Seleziona Autenticazione.
- Seleziona la scheda Metodo di accesso.
- Attiva l'opzione Google (blu).
- Fai clic su Salva nella finestra di dialogo risultante.
Se in un secondo momento in questo codelab ricevi errori con il messaggio "CONFIGURATION_NOT_FOUND", torna a questo passaggio e ricontrolla il tuo lavoro.
Conferma la dipendenza di Firebase Auth
Verifica che le dipendenze di Firebase Auth esistano nel file Podfile
.
Podfile
pod 'Firebase/Auth'
Configura il file Info.plist per Accedi con Google.
Dovrai aggiungere uno schema URL personalizzato al tuo progetto XCode.
- Apri la configurazione del progetto: fai doppio clic sul nome del progetto nella visualizzazione ad albero a sinistra. Seleziona l'app dalla sezione TARGET, poi seleziona la scheda Informazioni ed espandi la sezione Tipi di URL.
- Fai clic sul pulsante + e aggiungi uno schema URL per l'ID client invertito. Per trovare questo valore, apri il file di configurazione GoogleService-Info.plist e cerca la chiave REVERSED_CLIENT_ID. Copia il valore della chiave e incollalo nella casella Schemi URL della pagina di configurazione. Lascia vuoti gli altri campi.
- Al termine, la configurazione dovrebbe essere simile alla seguente (ma con i valori specifici dell'applicazione):
Imposta clientID per Accedi con Google
Una volta configurato Firebase, possiamo utilizzare il clientID per configurare l'accesso con Google all'interno del metodo "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
}
Aggiungere il gestore di accesso
Una volta che l'accesso con Google è andato a buon fine, utilizza l'account per l'autenticazione con 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
}
}
}
Consentire l'accesso automatico all'utente. Poi aggiungi un listener a Firebase Auth per consentire all'utente di accedere all'app dopo l'accesso. e rimuovi il listener su 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)
}
}
Esci
Aggiungere il metodo di disconnessione
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)")
}
}
Testare la lettura dei messaggi come utente che ha eseguito l'accesso
- Fai clic sul pulsante
Esegui.
- Dovresti essere reindirizzato immediatamente alla schermata di accesso. Tocca il pulsante Accedi con Google.
- Se tutto ha funzionato correttamente, dovresti essere reindirizzato alla schermata di messaggistica.
6. Attivare Realtime Database
Importare i messaggi
Nel tuo progetto nella console Firebase, seleziona l'elemento Database nella barra di navigazione a sinistra. Nel menu extra del database, seleziona Importa JSON. Vai al file initial_messages.json
nella directory friendlychat, selezionalo e fai clic sul pulsante Importa. Verranno sostituiti tutti i dati attualmente presenti nel database. Puoi anche modificare direttamente il database utilizzando il segno + verde e la x rossa per aggiungere e rimuovere elementi.
Dopo l'importazione, il database dovrebbe avere il seguente aspetto:
Conferma la dipendenza dal database Firebase
Nel blocco delle dipendenze del file Podfile
, verifica che Firebase/Database
sia incluso.
Podfile
pod 'Firebase/Database'
Sincronizzare i messaggi esistenti
Aggiungi il codice che sincronizza i messaggi appena aggiunti all'interfaccia utente dell'app.
Il codice che aggiungi in questa sezione:
- Inizializza il database Firebase e aggiungi un listener per gestire le modifiche apportate al database.
- Aggiorna
DataSnapshot
in modo che vengano visualizzati i nuovi messaggi.
Modifica i metodi "deinit", "configureDatabase" e "tableView:cellForRow indexPath:" di FCViewController; sostituiscili con il codice definito di seguito:
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
}
Testare la sincronizzazione dei messaggi
- Fai clic sul pulsante
Esegui.
- Fai clic sul pulsante Accedi per iniziare per andare alla finestra dei messaggi.
- Aggiungi nuovi messaggi direttamente nella console Firebase facendo clic sul simbolo + verde accanto alla voce "messaggi" e aggiungendo un oggetto come il seguente:
- Verifica che vengano visualizzati nell'interfaccia utente di Friendly-Chat.
7. Invio messaggi
Implementare Invia messaggio
Effettua il push dei valori nel database. Quando utilizzi il metodo push per aggiungere dati a Firebase Realtime Database, viene aggiunto un ID automatico. Questi ID generati automaticamente sono sequenziali, il che garantisce che i nuovi messaggi vengano aggiunti nell'ordine corretto.
Modifica il metodo "sendMessage:" di FCViewController; sostituiscilo con il codice definito di seguito:
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)
}
Testare l'invio di messaggi
- Fai clic sul pulsante
Esegui.
- Fai clic su Accedi per andare alla finestra dei messaggi.
- Digita un messaggio e premi Invia. Il nuovo messaggio dovrebbe essere visibile nell'UI dell'app e nella console Firebase.
8. Archiviare e ricevere immagini
Conferma la dipendenza di Firebase Storage
Nel blocco delle dipendenze di Podfile
, verifica che Firebase/Storage
sia incluso.
Podfile
pod 'Firebase/Storage'
Configurare Cloud Storage for Firebase
Ecco come configurare Cloud Storage for Firebase nel tuo progetto Firebase:
- Nel riquadro a sinistra della console Firebase, espandi Build e seleziona Storage.
- Fai clic su Inizia.
- Seleziona una posizione per il bucket di archiviazione predefinito.
I bucket inUS-WEST1
,US-CENTRAL1
eUS-EAST1
possono usufruire del livello"Sempre senza costi" per Google Cloud Storage. I bucket in tutte le altre località seguono i prezzi e l'utilizzo di Google Cloud Storage. - Fai clic su Avvia in modalità di test. Leggi l'esclusione di responsabilità relativa alle regole di sicurezza.
Più avanti in questo codelab, aggiungerai regole di sicurezza per proteggere i tuoi dati. Nondistribuire o esporre pubblicamente un'app senza aggiungere regole di sicurezza per il bucket Storage. - Fai clic su Crea.
Configura FirebaseStorage
FCViewController.swift
func configureStorage() {
storageRef = Storage.storage().reference()
}
Ricevere immagini nei messaggi esistenti
Aggiungi il codice che scarica le immagini da Firebase Storage.
Modifica il metodo "tableView: cellForRowAt indexPath:" di FCViewController; sostituiscilo con il codice definito di seguito:
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. Invio di messaggi con immagini
Implementare Store and Send Images
Carica un'immagine dall'utente, quindi sincronizza l'URL di archiviazione di questa immagine con il database in modo che venga inviata all'interno del messaggio.
Modifica il metodo "imagePickerController: didFinishPickingMediaWithInfo:" di FCViewController; sostituiscilo con il codice definito di seguito:
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])
}
}
}
Testare l'invio e la ricezione di messaggi illustrati
- Fai clic sul pulsante
Esegui.
- Fai clic su Accedi per andare alla finestra dei messaggi.
- Fai clic sull'icona "Aggiungi una foto" per selezionarne una. Il nuovo messaggio con la foto dovrebbe essere visibile nell'interfaccia utente dell'app e nella console Firebase.
10. Complimenti!
Hai utilizzato Firebase per creare facilmente un'applicazione di chat in tempo reale.
Argomenti trattati
- Realtime Database
- Accesso federato
- Archiviazione