1. Visão Geral
Bem-vindo ao codelab do Friendly Chat. Neste codelab, você aprenderá a usar a plataforma Firebase para criar aplicativos iOS. Você implementará um cliente de chat e monitorará seu desempenho usando o Firebase.
Este codelab também está disponível em Objective-C.
O que você aprenderá
- Permitir que os usuários façam login.
- Sincronize dados usando o Firebase Realtime Database.
- Armazene arquivos binários no Firebase Storage.
O que você precisará
- código X
- CocoaPods
- Um dispositivo de teste com iOS 8.0+ ou simulador
Como você usará este tutorial?
Como classificaria sua experiência com a criação de aplicativos iOS?
2. Obtenha o código de amostra
Clone o repositório GitHub na linha de comando.
$ git clone https://github.com/firebase/codelab-friendlychat-ios
3. Crie o aplicativo inicial
Para criar o aplicativo inicial:
- Em uma janela de terminal, navegue até o
Diretório
ios-starter/swift-starter
do download do código de amostra - Execute
pod install --repo-update
- Abra o arquivo FriendlyChatSwift.xcworkspace para abrir o projeto no Xcode.
- Clique no
botão Executar .
Você deve ver a tela inicial do Friendly Chat após alguns segundos. A IU deve aparecer. No entanto, neste momento você não pode entrar, enviar ou receber mensagens. O aplicativo será interrompido com uma exceção até que você conclua a próxima etapa.
4. Crie um projeto de console do Firebase
Criar projeto
No console do Firebase , selecione Adicionar projeto .
Chame o projeto FriendlyChat
e clique em Create Project .
Conecte seu aplicativo iOS
- Na tela Project Overview do seu novo projeto, clique em Add Firebase to your iOS app .
- Digite o ID do pacote, como "
com.google.firebase.codelab.FriendlyChatSwift
". - Insira o ID da App Store como "
123456
". - Clique em Registrar aplicativo .
Adicione o arquivo GoogleService-Info.plist ao seu aplicativo
Na segunda tela, clique em Download GoogleService-Info.plist para baixar um arquivo de configuração que contém todos os metadados Firebase necessários para seu aplicativo. Copie esse arquivo para seu aplicativo e adicione-o ao destino FriendlyChatSwift .
Agora você pode clicar no "x" no canto superior direito do pop-up para fechá-lo - pulando as etapas 3 e 4 - pois você executará essas etapas aqui.
Importar módulo do Firebase
Comece certificando-se de que o módulo Firebase
seja importado.
AppDelegate.swift , FCViewController.swift
import Firebase
Configurar o Firebase no AppDelegate
Use o método "configure" no FirebaseApp dentro da função application:didFinishLaunchingWithOptions para configurar os serviços subjacentes do Firebase a partir do arquivo .plist.
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance().delegate = self
return true
}
5. Identifique os usuários
Use regras para restringir a usuários autenticados
Agora adicionaremos uma regra para exigir autenticação antes de ler ou escrever qualquer mensagem. Para fazer isso, adicionamos as seguintes regras ao nosso objeto de dados de mensagens. Na seção Banco de dados do Firebase console , 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 obter mais informações sobre como isso funciona (incluindo documentação sobre a variável "auth"), consulte a documentação de segurança do Firebase.
Configurar APIs de autenticação
Antes que seu aplicativo possa acessar as APIs do Firebase Authentication em nome de seus usuários, você terá que habilitá-lo
- Navegue até o console do Firebase e selecione seu projeto
- Selecione Autenticação
- Selecione a guia Método de login
- Mude o Google switch para ativado (azul)
- Pressione Salvar na caixa de diálogo resultante
Se você receber erros posteriormente neste codelab com a mensagem "CONFIGURATION_NOT_FOUND", volte a esta etapa e verifique novamente seu trabalho.
Confirme a dependência do Firebase Auth
Confirme se existem dependências do Firebase Auth no arquivo Podfile
.
Podfile
pod 'Firebase/Auth'
Configure seu Info.plist para login do Google.
Você precisará adicionar um esquema de URL personalizado ao seu projeto XCode.
- Abra a configuração do seu projeto: clique duas vezes no nome do projeto na visualização em árvore à esquerda. Selecione seu aplicativo na seção TARGETS, selecione a guia Info e expanda a seção URL Types.
- Clique no botão + e adicione um esquema de URL para seu ID de 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 dessa chave e cole-o na caixa Esquemas de URL na página de configuração. Deixe os outros campos em branco.
- Quando concluída, sua configuração deve ser semelhante à seguinte (mas com os valores específicos do aplicativo):
Definir clientID para login do Google
Após a configuração do Firebase, podemos usar o clientID para configurar o Login do Google dentro do método "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
}
Adicione o gerenciador de login
Depois que o resultado do login do Google for bem-sucedido, use a conta para autenticar com o 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
}
}
}
Entrar automaticamente o usuário. Em seguida, adicione um ouvinte ao Firebase Auth, para permitir que o usuário entre no aplicativo, após o login bem-sucedido. E remova o ouvinte ao 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)
}
}
Sair
Adicione o método Sair
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)")
}
}
Teste de leitura de mensagens como usuário conectado
- Clique no
botão Executar .
- Você deve ser enviado imediatamente para a tela de login. Toque no botão Login do Google.
- Você deve então ser enviado para a tela de mensagens se tudo funcionou bem.
6. Ative o banco de dados em tempo real
Importar mensagens
Em seu projeto no Firebase console, selecione o item Banco de dados na barra de navegação à esquerda. No menu flutuante do banco de dados, selecione Importar JSON . Navegue até o arquivo initial_messages.json
no diretório friendlychat, selecione-o e clique no botão Importar . 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 deve ficar assim:
Confirme a dependência do banco de dados do Firebase
No bloco de dependências do arquivo Podfile
, confirme se Firebase/Database
está incluído.
Podfile
pod 'Firebase/Database'
Sincronizar mensagens existentes
Adicione o código que sincroniza as mensagens recém-adicionadas à interface do usuário do aplicativo.
O código que você adicionar nesta seção irá:
- Inicialize o banco de dados do Firebase e adicione um ouvinte para lidar com as alterações feitas no banco de dados.
- Atualize o
DataSnapshot
para que novas mensagens sejam exibidas.
Modifique os métodos "deinit", "configureDatabase" e "tableView:cellForRow indexPath:" do seu FCViewController; substitua pelo código definido abaixo:
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
}
Testar Sincronização de Mensagens
- Clique no
botão Executar .
- Clique no botão Entrar para começar para ir para a janela de mensagens.
- Adicione novas mensagens diretamente no Firebase console clicando no símbolo + verde ao lado da entrada "messages" e adicionando um objeto como o seguinte:
- Confirme se eles aparecem na interface do usuário do bate-papo amigável.
7. Enviar mensagens
Implementar Enviar Mensagem
Empurre valores para o banco de dados. Ao usar o método push para adicionar dados ao Firebase Realtime Database, um ID automático será adicionado. Esses IDs gerados automaticamente são sequenciais, o que garante que novas mensagens sejam adicionadas na ordem correta.
Modifique o método "sendMessage:" do seu FCViewController; substitua pelo código definido abaixo:
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)
}
Teste de envio de mensagens
- Clique no
botão Executar .
- Clique em Entrar para ir para a janela de mensagens.
- Digite uma mensagem e clique em enviar. A nova mensagem deve estar visível na interface do usuário do aplicativo e no console do Firebase.
8. Armazene e receba imagens
Confirme a dependência de armazenamento do Firebase
No bloco de dependências do Podfile
, confirme se Firebase/Storage
está incluído.
Podfile
pod 'Firebase/Storage'
Ative o Firebase Storage no painel
Acesse o console do Firebase e confirme se o armazenamento está ativado com o domínio "gs://PROJECTID.appspot.com"
Se você estiver vendo a janela de ativação, clique em "COMEÇAR" para ativá-la com as regras padrão.
Configurar o FirebaseStorage
FCViewController.swift
func configureStorage() {
storageRef = Storage.storage().reference()
}
Receber imagens em mensagens existentes
Adicione o código que baixa imagens do Firebase Storage.
Modifique o método "tableView: cellForRowAt indexPath:" do seu FCViewController; substitua pelo código definido abaixo:
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. Envie mensagens de imagem
Implementar armazenar e enviar imagens
Carregue uma imagem do usuário e, em seguida, sincronize a URL de armazenamento dessa imagem com o banco de dados para que essa imagem seja enviada dentro da mensagem.
Modifique o método "imagePickerController: didFinishPickingMediaWithInfo:" do seu FCViewController; substitua pelo código definido abaixo:
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])
}
}
}
Teste de envio e recebimento de mensagens de imagem
- Clique no
botão Executar .
- Clique em Entrar para ir para a janela de mensagens.
- Clique no ícone "adicionar uma foto" para escolher uma foto. A nova mensagem com a foto deve estar visível na interface do usuário do aplicativo e no console do Firebase.
10. Parabéns!
Você usou o Firebase para criar facilmente um aplicativo de bate-papo em tempo real.
O que cobrimos
- banco de dados em tempo real
- Login federado
- Armazenar