Android でファイルをアップロードする

Cloud Storage を使用すると、デベロッパーは Firebase によって提供、管理される Google Cloud Storage バケットにファイルを迅速かつ容易にアップロードできます。

ファイルをアップロードする

ファイルを Cloud Storage にアップロードするには、まずファイル名を含むファイルの完全パスへの参照を作成します。

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

適切な参照を作成したら、putBytes()putFile()、または putStream() メソッドを呼び出して、Cloud Storage にファイルをアップロードできます。

Google Cloud Storage バケットのルートへの参照を指定してデータをアップロードすることはできません。参照は子 URL をポイントしている必要があります。

メモリ内のデータからのアップロード

putBytes() メソッドは最も簡単にファイルを Cloud Storage にアップロードできる方法です。putBytes()byte[] を受け取って UploadTask を返します。これを使用してアップロード ステータスの管理と監視を行うことができます。

// Get the data from an ImageView as bytes
imageView.setDrawingCacheEnabled(true);
imageView.buildDrawingCache();
Bitmap bitmap = imageView.getDrawingCache();
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, and download URL.
        Uri downloadUrl = taskSnapshot.getDownloadUrl();
    }
});

putBytes()byte[] を受け取るため、アプリがファイルのコンテンツ全体をメモリ内に一度に保持できる必要があります。使用するメモリを少なくするには、putStream() または putFile() を使用します。

ストリームからのアップロード

putStream() メソッドは、ファイルを Cloud Storage にアップロードする最も用途の広い方法です。putStream()InputStream を受け取って UploadTask を返します。これを使用してアップロード ステータスの管理と監視ができます。

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, and download URL.
        Uri downloadUrl = taskSnapshot.getDownloadUrl();
    }
});

ローカル ファイルからのアップロード

写真や動画など、端末上のローカル ファイルは、putFile() メソッドを使用してアップロードできます。putFile()File を受け取って UploadTask を返します。これを使用してアップロード ステータスの管理と監視を行うことができます。

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, and download URL.
        Uri downloadUrl = taskSnapshot.getDownloadUrl();
    }
});

ファイル メタデータを追加する

ファイルをアップロードするときにメタデータを含めることもできます。このメタデータには、namesizecontentType(一般的に MIME タイプと呼ばれます)などの標準的なファイル メタデータのプロパティが含まれます。putFile() メソッドは File 拡張子から MIME タイプを自動的に推測しますが、contentType をメタデータに指定することにより、自動検出されるタイプをオーバーライドすることができます。contentType を指定しなかった場合にファイル拡張子からデフォルトのコンテンツ タイプを自動的に推測できないときは、application/octet-stream が使用されます。ファイル メタデータについて詳しくは、ファイル メタデータの使用のセクションをご覧ください。

// 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 に変わります。アップロードをキャンセルするとアップロードが失敗し、アップロードがキャンセルされたことを示すエラーが返されます。

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

// Pause the upload
uploadTask.pause();

// Resume the upload
uploadTask.resume();

// Cancel the upload
uploadTask.cancel();

アップロードの進捗状況を監視する

アップロード タスクの成功、失敗、進捗状況、一時停止を処理するためのリスナーを追加することができます。

リスナーのタイプ 一般的な使用方法
OnProgressListener データが転送されると定期的に呼び出され、アップロードまたはダウンロードのインジケータを埋め込むために使用できます。
OnPausedListener タスクが一時停止されると呼び出されます。
OnSuccessListener タスクが正常に完了すると呼び出されます。
OnFailureListener アップロードが失敗すると呼び出されます。アップロードの失敗は、ネットワークのタイムアウトや認証の失敗が原因で発生します。またはタスクをキャンセルした場合に発生します。

OnFailureListenerException インスタンスとともに呼び出されます。その他のリスナーの呼び出しには、UploadTask.TaskSnapshot オブジェクトを使用します。このオブジェクトは、イベントが発生したときのタスクの不変のビューです。UploadTask.TaskSnapshot には、以下のプロパティが含まれます。

プロパティ 説明
getDownloadUrl String オブジェクトのダウンロードに使用できる URL です。これは他のクライアントと共有できる、推測できない公開 URL です。この値はアップロードが完了すると入力されます。
getError Exception タスクが失敗した場合に、原因を例外にします。
getBytesTransferred long このスナップショットが作成された時点で転送済みのバイト数の合計です。
getTotalByteCount long アップロードされる予定のバイト数の合計です。
getUploadSessionUri String putFile の別の呼び出しを使ってこのタスクを続行する場合に使用できる URI です。
getMetadata StorageMetadata アップロードが完了する前にサーバーに送信されているメタデータです。アップロードが完了した後でサーバーから返されるメタデータです。
getTask UploadTask このスナップショットを作成したタスクです。このタスクを使用して、アップロードをキャンセル、一時停止、または再開します。
getStorage StorageReference UploadTask を作成するために使用される StorageReference です。

UploadTask イベント リスナーは、アップロード イベントを監視するためのシンプルで効果的な方法です。

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

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

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

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

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

StorageReference mStorageRef;  //mStorageRef was previously used to transfer data.

@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) {
             handleSuccess(state); //call a user defined function to handle the event.
          }
        });
    }
}

getActiveUploadTasks では、指定した参照とその下にある有効なアップロード タスクがすべて取得されるため、複数のタスクの処理が必要になる場合があります。

プロセス再開後のアップロードの続行

プロセスがシャットダウンされると、進行中のアップロードも中断されます。ただし、プロセスが再開したら、サーバーでアップロード セッションを再開してアップロードを続行することができます。この方法ではファイルの最初からアップロードを開始しないため、時間と帯域幅を節約できます。

これを行うには、putFile を使用してアップロードを開始します。StorageTask の結果が返されたら getUploadSessionUri を呼び出して、結果の値を永続ストレージ(SharedPreferences など)に保存します。

    uploadTask = mStorageRef.putFile(localFile);
    uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
      @Override
      public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
        Uri sessionUri = taskSnapshot.getUploadSessionUri();
        if (sessionUri != null && !saved) {
           saved = true;
          // A persisted session has begun with the server.
          // Save this to persistent storage in case the process dies.
        }
      }
    });

プロセスと中断されたアップロードが再開したら、putFile をもう一度呼び出します。ただし、今回は保存された URI も渡します。

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

セッションは 1 週間維持されます。セッションの期限が切れた後でセッションを再開しようとしたり、エラーが発生した場合は、失敗のコールバックを受け取ります。アップロードの間にファイルが変更されていないことを必ずご確認ください。

エラー処理

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

アップロード、進捗状況の監視、エラー処理の完全な例を以下に示します。

// 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
        Uri downloadUrl = taskSnapshot.getMetadata().getDownloadUrl();
    }
});

これでファイルのアップロードが完了しました。次は、Cloud Storage からファイルをダウンロードする方法を学習しましょう。

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。