Загрузка файлов с помощью Cloud Storage на Android

Cloud Storage for Firebase allows you to quickly and easily upload files to a Cloud Storage bucket provided and managed by Firebase.

Загрузка файлов

To upload a file to Cloud Storage , you first create a reference to the full path of the file, including the file name.

Kotlin

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

Once you've created an appropriate reference, you then call the putBytes() , putFile() , or putStream() method to upload the file to Cloud Storage .

You cannot upload data with a reference to the root of your Cloud Storage bucket. Your reference must point to a child URL.

Загрузка данных из памяти.

Метод putBytes() — это самый простой способ загрузить файл в Cloud Storage . Метод putBytes() принимает byte[] и возвращает объект UploadTask , который можно использовать для управления и мониторинга статуса загрузки.

Kotlin

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

Because putBytes() accepts a byte[] , it requires your app to hold the entire contents of a file in memory at once. Consider using putStream() or putFile() to use less memory.

Загрузка из потока

Метод putStream() — это наиболее универсальный способ загрузки файла в Cloud Storage . putStream() принимает InputStream и возвращает UploadTask , который можно использовать для управления и мониторинга статуса загрузки.

Kotlin

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

Загрузка из локального файла

С помощью метода putFile() можно загружать локальные файлы на устройство, например, фотографии и видео с камеры. Метод putFile() принимает File и возвращает объект UploadTask , который можно использовать для управления и отслеживания статуса загрузки.

Kotlin

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

Получите URL-адрес для скачивания

After uploading a file, you can get a URL to download the file by calling the getDownloadUrl() method on the StorageReference :

Kotlin

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

Добавить метаданные файла

При загрузке файлов вы также можете добавлять метаданные. Эти метаданные содержат типичные свойства метаданных файла, такие как name , size и contentType (обычно называемый MIME-типом). Метод putFile() автоматически определяет MIME-тип по расширению File , но вы можете переопределить автоматически определенный тип, указав contentType в метаданных. Если вы не указываете contentType , и Cloud Storage не может определить значение по умолчанию по расширению файла, Cloud Storage использует application/octet-stream . Дополнительную информацию о метаданных файлов см. в разделе « Использование метаданных файлов».

Kotlin

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

Управление загрузками

Помимо начала загрузки, вы можете приостанавливать, возобновлять и отменять загрузку, используя методы pause() , resume() и cancel() . События паузы и возобновления вызывают изменения состояния pause и progress соответственно. Отмена загрузки приводит к сбою загрузки с ошибкой, указывающей на то, что загрузка была отменена.

Kotlin

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

Отслеживание хода загрузки

You can add listeners to handle success, failure, progress, or pauses in your upload task:

Тип слушателя Типичное использование
OnProgressListener This listener is called periodically as data is transferred and can be used to populate an upload/download indicator.
OnPausedListener This listener is called any time the task is paused.
OnSuccessListener This listener is called when the task has successfully completed.
OnFailureListener This listener is called any time the upload has failed. This can happen due to network timeouts, authorization failures, or if you cancel the task.

OnFailureListener вызывается с экземпляром Exception . Другие обработчики событий вызываются с объектом UploadTask.TaskSnapshot . Этот объект представляет собой неизменяемое представление задачи на момент возникновения события. Объект UploadTask.TaskSnapshot содержит следующие свойства:

Свойство Тип Описание
getDownloadUrl String A URL that can be used to download the object. This is a public unguessable URL that can be shared with other clients. This value is populated once an upload is complete.
getError Exception Если задача не была выполнена, причиной будет указано исключение.
getBytesTransferred long The total number of bytes that have been transferred when this snapshot was taken.
getTotalByteCount long The total number of bytes expected to be uploaded.
getUploadSessionUri String A URI that can be used to continue this task via another call to putFile.
getMetadata StorageMetadata Before an upload completes, this is the metadata being sent to the server. After the upload completes, this is the metadata returned by the server.
getTask UploadTask Задача, создавшая этот снимок. Используйте эту задачу, чтобы отменить, приостановить или возобновить загрузку.
getStorage StorageReference Объект StorageReference используемый для создания задачи UploadTask .

The UploadTask event listeners provide a simple and powerful way to monitor upload events.

Kotlin

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

Обработка изменений жизненного цикла действий

Загрузка файлов продолжается в фоновом режиме даже после изменения жизненного цикла активности (например, при отображении диалогового окна или повороте экрана). Все прикрепленные вами обработчики событий также останутся прикрепленными. Это может привести к неожиданным результатам, если они будут вызваны после остановки активности.

Эту проблему можно решить, подписав слушатели на область действия активности, чтобы они автоматически отменялись при остановке активности. Затем, при перезапуске активности, используйте метод getActiveUploadTasks , чтобы получить список задач загрузки, которые все еще выполняются или недавно завершились.

The example below demonstrates this and also shows how to persist the storage reference path used.

Kotlin

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 извлекает все активные задачи загрузки, находящиеся на уровне и ниже указанного значения, поэтому вам может потребоваться обработать несколько задач.

Продолжение загрузки при перезапуске процесса

Если ваш процесс будет остановлен, все текущие загрузки будут прерваны. Однако вы можете продолжить загрузку после перезапуска процесса, возобновив сессию загрузки с сервером. Это позволит сэкономить время и пропускную способность, поскольку загрузка не будет начинаться с начала файла.

To do this, begin uploading via putFile . On the resulting StorageTask , call getUploadSessionUri and save the resulting value in persistent storage (such as SharedPreferences).

Kotlin

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

After your process restarts with an interrupted upload, call putFile again. But this time also pass the Uri that was saved.

Kotlin

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

Продолжительность сессии — одна неделя. Если вы попытаетесь возобновить сессию после её истечения или если произошла ошибка, вы получите сообщение об ошибке. Вы несёте ответственность за то, чтобы файл не изменился между загрузками.

Обработка ошибок

При загрузке могут возникать ошибки по ряду причин, включая отсутствие локального файла или отсутствие у пользователя разрешения на загрузку нужного файла. Более подробную информацию об ошибках можно найти в разделе «Обработка ошибок» документации.

Полный пример

Полный пример загрузки с отслеживанием хода процесса и обработкой ошибок показан ниже:

Kotlin

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

Now that you've uploaded files, let's learn how to download them from Cloud Storage .