1. Visão geral
Este é o codelab FriendlyChat para iOS. Nele, você vai aprender a criar um aplicativo de chat para iOS em tempo real com todos os recursos usando o Firebase e recursos modernos do Swift, como SwiftUI, Swift Concurrency e o framework Observation.
O que você vai aprender
- Gerenciar o estado com o framework Observation moderno (
@Observable). - Autenticar usuários usando o Firebase Authentication.
- Sincronizar mensagens de chat em tempo real usando o Cloud Firestore.
- Armazenar e disponibilizar imagens usando o Cloud Storage para Firebase.
- Acessar as APIs do Firebase usando os recursos modernos do Swift Concurrency.
O que é necessário
- A versão mais recente do Xcode
- Um simulador de iOS ou um dispositivo de teste físico
- Uma Conta do Google para criar e gerenciar seu projeto do Firebase
2. Acessar o exemplo de código
Clone o repositório do GitHub na linha de comando:
$ git clone https://github.com/firebase/codelab-friendlychat-ios
O repositório codelab-friendlychat-ios contém vários projetos de exemplo:
ios-starter/swift-starter: o projeto inicial do Xcode que contém o esqueleto de layout do SwiftUI e comentáriosTODOem que você vai implementar os recursos do app com o Firebase.ios/swift: o projeto concluído do Xcode com o aplicativo de exemplo finalizado.
3. Criar o app inicial
Crie e execute o aplicativo inicial para se familiarizar com a interface do usuário:
- No Finder ou no Terminal, acesse o diretório
ios-starter/swift-starter. - Clique duas vezes em
FriendlyChatSwift.xcodeprojpara abrir o projeto no Xcode. - O Xcode resolve automaticamente as dependências do Gerenciador de pacotes do Swift em segundo plano (fazendo o download do
firebase-ios-sdkv12 ou mais recente do GitHub). - Selecione um simulador de iOS (por exemplo, iPhone 17 Pro) e clique no botão Executar (cmd + R).
Depois de alguns segundos, a tela de login do FriendlyChat vai aparecer. Nesse momento, os botões de login e os feeds de mensagens são marcadores de posição. Você vai conectar o Firebase ao app nas próximas etapas.
4. Configurar um projeto do Firebase
Criar um novo projeto do Firebase
- Faça login no console do Firebase usando sua Conta do Google.
- Clique no botão para criar um novo projeto e insira um nome (por exemplo,
FriendlyChat).
- Clique em Continuar.
- Se solicitado, leia e aceite os Termos do Firebase e clique em Continuar.
- (Opcional) Ative a assistência de IA no console do Firebase (chamada de "Gemini no Firebase").
- Neste codelab, você não precisa do Google Analytics. Portanto, desative a opção do Google Analytics.
- Clique em Criar projeto, aguarde o provisionamento do projeto e clique em Continuar.
Fazer upgrade do plano de preços do Firebase
Para usar o Cloud Storage para Firebase, seu projeto do Firebase precisa estar no plano de preços de pagamento por uso (Blaze), o que significa que ele está vinculado a uma conta do Cloud Billing.
- Uma conta do Cloud Billing exige uma forma de pagamento, como cartão de crédito.
- Se você ainda não conhece o Firebase e o Google Cloud, confira se tem qualificação para receber um crédito de US$300 e uma conta do Cloud Billing de teste sem custo financeiro.
- Se você estiver fazendo este codelab como parte de um evento, pergunte ao organizador se há créditos do Cloud disponíveis.
Para fazer upgrade do seu projeto para o plano Blaze, siga estas etapas:
- No console do Firebase, selecione Fazer upgrade do seu plano.
- Selecione o plano Blaze. Siga as instruções na tela para vincular uma conta do Cloud Billing ao seu projeto.
Se você precisou criar uma conta do Cloud Billing como parte desse upgrade, talvez seja necessário voltar para o fluxo de upgrade no console do Firebase para concluir o upgrade.
Conectar seu app iOS
- Na tela de visão geral do projeto, clique no ícone iOS para iniciar o fluxo de trabalho de configuração do app.
- Insira o ID do pacote:
com.google.firebase.codelab.FriendlyChatSwift - Clique em Registrar app.
Adicionar GoogleService-Info.plist ao seu projeto do Xcode
- Clique em Fazer o download do GoogleService-Info.plist para salvar o arquivo de configuração.
- No Xcode, arraste o arquivo
GoogleService-Info.plistbaixado para o grupo principalFriendlyChatSwiftno navegador do projeto. - Quando solicitado, verifique se a opção Copiar itens, se necessário está marcada e se o destino
FriendlyChatSwiftestá selecionado. Em seguida, clique em Concluir.
Configurar o Firebase em FriendlyChatSwiftApp.swift
Por fim, inicialize o Firebase com a configuração do projeto quando o aplicativo SwiftUI for iniciado. Abra FriendlyChatSwiftApp.swift e substitua os marcadores de posição TODO por import FirebaseCore e FirebaseApp.configure():
import SwiftUI
import FirebaseCore
@main
struct FriendlyChatSwiftApp: App {
init() {
FirebaseApp.configure()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
5. Autenticar usuários
Configurar a autenticação no console do Firebase
Antes de autenticar usuários, é necessário ativar o provedor de autenticação de sua escolha no console do Firebase. Este tutorial usa a autenticação por e-mail/senha:
- No console do Firebase, acesse Segurança > Autenticação e clique em Comece aqui.
- Selecione a guia Método de login.
- Clique em E-mail/Senha, clique no botão Ativar e em Salvar.
Proteger o Cloud Firestore com regras de autenticação
Em seguida, exija que os usuários sejam autenticados antes de ler ou gravar mensagens:
- No console do Firebase, acesse Bancos de dados e armazenamento > Banco de dados do Firestore e clique em Criar banco de dados.
- Selecione um local e clique em Próxima.
- Selecione Iniciar no modo de teste e clique em Criar.
- Selecione a guia Regras e atualize as regras de segurança para:
Essas regras permitem que qualquer usuário autenticado leia ou grave mensagens no banco de dados, o que é adequado para fins de aprendizado. Saiba mais sobre as regras de segurança na documentação.rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /messages/{messageId} { allow read, write: if request.auth != null; } } } - Clique em Publicar.
Observar o estado de autenticação em UserViewModel.swift
No SwiftUI, a observação reativa do estado do Firebase Auth garante que a interface do usuário alterne sem problemas entre a tela de login e a interface de chat.
Abra ViewModels/UserViewModel.swift e substitua o TODO em init() para observar as mudanças de estado de autenticação usando a AsyncSequence authStateChanges:
init() {
authTask = Task {
for await user in Auth.auth().authStateChanges {
self.user = user
}
}
}
Implementar login, inscrição e logout com o Swift Concurrency
Em UserViewModel.swift, substitua os comentários TODO restantes por métodos de autenticação async/await modernos:
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)
}
}
Testar a autenticação do usuário
- Clique no botão Executar no Xcode.
- No simulador de app, clique em Inscrever-se, insira um nome de exibição, e-mail e senha e toque em INSCREVER-SE.
- Você será autenticado automaticamente e direcionado para a tela de mensagens vazia.
6. Ler do Cloud Firestore
Adicionar mensagens de exemplo no console do Firebase
Preencha o banco de dados com mensagens de exemplo:
- No console do Firebase, acesse Banco de dados do Firestore e selecione a guia Dados.
- Clique em Iniciar coleção.
- Insira
messagespara o ID da coleção e clique em Próxima. - Deixe o ID do documento definido para geração automática (ou clique em ID automático).
- Adicione os seguintes campos ao documento:
text(tipo:string, valor:Hello)displayName(tipo:string, valor:anonymous)
- Clique em Salvar.
- Se quiser, clique em Adicionar documento para adicionar mais mensagens de exemplo.
Sincronizar mensagens em FriendlyMessageViewModel.swift
No SwiftUI, um modelo @Observable gera atualizações declarativas da interface do usuário. Abra ViewModels/FriendlyMessageViewModel.swift e implemente startListening() e stopListening() usando a 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()
}
Como o SwiftUI renderiza e rola automaticamente as mensagens
Em Views/ContentView.swift, observe como ScrollViewReader e LazyVStack renderizam bolhas de chat e rolam automaticamente para a mensagem mais recente sempre que messages.count muda:
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)
}
}
}
}
Ao vincular o estado do banco de dados diretamente ao estado da interface do usuário pelo modelo de visualização, o SwiftUI permite que o código do app mapeie as transições para animações de maneira limpa. Na próxima etapa, você vai gravar dados no banco de dados do app para observar essa animação em ação.
7. Enviar mensagens
Implementar sendMessage com o Swift Concurrency
Quando você adiciona um documento a uma coleção usando addDocument(), o Cloud Firestore gera um ID exclusivo para cada mensagem de chat.
Em ViewModels/FriendlyMessageViewModel.swift, substitua o TODO em sendMessage(text:imageUrl:) por um método 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)
}
Teste o envio de mensagens
- Clique no botão Executar no Xcode.
- Faça login em sua conta.
- Digite uma mensagem no campo de texto na parte de baixo e toque no ícone Enviar.
- Observe a mensagem aparecer instantaneamente no simulador.
8. Armazenar e receber imagens
Configurar o Cloud Storage para Firebase
- No console do Firebase, acesse Bancos de dados e armazenamento > Storage e clique em Comece aqui.
- Selecione Iniciar no modo de teste e clique em Próxima.
- Aceite o local de armazenamento padrão e clique em Concluído.
Seleção de imagens nativas com PhotosPicker do SwiftUI
O SwiftUI moderno (iOS 16 ou mais recente) oferece seleção de fotos nativa via PhotosPicker de import PhotosUI. Não são necessárias pontes de delegação do UIKit nem wrappers UIImagePickerController.
Em Views/FooterView.swift, observe como PhotosPicker vincula as imagens selecionadas:
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)
}
}
}
Implementar o upload de imagens
Quando uma foto é selecionada, faça o upload dos dados da imagem para o Cloud Storage e salve o URL de download público no Cloud Firestore.
Em Views/FooterView.swift, substitua o TODO em 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)")
}
}
Compartilhamento de imagens com o Cloud Storage
Em Views/FriendlyMessageImageView.swift, os URLs de imagem são carregados de forma assíncrona usando o Swift Concurrency e o SDK do Cloud Storage:
- Os URLs de download HTTP/HTTPS padrão são recuperados de forma assíncrona via
URLSession. - Os URLs do Google Cloud Storage (por exemplo,
gs://...) são buscados usandoStorage.storage().reference(forURL:).
Testar mensagens de imagem
- Clique no botão Executar no Xcode.
- Faça login em sua conta.
- Toque no ícone de foto, escolha uma imagem da biblioteca e observe o upload e a exibição no chat.
9. Conclusão
Parabéns! Você criou um aplicativo de chat para iOS em tempo real usando o Swift e o Firebase.
O que você aprendeu
- Integração do Gerenciador de pacotes do Swift (SPM) do Xcode para
firebase-ios-sdk. - Layouts declarativos do SwiftUI ,
PhotosPickere rolagem automáticaScrollViewReader. - Swift Concurrency (
async/await) em autenticação, Cloud Firestore e Cloud Storage. - Autenticação anônima e por e-mail/senha com observação de estado reativo.
- Cloud Firestore : detecção de snapshots em tempo real e gravações de ID automatizadas.
- Cloud Storage para Firebase : uploads binários e URLs de download públicos.