LoginSignup
2
1

More than 1 year has passed since last update.

Expo with React-NativeでカメラロールからファイルをS3にアップロード(署名付きURL/axios)

Posted at

概要

Expo + React-Nativeでカメラロールにある画像や動画をS3にアップロードしようとしたところ、
色々ハマったのでメモ

  • expo + react-native
  • カメラロールへのアクセスは ImagePicker を使う
  • S3は署名付きURLを使ってアップロード
  • axiosを使う

注)
S3署名付きURLとS3へのアップロードの部分についてはこの記事ではあまり触れません。
試している環境はあらかじめ、署名付きURLを発行するApi Gateway経由のLambdaで作成してあり、それを使っています

ハマったところ

ImagePickerで取得したデータがBlobじゃない

サブタイトルのとおり。

    const result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true,
      aspect: [4, 3],
      quality: 1
    })

こんな感じでファイルを取得するが、 result にはBlobを返してくれない

export declare type ImagePickerResult = {
    cancelled: true;
} | ({
    cancelled: false;
} & ImageInfo);


export declare type ImageInfo = {
    uri: string;
    width: number;
    height: number;
    type?: 'image' | 'video';
    exif?: {
        [key: string]: any;
    };
    base64?: string;
};

file uri は返却されているので、これを使ってBlobに変換する。
uri -> blobは fetch を使うことで変換できる
(React-Native周りでblob変換してくれるいいライブラリがないのでfetchで代用した)

const blob = await fetch(result.uri).then(r => r.blob())

axiosでBlobをS3にputしたらなぜかJSONファイルがアップロードされた

変換してできたBlobをaxiosでPUTしたら、S3にアップロードはされるものの
極端にサイズが小さい・・・

ダウンロードしてみると、JSONがアップロードされていた。なぜ・・・

試しに fetch でputしてみたらちゃんとアップロードされた


// これはちゃんとアップロードされる
await fetch(signedurl, {
  method: 'PUT',
  body: blob
})

// これだとblobでなくてJSON(!?)がアップロードされる
await axios.put(signedurl, blob, {})

悩みに悩んだ末、axiosがrequest bodyのblobを勝手に JSON.stringify()
parseしているんじゃないかと推察し、configでparseをやめさせてみたところうまくいった!


// request bodyはそのまま使え
await axios.put(signedurl, blob, {
  transformRequest: data => data,
})

出来上がり

抜粋版のソース


// カメラロールから選択したファイルを取得
const result = await ImagePicker.launchImageLibraryAsync({
  mediaTypes: ImagePicker.MediaTypeOptions.All,
  allowsEditing: true,
  aspect: [4, 3],
  quality: 1
})

// ファイルをblobに変換
const blob = await fetch(result.uri).then(r => r.blob())

// S3署名付きURLの取得
const signedurl = await axios.get('[s3の署名付きURLを取得するためのURL]')

// S3にアップロード
await axios.put(signedurl, blob, {
  transformRequest: data => data,
})

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1