Fazer upload de arquivos no Android

Com o Cloud Storage, os desenvolvedores ganham rapidez e facilidade ao fazer upload de arquivos para um intervalo do Google 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.

Java
Android

// 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

Kotlin
Android

// 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

Depois de criar uma referência apropriada, chame o método putBytes(), putFile() ou putStream() para fazer upload do arquivo no Cloud Storage.

Não é possível fazer o upload de dados com uma referência à raiz do seu intervalo do Google 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 no Cloud Storage. putBytes() recebe um byte[] e retorna um UploadTask que você pode usar para gerenciar e monitorar o status do upload.

Java
Android

// 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.
        // ...
    }
});

Kotlin
Android

// 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.metadata contains file metadata such as size, content-type, etc.
    // ...
}

Como putBytes() aceita um byte[], seu aplicativo deve guardar todo o conteúdo de um arquivo na memória de uma só vez. Use putStream() ou putFile() para usar menos memória.

Upload de um stream

O método putStream() é a maneira mais versátil de fazer upload de um arquivo no Cloud Storage. putStream() recebe um InputStream e retorna um UploadTask que você pode usar para gerenciar e monitorar o status do upload.

Java
Android

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.
        // ...
    }
});

Kotlin
Android

val stream = FileInputStream(File("path/to/images/rivers.jpg"))

uploadTask = mountainsRef.putStream(stream)
uploadTask.addOnFailureListener {
    // Handle unsuccessful uploads
}.addOnSuccessListener {
    // taskSnapshot.metadata 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.

Java
Android

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.
        // ...
    }
});

Kotlin
Android

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.metadata contains file metadata such as size, content-type, etc.
    // ...
}

Gerar um URL de download

Depois de fazer upload de um arquivo, você pode gerar um URL para fazer o download dele chamando o método getDownloadUrl() no StorageReference:

Java
Android

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
            // ...
        }
    }
});

Kotlin
Android

val ref = storageRef.child("images/mountains.jpg")
uploadTask = ref.putFile(file)

val urlTask = uploadTask.continueWithTask(Continuation<UploadTask.TaskSnapshot, Task<Uri>> { task ->
    if (!task.isSuccessful) {
        task.exception?.let {
            throw it
        }
    }
    return@Continuation ref.downloadUrl
}).addOnCompleteListener { task ->
    if (task.isSuccessful) {
        val downloadUri = task.result
    } 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 arquivo, como name, size e contentType (frequentemente chamadas de tipo MIME). O método putFile() infere automaticamente o tipo MIME da extensão File, mas você pode substituir o tipo detectado automaticamente especificando contentType nos metadados. Se você não fornecer um contentType e o Cloud Storage não for capaz de inferir um padrão a partir da extensão de arquivo, o Cloud Storage usará application/octet-stream. Veja mais informações sobre metadados de arquivo na seção Usar metadados de arquivo.

Java
Android

// 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);

Kotlin
Android

// Create file metadata including the content type
var metadata = 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 uploads, é possível pausar, retomar e cancelar uploads usando os métodos pause(), resume() e cancel(). Faça uma pausa e retome os eventos aumentando as mudanças de estado de pause e progress, respectivamente. Os uploads falham quando você os cancela. Depois disso, uma mensagem é exibida indicando que o upload foi cancelado.

Java
Android

uploadTask = storageRef.child("images/mountains.jpg").putFile(file);

// Pause the upload
uploadTask.pause();

// Resume the upload
uploadTask.resume();

// Cancel the upload
uploadTask.cancel();

Kotlin
Android

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 a qualquer momento em que a tarefa está 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, 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 não alterá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 que o upload é concluído.
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 instantâneo 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 por meio de outra chamada para putFile.
getMetadata StorageMetadata Antes de um upload ser concluído, este é o metadado enviado ao servidor. Após a conclusão do upload, estes são os metadados retornados pelo servidor.
getTask UploadTask A tarefa que criou o instantâneo. Use esta tarefa para cancelar, pausar ou continuar 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.

Java
Android

// 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();
        System.out.println("Upload is " + progress + "% done");
    }
}).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onPaused(UploadTask.TaskSnapshot taskSnapshot) {
        System.out.println("Upload is paused");
    }
});

Kotlin
Android

// Observe state change events such as progress, pause, and resume
uploadTask.addOnProgressListener { taskSnapshot ->
    val progress = (100.0 * taskSnapshot.bytesTransferred) / taskSnapshot.totalByteCount
    System.out.println("Upload is $progress% done")
}.addOnPausedListener {
    System.out.println("Upload is paused")
}

Como lidar com 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.

Java
Android

@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!
                // ...
            }
        });
    }
}

Kotlin
Android

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)

    // If there's an upload in progress, save the reference so you can query it later
    storageRef?.let {
        outState.putString("reference", it.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 = FirebaseStorage.getInstance().getReferenceFromUrl(stringRef)

    // Find all UploadTasks under this StorageReference (in this example, there should be one)

    storageRef?.activeUploadTasks?.let { it ->
        if (it.size > 0) {
            // Get the task monitoring the upload
            val task = it[0]

            // Add new listeners to the task using an Activity scope
            task.addOnSuccessListener(this) {
                // Success!
                // ...
            }
        }
    }
}

getActiveUploadTasks recupera todas as tarefas de upload ativas na referência fornecida e abaixo dela. Portanto, você pode precisar processar diversas tarefas.

Continuar uploads durante reinicializações de processo

Se o 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, pois não reinicia o upload do início do arquivo.

Para fazer isso, comece a fazer o upload via putFile. Na StorageTask resultante, chame getUploadSessionUri e salve o valor resultante no armazenamento persistente (como SharedPreferences).

Java
Android

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.
        }
    }
});

Kotlin
Android

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.
    }
}

Depois que o processo for reiniciado com um upload interrompido, chame putFile novamente. Dessa vez, transfira também o URI que foi salvo.

Java
Android

//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);

Kotlin
Android

// 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.Builder().build(), sessionUri)

As 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 retorno de chamada de falha. É sua responsabilidade garantir que o arquivo não seja alterado entre uploads.

Como lidar com erros

Há diversos motivos pelos quais erros podem ocorrer, como arquivo não existente, usuário sem permissão para acessar o arquivo desejado ou cancelamento do upload do arquivo por parte do usuário. Encontre mais informações sobre erros na seção Como lidar com erros da documentação.

Exemplo completo

Um exemplo completo de upload com monitoramento de andamento e tratamento de erros é mostrado abaixo:

Java
Android

// 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();
        System.out.println("Upload is " + progress + "% done");
    }
}).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onPaused(UploadTask.TaskSnapshot taskSnapshot) {
        System.out.println("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
        // ...
    }
});

Kotlin
Android

// File or Blob
file = Uri.fromFile(File("path/to/mountains.jpg"))

// Create the file metadata
metadata = StorageMetadata.Builder()
        .setContentType("image/jpeg")
        .build()

// 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.
uploadTask.addOnProgressListener { taskSnapshot ->
    val progress = (100.0 * taskSnapshot.bytesTransferred) / taskSnapshot.totalByteCount
    System.out.println("Upload is $progress% done")
}.addOnPausedListener {
    System.out.println("Upload is paused")
}.addOnFailureListener {
    // Handle unsuccessful uploads
}.addOnSuccessListener {
    // Handle successful uploads on complete
    // ...
}

Agora que você já sabe fazer upload de arquivos, veja como fazer o download no Cloud Storage.

Enviar comentários sobre…

Precisa de ajuda? Acesse nossa página de suporte.