Com o Cloud Storage for Firebase, é possível fazer upload de arquivos com rapidez e facilidade para um bucket do Cloud Storage fornecido e gerenciado pelo Firebase.
Fazer upload de arquivos
Para fazer upload de um arquivo para o Cloud Storage, primeiro crie uma referência ao caminho completo do arquivo, incluindo o nome dele.
Kotlin+KTX
// Create a storage reference from our app val storageRef = storage.reference // Create a reference to "mountains.jpg" val mountainsRef = storageRef.child("mountains.jpg") // Create a reference to 'images/mountains.jpg' val mountainImagesRef = storageRef.child("images/mountains.jpg") // While the file names are the same, the references point to different files mountainsRef.name == mountainImagesRef.name // true mountainsRef.path == mountainImagesRef.path // false
Java
// Create a storage reference from our app StorageReference storageRef = storage.getReference(); // Create a reference to "mountains.jpg" StorageReference mountainsRef = storageRef.child("mountains.jpg"); // Create a reference to 'images/mountains.jpg' StorageReference mountainImagesRef = storageRef.child("images/mountains.jpg"); // While the file names are the same, the references point to different files mountainsRef.getName().equals(mountainImagesRef.getName()); // true mountainsRef.getPath().equals(mountainImagesRef.getPath()); // false
Depois de criar uma referência apropriada, chame os métodos putBytes()
, putFile()
ou putStream()
para fazer upload do arquivo para o Cloud Storage.
Não é possível fazer upload de dados com uma referência à raiz do bucket do Cloud Storage. Sua referência precisa apontar para um URL filho.
Fazer upload de dados na memória
O método putBytes()
é a maneira mais simples de fazer upload de um arquivo para o Cloud Storage. putBytes()
recebe um byte[]
e retorna um UploadTask
que pode ser usado para gerenciar e monitorar o status do upload.
Kotlin+KTX
// Get the data from an ImageView as bytes imageView.isDrawingCacheEnabled = true imageView.buildDrawingCache() val bitmap = (imageView.drawable as BitmapDrawable).bitmap val baos = ByteArrayOutputStream() bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos) val data = baos.toByteArray() var uploadTask = mountainsRef.putBytes(data) uploadTask.addOnFailureListener { // Handle unsuccessful uploads }.addOnSuccessListener { taskSnapshot -> // taskSnapshot.metadata contains file metadata such as size, content-type, etc. // ... }
Java
// Get the data from an ImageView as bytes imageView.setDrawingCacheEnabled(true); imageView.buildDrawingCache(); Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] data = baos.toByteArray(); UploadTask uploadTask = mountainsRef.putBytes(data); uploadTask.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { // Handle unsuccessful uploads } }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc. // ... } });
Como putBytes()
aceita um byte[]
, seu app precisa guardar todo o
conteúdo de um arquivo na memória de uma só vez. Use putStream()
ou
putFile()
para usar menos memória.
Fazer upload usando um stream
O método putStream()
é a maneira mais versátil de fazer upload de um arquivo para o Cloud Storage. putStream()
recebe um InputStream
e retorna um UploadTask
que pode ser usado para gerenciar e monitorar o status do upload.
Kotlin+KTX
val stream = FileInputStream(File("path/to/images/rivers.jpg")) uploadTask = mountainsRef.putStream(stream) uploadTask.addOnFailureListener { // Handle unsuccessful uploads }.addOnSuccessListener { taskSnapshot -> // taskSnapshot.metadata contains file metadata such as size, content-type, etc. // ... }
Java
InputStream stream = new FileInputStream(new File("path/to/images/rivers.jpg")); uploadTask = mountainsRef.putStream(stream); uploadTask.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { // Handle unsuccessful uploads } }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc. // ... } });
Fazer upload de um arquivo local
Use o método putFile()
para fazer upload de arquivos locais no dispositivo, como fotos e vídeos da
câmera. putFile()
recebe um File
e retorna um
UploadTask
, que pode ser usado para gerenciar e monitorar o status do upload.
Kotlin+KTX
var file = Uri.fromFile(File("path/to/images/rivers.jpg")) val riversRef = storageRef.child("images/${file.lastPathSegment}") uploadTask = riversRef.putFile(file) // Register observers to listen for when the download is done or if it fails uploadTask.addOnFailureListener { // Handle unsuccessful uploads }.addOnSuccessListener { taskSnapshot -> // taskSnapshot.metadata contains file metadata such as size, content-type, etc. // ... }
Java
Uri file = Uri.fromFile(new File("path/to/images/rivers.jpg")); StorageReference riversRef = storageRef.child("images/"+file.getLastPathSegment()); uploadTask = riversRef.putFile(file); // Register observers to listen for when the download is done or if it fails uploadTask.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { // Handle unsuccessful uploads } }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc. // ... } });
Gerar um URL de download
Depois de fazer upload de um arquivo, é possível gerar um URL para fazer o download dele chamando
o método getDownloadUrl()
no StorageReference
:
Kotlin+KTX
val ref = storageRef.child("images/mountains.jpg") uploadTask = ref.putFile(file) val urlTask = uploadTask.continueWithTask { task -> if (!task.isSuccessful) { task.exception?.let { throw it } } ref.downloadUrl }.addOnCompleteListener { task -> if (task.isSuccessful) { val downloadUri = task.result } else { // Handle failures // ... } }
Java
final StorageReference ref = storageRef.child("images/mountains.jpg"); uploadTask = ref.putFile(file); Task<Uri> urlTask = uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() { @Override public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception { if (!task.isSuccessful()) { throw task.getException(); } // Continue with the task to get the download URL return ref.getDownloadUrl(); } }).addOnCompleteListener(new OnCompleteListener<Uri>() { @Override public void onComplete(@NonNull Task<Uri> task) { if (task.isSuccessful()) { Uri downloadUri = task.getResult(); } else { // Handle failures // ... } } });
Adicionar metadados de arquivo
Você também pode incluir metadados ao fazer upload de arquivos.
Em geral, esses metadados contêm propriedades típicas de arquivos, como name
, size
e contentType
(frequentemente chamadas de tipo MIME). O método putFile()
infere automaticamente o tipo MIME da extensão File
, mas é possível substituir o tipo detectado automaticamente especificando contentType
nos metadados. Se você não fornecer um contentType
e o Cloud Storage não puder inferir um padrão pela extensão de arquivo, o Cloud Storage usará application/octet-stream
. Veja mais informações sobre metadados de arquivos na seção Usar metadados de arquivos.
Kotlin+KTX
// Create file metadata including the content type var metadata = storageMetadata { contentType = "image/jpg" } // Upload the file and metadata uploadTask = storageRef.child("images/mountains.jpg").putFile(file, metadata)
Java
// Create file metadata including the content type StorageMetadata metadata = new StorageMetadata.Builder() .setContentType("image/jpg") .build(); // Upload the file and metadata uploadTask = storageRef.child("images/mountains.jpg").putFile(file, metadata);
Gerenciar uploads
Além de iniciar os uploads, você pode pausar, retomar e cancelar uploads usando
os métodos pause()
, resume()
e cancel()
. Eventos de pausa e retomada
provocam as mudanças de estado pause
e progress
, respectivamente. Cancelar um
upload faz com que ele falhe com um erro indicando que o
upload foi cancelado.
Kotlin+KTX
uploadTask = storageRef.child("images/mountains.jpg").putFile(file) // Pause the upload uploadTask.pause() // Resume the upload uploadTask.resume() // Cancel the upload uploadTask.cancel()
Java
uploadTask = storageRef.child("images/mountains.jpg").putFile(file); // Pause the upload uploadTask.pause(); // Resume the upload uploadTask.resume(); // Cancel the upload uploadTask.cancel();
Monitorar o andamento do upload
Você pode adicionar listeners para gerenciar êxitos, falhas, progresso ou pausas na tarefa de upload:
Tipo de listener | Uso típico |
---|---|
OnProgressListener |
Este listener é chamado periodicamente à medida que os dados são transferidos e pode ser usado para preencher um indicador de upload/download. |
OnPausedListener |
Este listener é chamado sempre que a tarefa é pausada. |
OnSuccessListener |
Este listener é chamado quando a tarefa é concluída com êxito. |
OnFailureListener |
Este listener é chamado sempre que o upload falha. Isso pode acontecer devido ao tempo limite da rede, a falhas de autorização ou se você cancelar a tarefa. |
OnFailureListener
é chamado com uma instância Exception
. Outros listeners são chamados com um objeto UploadTask.TaskSnapshot
.
Esse objeto é uma visualização imutável da tarefa no momento em que o evento ocorreu.
Um UploadTask.TaskSnapshot
contém as seguintes propriedades:
Propriedade | Tipo | Descrição |
---|---|---|
getDownloadUrl |
String |
Um URL que pode ser usado para fazer o download do objeto. Trata-se de um URL público que não pode ser adivinhado e que pode ser compartilhado com outros clientes. Esse valor é preenchido uma vez concluído o upload. |
getError |
Exception |
Se a tarefa falhou, ela terá a causa como uma Exceção. |
getBytesTransferred |
long |
O número total de bytes que foram transferidos quando o snapshot foi capturado. |
getTotalByteCount |
long |
O número total de bytes esperados no upload. |
getUploadSessionUri |
String |
Um URI que pode ser usado para continuar a tarefa com outra chamada para putFile. |
getMetadata |
StorageMetadata |
Antes de um upload ser concluído, estes são os metadados enviados ao servidor. Após a conclusão do upload, estes são os metadados retornados pelo servidor. |
getTask |
UploadTask |
A tarefa que criou o snapshot. Use esta tarefa para cancelar, pausar ou retomar o upload. |
getStorage |
StorageReference |
O StorageReference usado para criar o UploadTask . |
Os listeners do evento UploadTask
fornecem uma maneira simples e poderosa de monitorar
eventos de upload.
Kotlin+KTX
// Observe state change events such as progress, pause, and resume // You'll need to import com.google.firebase.storage.component1 and // com.google.firebase.storage.component2 uploadTask.addOnProgressListener { (bytesTransferred, totalByteCount) -> val progress = (100.0 * bytesTransferred) / totalByteCount Log.d(TAG, "Upload is $progress% done") }.addOnPausedListener { Log.d(TAG, "Upload is paused") }
Java
// Observe state change events such as progress, pause, and resume uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() { @Override public void onProgress(UploadTask.TaskSnapshot taskSnapshot) { double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount(); Log.d(TAG, "Upload is " + progress + "% done"); } }).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() { @Override public void onPaused(UploadTask.TaskSnapshot taskSnapshot) { Log.d(TAG, "Upload is paused"); } });
Processar mudanças no ciclo de vida de atividades
Os uploads continuam em segundo plano mesmo após mudanças no ciclo de vida de atividades (como apresentar uma caixa de diálogo ou girar a tela). Qualquer listener conectado permanecerá conectado. Isso poderá causar resultados inesperados se eles forem chamados após a interrupção da atividade.
Esse problema pode ser solucionado ao inscrever seus listeners com um escopo de atividade
para cancelar o registro automaticamente quando a atividade for interrompida. Em seguida, use o
método getActiveUploadTasks
quando a atividade for reiniciada para receber as tarefas de upload
que ainda estiverem em andamento ou que tiverem sido concluídas recentemente.
O exemplo abaixo demonstra isso e também mostra como manter o caminho de referência de armazenamento utilizado.
Kotlin+KTX
override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) // If there's an upload in progress, save the reference so you can query it later outState.putString("reference", storageRef.toString()) } override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) // If there was an upload in progress, get its reference and create a new StorageReference val stringRef = savedInstanceState.getString("reference") ?: return storageRef = Firebase.storage.getReferenceFromUrl(stringRef) // Find all UploadTasks under this StorageReference (in this example, there should be one) val tasks = storageRef.activeUploadTasks if (tasks.size > 0) { // Get the task monitoring the upload val task = tasks[0] // Add new listeners to the task using an Activity scope task.addOnSuccessListener(this) { // Success! // ... } } }
Java
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // If there's an upload in progress, save the reference so you can query it later if (mStorageRef != null) { outState.putString("reference", mStorageRef.toString()); } } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // If there was an upload in progress, get its reference and create a new StorageReference final String stringRef = savedInstanceState.getString("reference"); if (stringRef == null) { return; } mStorageRef = FirebaseStorage.getInstance().getReferenceFromUrl(stringRef); // Find all UploadTasks under this StorageReference (in this example, there should be one) List<UploadTask> tasks = mStorageRef.getActiveUploadTasks(); if (tasks.size() > 0) { // Get the task monitoring the upload UploadTask task = tasks.get(0); // Add new listeners to the task using an Activity scope task.addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot state) { // Success! // ... } }); } }
getActiveUploadTasks
recupera todas as tarefas ativas de upload na referência fornecida e
abaixo dela, portanto, talvez seja necessário processar diversas tarefas.
Como continuar uploads após reinicializações de processos
Se seu processo for encerrado, qualquer upload em andamento será interrompido. No entanto, você pode continuar o upload depois que o processo for reiniciado, retomando a sessão de upload com o servidor. Isso pode poupar tempo e largura de banda, já que não reinicia o upload do arquivo do zero.
Para fazer isso, comece a fazer o upload via putFile
. Na StorageTask
resultante,
chame getUploadSessionUri
e salve o valor resultante em um armazenamento permanente
(como SharedPreferences).
Kotlin+KTX
uploadTask = storageRef.putFile(localFile) uploadTask.addOnProgressListener { taskSnapshot -> sessionUri = taskSnapshot.uploadSessionUri if (sessionUri != null && !saved) { saved = true // A persisted session has begun with the server. // Save this to persistent storage in case the process dies. } }
Java
uploadTask = mStorageRef.putFile(localFile); uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() { @Override public void onProgress(UploadTask.TaskSnapshot taskSnapshot) { Uri sessionUri = taskSnapshot.getUploadSessionUri(); if (sessionUri != null && !mSaved) { mSaved = true; // A persisted session has begun with the server. // Save this to persistent storage in case the process dies. } } });
Depois que o processo for reiniciado com um upload interrompido, chame putFile novamente. Dessa vez, transfira também o URI que foi salvo.
Kotlin+KTX
// resume the upload task from where it left off when the process died. // to do this, pass the sessionUri as the last parameter uploadTask = storageRef.putFile( localFile, storageMetadata { }, sessionUri, )
Java
//resume the upload task from where it left off when the process died. //to do this, pass the sessionUri as the last parameter uploadTask = mStorageRef.putFile(localFile, new StorageMetadata.Builder().build(), sessionUri);
Sessões duram uma semana. Se tentar retomar uma sessão após a expiração ou se ela tiver apresentado um erro, você receberá um callback de falha. É sua responsabilidade garantir que o arquivo não seja alterado entre uploads.
Tratamento de erros
Há uma série de motivos pelos quais erros podem ocorrer no upload, incluindo arquivo local não existente ou o usuário não ter permissão para fazer upload do arquivo desejado. Encontre mais informações sobre erros na seção Tratamento de erros da documentação.
Exemplo completo
Um exemplo completo de upload com monitoramento de andamento e tratamento de erros é mostrado abaixo:
Kotlin+KTX
// File or Blob file = Uri.fromFile(File("path/to/mountains.jpg")) // Create the file metadata metadata = storageMetadata { contentType = "image/jpeg" } // Upload file and metadata to the path 'images/mountains.jpg' uploadTask = storageRef.child("images/${file.lastPathSegment}").putFile(file, metadata) // Listen for state changes, errors, and completion of the upload. // You'll need to import com.google.firebase.storage.component1 and // com.google.firebase.storage.component2 uploadTask.addOnProgressListener { (bytesTransferred, totalByteCount) -> val progress = (100.0 * bytesTransferred) / totalByteCount Log.d(TAG, "Upload is $progress% done") }.addOnPausedListener { Log.d(TAG, "Upload is paused") }.addOnFailureListener { // Handle unsuccessful uploads }.addOnSuccessListener { // Handle successful uploads on complete // ... }
Java
// File or Blob file = Uri.fromFile(new File("path/to/mountains.jpg")); // Create the file metadata metadata = new StorageMetadata.Builder() .setContentType("image/jpeg") .build(); // Upload file and metadata to the path 'images/mountains.jpg' uploadTask = storageRef.child("images/"+file.getLastPathSegment()).putFile(file, metadata); // Listen for state changes, errors, and completion of the upload. uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() { @Override public void onProgress(UploadTask.TaskSnapshot taskSnapshot) { double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount(); Log.d(TAG, "Upload is " + progress + "% done"); } }).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() { @Override public void onPaused(UploadTask.TaskSnapshot taskSnapshot) { Log.d(TAG, "Upload is paused"); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { // Handle unsuccessful uploads } }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { // Handle successful uploads on complete // ... } });
Agora que você já sabe fazer upload de arquivos, veja como baixá-los do Cloud Storage.