こんにちは!
SJC共同開発推進室の鈴木です。
最近、業務でAndroid JavaでAWS S3へのファイル転送を効率化するライブラリを利用する機会がありましたので、今回はその便利な機能をご紹介します。
特に、ファイルアップロードが頻繁に求められるAndroidアプリ開発で、その効率と信頼性を格段に高めてくれるAWS SDKのユーティリティ、TransferUtilityに焦点を当てて解説していきます。
TransferUtilityとは?
TransferUtilityとは、AWSのストレージサービスである S3との間でファイルをやり取りを簡単にしてくれるAWS SDKです。
単にファイルを送るだけであれば、「PutObject」で指定されたファイルをそのままS3にアップロードするといったAWS SDK の基本的な API や AWS CLI でも可能です。しかし、効率的かつ信頼性が高く、大規模にデータを転送するためには、マルチパートアップロードや自動リトライ、転送状況の監視といった機能も実装したいところです。これらの機能を一手に引き受けてくれるのが、AWS SDK が提供する「TransferUtility」のような転送ユーティリティです。
今回は TransferUtility を中心にご紹介しますが、同様の機能は他の言語でも利用できます。
例えば、Java の場合は「S3TransferManager」(software.amazon.awssdk.transfer.s3.S3TransferManager)、Python の場合は boto3.s3.transfer.S3Transfer クラスで、TransferUtility に相当する機能が提供されています。
TransferUtilityの主な機能
大きいファイルも転送できるマルチパートアップロード
大きなファイルをネットワーク経由で送るとき、途中で接続が切れたり、タイムアウトになったりすると困りますよね。最初からやり直し、なんてことになったら時間も手間もかかってしまいます。
この問題を解決するために S3 の「マルチパートアップロード」機能を自動で行ってくれます。これは、ファイルを小さなパートに分割して、それぞれを並行してアップロードしてくれます。もし途中でどこかのパートが失敗しても、そのパートだけを再送すればいいので、ファイル全体の転送が効率的になり、途中で失敗しにくくなります。
バックグラウンドでのアップロード
ファイルアップロードのような時間のかかる処理を、メインスレッドで実行すると、アプリが一時的にフリーズしたり、システム全体の動作に影響が出てしまう可能性があります。
TransferUtilityは、操作をバックグラウンドで非同期に実行します。これにより、アップロードが進行中でも、スレッドはブロックされずにスムーズな動作を維持できます。ユーザーはアップロード中も他の機能を滞りなく実行できます。
アップロードの進捗をリアルタイムで確認
アップロードの状況変化(例えば、進行中、完了、失敗、ネットワーク待ちなど)や、具体的な進捗具合(どれくらい転送できたか、全体のサイズはどれくらいか)をリアルタイムで確認できます。これを使えば、プログレスバーを表示したり、状況に合わせたメッセージを出したりするのも簡単です。
現在の状況を正確に把握できるため、データが確実に届いているかを確認でき、転送に問題があった場合の処理をより簡単に実装できます。
ファイルをS3にアップロードする手順
TransferUtilityの初期化
まず、TransferUtilityを使うための準備です。AWSの認証情報(IAMロールまたはAWS IAMユーザーのアクセスキー・シークレットキー)と、S3のリージョン情報が必要になります。起動時などに一度だけ実行します。
| 
					 1 2 3 4 5 6  | 
						// 1. AWS 認証情報の取得 (例: Cognito Identity Pool を使用する場合) AWSCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider( getApplicationContext(), "YOUR_IDENTITY_POOL_ID", // Cognito Identity Pool ID Regions.YOUR_AWS_REGION // S3バケットのリージョン (例: Regions.AP_NORTHEAST_1 for 東京) );  | 
					
AmazonS3Client: S3サービスと通信するためのクライアントです。認証情報とリージョンを設定します。
| 
					 1 2 3  | 
						// 2. S3 クライアントの作成 AmazonS3Client s3Client = new AmazonS3Client(credentialsProvider); s3Client.setRegion(Region.getRegion(Regions.YOUR_AWS_REGION)); // S3クライアントにリージョンを設定  | 
					
context()でアプリのコンテキストを、そしてs3Client()で先ほど作ったS3クライアントをTransferUtilityに教えてあげます。これにより、TransferUtilityはアプリの環境下でS3との通信を行う準備が整います。
これだけの設定で、TransferUtilityのインスタンスを生成できます。
| 
					 1 2 3 4 5  | 
						// 3. TransferUtility の作成 TransferUtility transferUtility = TransferUtility.builder() .context(getApplicationContext()) .s3Client(s3Client) .build();  | 
					
ファイルのアップロードと状況監視
ファイル送信の結果、アップロードの進捗状況や完了・失敗といったステータスをリアルタイムで受け取る方法をご紹介します。
以下の例のように、TransferUtility.upload()メソッドを呼び出し、その返り値である TransferObserverに対して、TransferListenerを設定します。
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50  | 
						import com.amazonaws.mobileconnectors.s3.transferutility.TransferListener; import com.amazonaws.mobileconnectors.s3.transferutility.TransferObserver; import com.amazonaws.mobileconnectors.s3.transferutility.TransferState; // ... TransferUtility の初期化後 ... String bucketName = "your-s3-bucket-name"; // S3バケット名 String objectKey = "my_awesome_photo.jpg"; // S3に保存する際のファイル名 // アップロードしたいファイルを指定 File fileToUpload = new File(getFilesDir(), "demo_image.jpg"); // 例: アプリの内部ストレージにあるファイル // アップロードを実行 TransferObserver observer = transferUtility.upload(bucketName, objectKey, fileToUpload); // 転送状況の監視リスナーを設定 observer.setTransferListener(new TransferListener() {     @Override     public void onStateChanged(int id, TransferState state) {         // アップロードの状態が変わるたびに呼ばれます         Log.d("S3Upload", "ID: " + id + ", 状態: " + state);         if (TransferState.COMPLETED == state) {             Log.d("S3Upload", "アップロード完了!S3に保存されました!");             // 例: UIを更新して「アップロード成功!」と表示する         } else if (TransferState.FAILED == state) {             Log.e("S3Upload", "アップロード失敗しました。ネットワークを確認してください。");             // 例: エラーメッセージを表示する         } else if (TransferState.WAITING_FOR_NETWORK == state) {             Log.i("S3Upload", "ネットワーク接続を待機中です...");             // 例: 「インターネット接続がありません。回復次第再開します」とユーザーに伝える         }     }     @Override     public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {         // 転送の進捗状況が変わるたびに呼ばれます         float percent = ((float) bytesCurrent / (float) bytesTotal) * 100;         Log.d("S3Upload", "ID: " + id + ", 進捗: " + String.format("%.2f%%", percent) +                           " (" + bytesCurrent + "/" + bytesTotal + " バイト)");         // 例: プログレスバーの値を更新する     }     @Override     public void onError(int id, Exception ex) {         // エラーが発生したときに呼ばれます         Log.e("S3Upload", "アップロード中に予期せぬエラーが発生しました。", ex);     } });  | 
					
TransferUtilityでのアップロードの肝は、以下の3つです。
TransferObserver: アップロード処理そのものを表すオブジェクトです。アップロードの現在の状態や進捗を「監視」できます。TransferListener: アップロードの状況に変化があったときに通知を受け取るための仕組みです。これをTransferObserverに設定することで、「アップロードが始まった」「半分進んだ」「終わった」といったイベントをアプリ側で検知できるようになります。transferUtility.upload()メソッドを呼び出すだけでアップロード処理が開始されます。引数には、アップロード先のS3バケット名、S3に保存する際のファイル名(オブジェクトキー)、そしてアップロードしたいファイル本体を渡します。
| 
					 1  | 
						TransferObserver observer = transferUtility.upload(bucketName, objectKey, fileToUpload);  | 
					
TransferListenerには、今回の例では以下の3つのコールバックメソッドを実装しております。
onStateChanged(int id, TransferState state): アップロードの状態が変化したときに呼び出されます。例えば、COMPLETED(完了)、FAILED(失敗)、WAITING_FOR_NETWORK(ネットワーク待機中)、IN_PROGRESS(進行中)など、さまざまな状態を検知して、アプリの表示を更新したり、次の処理に進んだりできます。onProgressChanged(int id, long bytesCurrent, long bytesTotal): アップロードの進捗状況に変化があったときに呼び出されます。現在転送されたバイト数(bytesCurrent)と全体のバイト数(bytesTotal)が提供されるので、これを使ってプログレスバーを更新するなど、進捗を視覚的わかります。onError(int id, Exception ex): アップロード中に予期せぬエラーが発生したときに呼び出されます。ここでエラーの内容をログに出力したり、エラーが発生したことを伝えたりする処理を実装します。
3. まとめ
今回は、TransferUtility を使った AWS S3 へのファイルアップロードについてご紹介させていただきました。実際に利用してみて、裏側で自動的に行われるマルチパートアップロードや、非同期処理によるアプリケーションの応答性維持、そしてリアルタイムな進捗監視といった機能が、とても便利だと感じました。今後もAWSの学習を進めていきたいと思います。
エコモットでは、ともに未来の常識を創る仲間を募集しています。
弊社に少しでも興味がある方はぜひ下記の採用ページをご覧ください!
      


