Android で Cloud Storage を使用してファイルをダウンロードする

Cloud Storage for Firebase を使用すると、Firebase によって提供、管理される Cloud Storage バケットからファイルを迅速かつ容易にダウンロードできます。

参照を作成する

ファイルをダウンロードするには、まずダウンロードするファイルへの Cloud Storage 参照を作成します。

参照は、Cloud Storage バケットのルートに子パスを付加して作成することも、Cloud Storage のオブジェクトを参照する既存の gs:// または https:// URL から作成することもできます。

Kotlin+KTX

// Create a storage reference from our app
val storageRef = storage.reference

// Create a reference with an initial file path and name
val pathReference = storageRef.child("images/stars.jpg")

// Create a reference to a file from a Google Cloud Storage URI
val gsReference = storage.getReferenceFromUrl("gs://bucket/images/stars.jpg")

// Create a reference from an HTTPS URL
// Note that in the URL, characters are URL escaped!
val httpsReference = storage.getReferenceFromUrl(
    "https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg",
)

Java

// Create a storage reference from our app
StorageReference storageRef = storage.getReference();

// Create a reference with an initial file path and name
StorageReference pathReference = storageRef.child("images/stars.jpg");

// Create a reference to a file from a Google Cloud Storage URI
StorageReference gsReference = storage.getReferenceFromUrl("gs://bucket/images/stars.jpg");

// Create a reference from an HTTPS URL
// Note that in the URL, characters are URL escaped!
StorageReference httpsReference = storage.getReferenceFromUrl("https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg");

ファイルをダウンロードする

参照を作成したら、getBytes() または getStream() を呼び出して Cloud Storage からファイルをダウンロードできます。別のライブラリのファイルをダウンロードしたい場合は、getDownloadUrl() を使用してダウンロード URL を取得できます。

メモリにダウンロードする

getBytes() メソッドを使用してファイルを byte[] にダウンロードします。これは最も簡単にファイルをダウンロードできる方法ですが、ファイルのコンテンツ全体をメモリ内に読み込む必要があります。アプリで使用できるメモリよりも大きなファイルをリクエストするとアプリがクラッシュするため、メモリの問題が発生しないように、getBytes() にダウンロードの最大バイト数を設定します。アプリで処理できる範囲内で最大サイズを設定するか、別のダウンロード メソッドを使用してください。

Kotlin+KTX

var islandRef = storageRef.child("images/island.jpg")

val ONE_MEGABYTE: Long = 1024 * 1024
islandRef.getBytes(ONE_MEGABYTE).addOnSuccessListener {
    // Data for "images/island.jpg" is returned, use this as needed
}.addOnFailureListener {
    // Handle any errors
}

Java

StorageReference islandRef = storageRef.child("images/island.jpg");

final long ONE_MEGABYTE = 1024 * 1024;
islandRef.getBytes(ONE_MEGABYTE).addOnSuccessListener(new OnSuccessListener<byte[]>() {
    @Override
    public void onSuccess(byte[] bytes) {
        // Data for "images/island.jpg" is returns, use this as needed
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle any errors
    }
});

ローカル ファイルにダウンロードする

getFile() メソッドは、ファイルをローカル デバイスに直接ダウンロードします。オフライン中にファイルにアクセスしたい場合や、別のアプリでファイルを共有したい場合は、このメソッドを使用します。getFile() から返される DownloadTask を使用して、ダウンロードの管理とダウンロード ステータスのモニタリングを行うことができます。

Kotlin+KTX

islandRef = storageRef.child("images/island.jpg")

val localFile = File.createTempFile("images", "jpg")

islandRef.getFile(localFile).addOnSuccessListener {
    // Local temp file has been created
}.addOnFailureListener {
    // Handle any errors
}

Java

islandRef = storageRef.child("images/island.jpg");

File localFile = File.createTempFile("images", "jpg");

islandRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
        // Local temp file has been created
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle any errors
    }
});

ダウンロードを積極的に管理したい場合は、ダウンロードの管理で詳細をご覧ください。

URL 経由でデータをダウンロードする

URL をベースにしたダウンロード インフラストラクチャがすでにある場合や、URL を共有したい場合は、Cloud Storage 参照に対して getDownloadUrl() メソッドを呼び出してファイルのダウンロード URL を取得できます。

Kotlin+KTX

storageRef.child("users/me/profile.png").downloadUrl.addOnSuccessListener {
    // Got the download URL for 'users/me/profile.png'
}.addOnFailureListener {
    // Handle any errors
}

Java

storageRef.child("users/me/profile.png").getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
    @Override
    public void onSuccess(Uri uri) {
        // Got the download URL for 'users/me/profile.png'
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle any errors
    }
});

FirebaseUI によって画像をダウンロードする

FirebaseUI にはシンプルかつカスタマイズ可能で本番環境に対応したネイティブのモバイル バインドが用意されているため、ボイラープレート コードをなくし、Google のベスト プラクティスの採用を促進できます。FirebaseUI なら、Glide とのインテグレーションを使用して、Cloud Storage からすばやく簡単に画像をダウンロード、キャッシュ保存、表示することができます。

最初に FirebaseUI を app/build.gradle に追加します。

dependencies {
    // FirebaseUI Storage only
    implementation 'com.firebaseui:firebase-ui-storage:7.2.0'
}

次に、Cloud Storage から ImageView に直接画像を読み込みます。

Kotlin+KTX

// Reference to an image file in Cloud Storage
val storageReference = Firebase.storage.reference

// ImageView in your Activity
val imageView = findViewById<ImageView>(R.id.imageView)

// Download directly from StorageReference using Glide
// (See MyAppGlideModule for Loader registration)
Glide.with(context)
    .load(storageReference)
    .into(imageView)

Java

// Reference to an image file in Cloud Storage
StorageReference storageReference = FirebaseStorage.getInstance().getReference();

// ImageView in your Activity
ImageView imageView = findViewById(R.id.imageView);

// Download directly from StorageReference using Glide
// (See MyAppGlideModule for Loader registration)
Glide.with(context)
        .load(storageReference)
        .into(imageView);

アクティビティのライフサイクルの変更を処理する

アクティビティのライフサイクル(ダイアログの表示や画面の回転など)が変わった後でも、ダウンロードはバックグラウンドで継続します。指定したリスナーも、指定されたまま残ります。このため、アクティビティが停止した後でリスナーが呼び出されると、予期せぬ結果が生じることがあります。

この問題を解決するには、アクティビティの範囲を指定してリスナーを登録します。こうすると、そのアクティビティが停止したときにリスナーは自動的に登録を解除されます。次に、アクティビティが再開したら getActiveDownloadTasks メソッドを使用して、実行中または最近完了したダウンロード タスクを取得します。

以下の例は、上記の手順と、使用するストレージ参照パスを保持する方法を示しています。

Kotlin+KTX

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

    // If there's a download 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 a download in progress, get its reference and create a new StorageReference
    val stringRef = savedInstanceState.getString("reference") ?: return

    storageRef = Firebase.storage.getReferenceFromUrl(stringRef)

    // Find all DownloadTasks under this StorageReference (in this example, there should be one)
    val tasks = storageRef.activeDownloadTasks

    if (tasks.size > 0) {
        // Get the task monitoring the download
        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 a download 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 a download 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 DownloadTasks under this StorageReference (in this example, there should be one)
    List<FileDownloadTask> tasks = mStorageRef.getActiveDownloadTasks();
    if (tasks.size() > 0) {
        // Get the task monitoring the download
        FileDownloadTask task = tasks.get(0);

        // Add new listeners to the task using an Activity scope
        task.addOnSuccessListener(this, new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
            @Override
            public void onSuccess(FileDownloadTask.TaskSnapshot state) {
                // Success!
                // ...
            }
        });
    }
}

エラーを処理する

ダウンロード時にエラーが発生する理由としては、ファイルが存在しない、目的のファイルへのアクセス権がないなど、多くの理由が考えられます。エラーの詳細については、このドキュメントのエラーを処理するのセクションをご覧ください。

ダウンロードとエラー処理の完全な例を以下に示します。

Kotlin+KTX

storageRef.child("users/me/profile.png").getBytes(Long.MAX_VALUE).addOnSuccessListener {
    // Use the bytes to display the image
}.addOnFailureListener {
    // Handle any errors
}

Java

storageRef.child("users/me/profile.png").getBytes(Long.MAX_VALUE).addOnSuccessListener(new OnSuccessListener<byte[]>() {
    @Override
    public void onSuccess(byte[] bytes) {
        // Use the bytes to display the image
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle any errors
    }
});

Cloud Storage に保存されているファイルのメタデータを取得して更新することもできます。