1. Visão geral
Este é o codelab do Friendly Chat. Neste codelab, você aprenderá a usar a plataforma Firebase para criar aplicativos iOS. Você vai implementar um cliente de chat e monitorar o desempenho dele usando o Firebase.
O que você aprenderá
- Permita que os usuários façam login.
- Sincronizar dados usando o Firebase Realtime Database.
- Armazenar arquivos binários no Firebase Storage.
O que é necessário
- Xcode
- CocoaPods
- Um dispositivo de teste com iOS 8.0+ ou simulador
Como você usará este tutorial?
Como você classificaria sua experiência com a criação de apps iOS?
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
3. Criar o app inicial
Para criar o app inicial:
- Em uma janela do terminal, navegue até o diretório
ios-starter/swift-starter
no download do exemplo de código - Executar
pod install --repo-update
- Abra o arquivo FriendlyChatSwift.xcworkspace para abrir o projeto no Xcode.
- Clique no botão Executar.
A tela inicial do Friendly Chat será exibida após alguns segundos. A interface será exibida. No entanto, você não poderá fazer login, enviar nem receber mensagens no momento. O app será cancelado com uma exceção até que você conclua a próxima etapa.
4. Criar projeto do Console do Firebase
Criar projeto
No Console do Firebase, selecione Adicionar projeto.
Chame o projeto FriendlyChat
e clique em Criar projeto.
Conectar seu app iOS
- Na tela "Visão geral do projeto" do novo projeto, clique em Adicionar o Firebase ao app para iOS.
- Insira o ID do pacote como "
com.google.firebase.codelab.FriendlyChatSwift
". - Insira o ID da App Store como "
123456
". - Clique em Registrar app.
Adicionar o arquivo GoogleService-Info.plist ao app
Na segunda tela, clique em Fazer o download do GoogleService-Info.plist para fazer o download de um arquivo de configuração que contenha todos os metadados necessários do Firebase para seu app. Copie esse arquivo para o aplicativo e adicione-o ao destino FriendlyChatSwift.
Agora você pode clicar no "x" no canto superior direito do pop-up para fechá-lo, ignorando as etapas 3 e 4, já que você realizará essas etapas aqui.
Importar o módulo do Firebase
Comece verificando se o módulo Firebase
foi importado.
AppDelegate.swift e FCViewController.swift
import Firebase
Configurar o Firebase no AppDelegate
Usar o botão "Configurar" no FirebaseApp na função application:didFinishLaunchingWithOptions para configurar os serviços do Firebase a partir do arquivo .plist.
AppDelegate.swift (link em inglês)
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance().delegate = self
return true
}
5. Identificar usuários
Usar regras para restringir a usuários autenticados
Agora adicionaremos uma regra para exigir autenticação antes de ler ou gravar mensagens. Para isso, adicionamos as seguintes regras ao nosso objeto de dados de mensagens. Na seção "Banco de dados" do Console do Firebase, selecione "Realtime Database" e clique na guia "Regras". Em seguida, atualize as regras para que fiquem assim:
{
"rules": {
"messages": {
".read": "auth != null",
".write": "auth != null"
}
}
}
Para mais informações sobre como isso funciona (incluindo a documentação sobre a variável "auth"), consulte a documentação de segurança do Firebase.
Configurar as APIs do Authentication
Para que seu aplicativo possa acessar as APIs do Firebase Authentication em nome dos usuários, você precisará ativá-las
- Navegue até o Console do Firebase e selecione o projeto
- Selecione Autenticação.
- Selecione a guia Método de login.
- Alterne o botão Google para "ativado" (azul).
- Pressione Salvar na caixa de diálogo exibida.
Se você receber erros posteriormente neste codelab com a mensagem "CONFIGURATION_NOT_FOUND", volte para esta etapa e verifique seu trabalho.
Confirmar a dependência do Firebase Auth
Confirme se as dependências do Firebase Auth existem no arquivo Podfile
.
Podfile (link em inglês)
pod 'Firebase/Auth'
Configure o Info.plist para fazer login no Google.
Você precisa adicionar um esquema de URL personalizado ao seu projeto do XCode.
- Abra a configuração do seu projeto clicando duas vezes no nome dele na visualização em árvore à esquerda. Selecione seu app na seção "DESTINOS". Em seguida, selecione a guia "Informações" e expanda a seção "Tipos de URL".
- Clique no botão + e adicione um esquema de URL para o ID do cliente invertido. Para encontrar esse valor, abra o arquivo de configuração GoogleService-Info.plist e procure a chave REVERSED_CLIENT_ID. Copie o valor da chave e cole-o na caixa Esquemas de URL na página de configuração. Deixe os outros campos em branco.
- Quando concluída, a configuração será parecida com esta, mas com os valores específicos do seu aplicativo:
Definir o clientID para o Login do Google
Depois de configurar o Firebase, podemos usar o clientID para configurar o Login do Google dentro do "didFinishLaunchingWithOptions:" .
AppDelegate.swift (link em inglês)
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
return true
}
Adicionar o gerenciador de login
Depois que o resultado do Login do Google for concluído, use a conta para fazer a autenticação com o Firebase.
AppDelegate.swift (link em inglês)
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
}
}
}
Fazer login do usuário automaticamente. Em seguida, adicione um listener ao Firebase Auth para permitir que o usuário acesse o app após o login. E remova o listener ao deinit.
SignInViewController.swift (link em inglês)
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)
}
}
Sair
Adicionar o método "Sair"
FCViewController.swift (em inglês)
@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)")
}
}
Testar a leitura de mensagens como usuário conectado
- Clique no botão Executar.
- Você será direcionado imediatamente para a tela de login. Toque no botão de Login do Google.
- Se tudo tiver funcionado bem, você será direcionado para a tela de mensagens.
6. Ativar o Realtime Database
Importar mensagens
No projeto do Console do Firebase, selecione o item Database na barra de navegação à esquerda. No menu flutuante do banco de dados, selecione Importar o JSON. Procure o arquivo initial_messages.json
no diretório do Friendlychat, selecione-o e clique no botão Import. Isso substituirá todos os dados atualmente em seu banco de dados. Você também pode editar o banco de dados diretamente, usando o + verde e o x vermelho para adicionar e remover itens.
Depois de importar seu banco de dados, você verá o seguinte:
Confirme a dependência do Firebase Database
No bloco de dependências do arquivo Podfile
, confirme se Firebase/Database
está incluído.
Podfile (link em inglês)
pod 'Firebase/Database'
Sincronizar mensagens existentes
Adicione um código que sincronize as mensagens recém-adicionadas à interface do aplicativo.
O código que você adicionar nesta seção vai:
- Inicialize o banco de dados do Firebase e adicione um listener para lidar com as alterações feitas nele.
- Atualize o
DataSnapshot
para que as novas mensagens apareçam.
Modifique os parâmetros "deinit", "configureDatabase" e "tableView:cellForRow indexPath" do FCViewController: métodos. substitua pelo código definido abaixo:
FCViewController.swift (em inglês)
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
}
Testar a sincronização de mensagens
- Clique no botão Executar.
- Clique no botão Fazer login para começar para acessar a janela de mensagens.
- Adicione novas mensagens diretamente no Console do Firebase clicando no símbolo + verde ao lado de "messages" (mensagens) entrada e adicionando um objeto como o seguinte:
- Confirme se elas aparecem na interface do Friendly-Chat.
7. Enviar mensagens
Implementar o envio de mensagens
Enviar valores para o banco de dados. Quando você usa o método push para adicionar dados ao Firebase Realtime Database, um ID automático é adicionado. Esses IDs gerados automaticamente são sequenciais, o que garante que as novas mensagens sejam adicionadas na ordem correta.
Modifique o "sendMessage:" do seu FCViewController método substitua pelo código definido abaixo:
FCViewController.swift (em inglês)
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)
}
Testar o envio de mensagens
- Clique no botão Executar.
- Clique em Fazer login para acessar a janela de mensagens.
- Digite uma mensagem e clique em "Enviar". A nova mensagem deve estar visível na interface do app e no Console do Firebase.
8. Armazenar e receber imagens
Confirme a dependência do Firebase Storage
No bloco de dependências do Podfile
, confirme se Firebase/Storage
está incluído.
Podfile (link em inglês)
pod 'Firebase/Storage'
Ativar o Firebase Storage no painel
Acesse o console do Firebase e confirme se o Storage está ativado com "gs://PROJECTID.appspot.com" domínio
Se a janela de ativação for exibida, clique em "COMEÇAR" para ativá-lo com as regras padrão.
Configurar o FirebaseStorage
FCViewController.swift (em inglês)
func configureStorage() {
storageRef = Storage.storage().reference()
}
Receber imagens em mensagens atuais
Adicione o código que faz o download de imagens do Firebase Storage.
Modifique a "tableView: cellForRowAt indexPath:" do FCViewController método substitua pelo código definido abaixo:
FCViewController.swift (em inglês)
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. Enviar mensagens com imagens
Implementar o armazenamento e o envio de imagens
Faça upload de uma imagem do usuário e sincronize o URL de armazenamento dessa imagem com o banco de dados para que ela seja enviada dentro da mensagem.
Modifique o "imagePickerController: didFinishPickingMediaWithInfo do do FCViewController: método substitua pelo código definido abaixo:
FCViewController.swift (em inglês)
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])
}
}
}
Testar o envio e o recebimento de mensagens com imagem
- Clique no botão Executar.
- Clique em Fazer login para acessar a janela de mensagens.
- Clique em "Adicionar uma foto" para escolher uma foto. A nova mensagem com a foto deve aparecer na interface do app e no Console do Firebase.
10. Parabéns!
Você usou o Firebase para criar facilmente um aplicativo de chat em tempo real.
O que vimos
- Realtime Database
- Login federado
- Armazenamento