Armazenando dados no Firebase com Android — Storage

Quem falou que aplicações simples precisam de um super backend?

Daivid Vasconcelos Leal
Jul 15 · 5 min read
Image for post
Image for post

Já falamos aqui no Blog sobre as formas de salvar dados no Firebase com o Cloud Firestore. Se você ainda não viu, clique aqui para ver a estrutura do projeto que estamos usando como exemplo. Hoje, vamos dar continuidade a este conteúdo, mostrando como salvar arquivos com o Storage.

E para que usamos o Storage? Basicamente, para armazenamento de arquivos, sejam esses arquivos imagens, vídeos, áudio, etc. Quando existe a necessidade de salvar arquivos, temos como opção o storage, que funciona da seguinte forma:

O usuário quer salvar um determinado tipo de arquivo. O desenvolvedor, por sua vez, vai utilizar o SDK do Firebase para realizar o upload, download ou delete do arquivo. Nos casos de upload o Firebase já retorna uma referência do arquivo que será utilizado, e com essa referência podemos fazer as operações citadas anteriormente.

Além de fazer as operações, cada usuário pode ter uma relação de arquivos que pode acessar, ou seja, além de nos oferecer as operações que foram citadas acima, temos a possibilidade também de deixar públicas essas operações, para quaisquer usuários, para um grupo ou ainda para um único usuário do nosso sistema.

Abaixo podemos ver como funcionam as regras e onde nosso servidor fica localizado.

Image for post
Image for post
Print screen da primeira tela apresentada pelo Firebase ao clicar em “Primeiros passos”. firebase.google.com

Na imagem acima, a regra criada é para acesso aos arquivos, tendo em vista que o usuário tem que estar com uma conta logada no Firebase.

Image for post
Image for post
firebase.google.com

Podemos ver que o servidor fica localizado nos Estados Unidos neste exemplo. Em outros planos pagos, podemos alterar a localização desse servidor, influenciando no tempo de resposta das solicitações.

Se necessário, podemos criar tipos de regras diferentes com o seguinte payload:

{
"uid": "",
"token": {
"sub": "",
"aud": "app-999999",
"email": "",
"email_verified": false,
"phone_number": "",
"name": "",
"firebase": {
"sign_in_provider": "google.com"
}
}
}

Com esse payload, você pode criar várias formas de acessar os arquivos, no painel do Storage em regras → editar regras → ativar autenticação.

Bem, antes de qualquer coisa precisamos definir a lib que vamos utilizar para ter acesso às funções do Storage.

implementation "com.google.firebase:firebase-storage:19.1.0"

Após o sync, podemos utilizar as bibliotecas do Storage e fazer as operações desejadas com os arquivos.

Para usar a instância do FirebaseStorage só precisamos utilizar a função estática disponível:

FirebaseStorage.getInstance()

Obs: importante lembrar que devemos inicializar o FirebaseApp no aplicativo para que não ocorra nenhum erro ao tentar utilizar as funções da instância do Firebase no seu projeto. Para isso utilize, de preferência na sua classe de application, o seguinte trecho de código:

FirebaseApp.initializeApp(context)

Upload

A partir desta seção tenha em mente a seguinte classe, com a implementação dos métodos descritos em sequência como parte do escopo dela:

class ServiceFirebaseStorage(
private val firebaseStorage: FirebaseStorage
){ }

No trecho de código a seguir, para fazer o upload por meio de uma Uri do arquivo só precisamos chamar a função putFile, passando a Uri do arquivo desejado. Veja o código:

fun uploadPhoto(
uriFile: Uri,
fileName: String,
success: () -> Unit,
error: (Exception?) -> Unit
) {
val ref = firebaseStorage.getReference(fileName)
ref.putFile(uriFile).addOnCompleteListener{
success()
}.addOnFailureListener{
error(it)
}
}

No trecho de código acima podemos perceber que só precisamos criar uma referência para o arquivo no Storage do Firebase, que pode ser o nome específico do arquivo que se deseja fazer o upload, como por exemplo “image.jpg”, e podemos também perceber que com isso só fazemos o upload do arquivo desejado. Mas como podemos recuperá-lo depois? Como acessar uma url para o arquivo desejado?

Bem, neste caso fazemos uma simples modificação do código e acessamos outros métodos já concedidos pela biblioteca do Storage. Com isso já é possível ter acesso à url de um arquivo e carregá-lo onde for necessário. No exemplo de uma imagem poderíamos utilizar o Picasso ou o FirebaseUI para carregar em um ImageView. Vejamos o código a seguir com a modificação:

fun uploadPhoto(
uriFile: Uri,
fileName: String,
success: (uri: Uri) -> Unit,
error: (Exception?) -> Unit
) {
val ref = firebaseStorage.getReference(fileName)
val task = ref.putFile(uriFile)
this.generateUrlDownload(ref, task, success, error)
}

private fun generateUrlDownload(
reference: StorageReference,
task: StorageTask<UploadTask.TaskSnapshot>,
success: (uri: Uri) -> Unit,
error: (Exception?) -> Unit
) {
task.continueWithTask { taskExecuted ->
if
(taskExecuted.isSuccessful) {
reference.downloadUrl
} else {
taskExecuted.exception?.let {
throw it
}
}
}.addOnCompleteListener { task ->
if
(task.isSuccessful) {
task.result?.let(success) ?: run {
error(Throwable("Unknown Error"))
}
} else {
error(Throwable("Unknown Error!"))
}
}.addOnFailureListener(error)
}

No exemplo acima salvamos a chamada da função putFile em uma variável para que essa função seja executada, e após a sua execução seja possível recuperar o a url de download do arquivo anteriormente salvo.

É possível ver que, ao final da execução, a função retorne a url da imagem. Utilizando o “observador” addOnCompleteListener podemos ter acesso direto a essa url e retorná-la para que seja salva como SharedPrefences ou em algum banco de dados interno ou externo à nossa aplicação.

Além da possibilidade de fazer o upload, o Firebase permite você cancelar, pausar ou retomar o upload do seu arquivo por meio das funções task.pause(), task.cancel() e task.resume().

Download

Agora vejamos como fazer o download de um arquivo. Para isso é necessário ter a referência do arquivo, a referência do firebase e um arquivo temporário no qual será salvo o dado que foi realizado o download do Storage. Então, repare a pequena mudança no código a seguir:

fun downloadFile(
fileName: String,
fileType: String,
fileExt: String,
success: (file: File) -> Unit,
error: (Exception?) -> Unit
) {
val ref = firebaseStorage.reference.child(fileName)
val saveFileInto = File.createTempFile(fileType, fileExt)
ref.getFile(saveFileInto).addOnSuccessListener {
success(saveFileInto)
}.addOnFailureListener(error)
}

Veja no exemplo acima que temos primeiro reference, como referência do Firebase, e logo a chamada do método child para a busca de um arquivo específico. Logo depois temos um arquivo temporário definido como saveFileInto, criado para salvar o arquivo do qual foi feito o download.

Delete

Por fim, porém não menos importante veremos aqui como deletar um arquivo. A função de delete já está pronta e, como no caso do downlaod, só é necessário definir qual arquivo será deletado dando a referência do Firebase e do arquivo por meio do nome.

fun deleteFile(
fileDir: String,
success: (task: Task<Void>) -> Unit,
error: (java.lang.Exception?) -> Unit
) {
val ref = firebaseStorage.reference.child(fileDir)
ref.delete().addOnFailureListener(error)
.addOnCompleteListener(success)
}

Conclusão

Bem, com essa solução proposta pelo Firebase podemos simplesmente esquecer a criação de serviços complexos de FTP para armazenamento de arquivos. Como dito anteriormente, o Firebase é uma ótima solução para serviços simples, mas pense antes de sair mudando tudo para essa proposta. Às vezes é preciso usar outros serviços que ainda não estão incluídos nessa ferramenta.

A gente continua com RealTime Database nos próximos capítulos… Fique atento(a)! Quer fazer parte de um time que está trocando conhecimento todo o tempo? Saiba mais sobre a Concrete aqui e deixe o seu currículo. Até a próxima!

Concrete

Nós desenvolvemos produtos digitais com inovação, agilidade…

Daivid Vasconcelos Leal

Written by

Currently Master Student at UFRPE in Applied Computer Science with the field Quantum Computer, and Android Developer at Concrete Solutions.

Concrete

Concrete

Nós desenvolvemos produtos digitais com inovação, agilidade e excelentes práticas, para que o mercado brasileiro e latino-americano acompanhe a velocidade do mercado digital mundial.

Daivid Vasconcelos Leal

Written by

Currently Master Student at UFRPE in Applied Computer Science with the field Quantum Computer, and Android Developer at Concrete Solutions.

Concrete

Concrete

Nós desenvolvemos produtos digitais com inovação, agilidade e excelentes práticas, para que o mercado brasileiro e latino-americano acompanhe a velocidade do mercado digital mundial.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store