본문 바로가기
ReactNative :

[FN] 게시판 개발 일지[4] / image-picker를 사용한 AWS S3 이미지 업로드

by 밍코딩코 2025. 2. 5.

이미지 업로드가 계속 실패하는 문제 때문에 오랜 시간 붙잡고 있다가 결국 해결해서 정리함

(ReactNative Cli TypeScript 프로젝트)

 

▼ S3와 IAM 관련 설정은 아래 게시글을 참고 ▼

 

[FN] AWS S3, AWS IAM

게시글을 작성 후 Firebase database에 게시글 데이터는 잘 저장이 된다.이제 게시글에 사용자가 이미지를 등록하는 기능을 추가하려고 하는데. Firebase Storage도 있지만,나는 AWS S3를 사용하여 구현하

codingco.tistory.com

image-picker(사진 선택) 관련 설명은 아래 게시글을 참고 ▼

 

 

[FN] 게시판 개발 일지[3] / image-picker

이전 글에서 AWS S3 관련 설정을 다했으니 이제는 게시글에 사진을 등록하고 불러오고 등 구현해보자과정은 사용자가 게시글을 작성할 때 사진을 등록 -> 게시글 작성 -> 사진은 AWS S3에 업로드 ->

codingco.tistory.com

 

1.  .env

선택된 사진을 AWS S3에 업로드하기 위해서는 프로젝트 루트 폴더에 .env 라는 파일을 만들고 거기에 민감한 엑세스 키, 비밀 키를 정의하고 .gitignore에 .env 를 정의하여 깃허브에 올라가지 않도록 해야한다.

깃허브에 민감한 정보를 push 하면서 깃허브에서 자동으로 막아버림..

 

.env

S3_BUCKET=
REGION=
AWS_ACCESS=
AWS_SECRET=

 

다음으로는 types 폴더를 하나 생성하고 env.d.ts 파일을 생성해서 아래 코드처럼 작성 후 ImageUploader.tsx 에서 @env를 import 하여 사용한다.

 

.env.d.ts

declare module '@env' {
    export const S3_BUCKET: string;
    export const REGION: string;
    export const AWS_ACCESS: string;
    export const AWS_SECRET: string;
  }

 

이후에는 babel.config.js 코드를 수정한다. 추가하기전에 dotenv는 install 해주고 아래처럼 dotenv 코드를 추가해야함. 

 

babel.config.js

module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    '@babel/plugin-transform-class-static-block',
    [
      'module:react-native-dotenv',
      {
        moduleName: '@env',
        path: '.env',
        safe: false,
        allowUndefined: true,
      },
    ],
  ],
};

 

마지막으로 tsconfig.json 코드를 아래처럼 paths를 추가해준다.

{
  "extends": "@react-native/typescript-config/tsconfig.json",
  "compilerOptions": {
    "lib": ["esnext", "dom"],
    "strict": true,
    "baseUrl": "./",
    "paths": {
      "@env": ["node_modules/react-native-dotenv"]
    }
  }
}

 

2. 게시글 작성 페이지

게시글 작성 페이지에서 이미지 업로드 관련 import 해야할 부분은 다음과 같다.

  • ImageUploader : 이미지 선택, 삭제, 수정 컴포넌트
  • @aws-sdk/client-s3 : AWS S3와 상호작용할 때 사용
  • '@env' : 앞에서 설명했듯이 S3 버킷 관련 민감한 정보들을 .env에 정의하고 가져와서 사용
  • RNFS : S3에 업로드할 때 이미지를 Base64로 변환해야 하는데, 이를 도와줌
  • Buffer : Base64로 변환된 이미지 데이터를 바이너리 형태로 변환 / S3 업로드할 때 사용해야 할 수도

그리고 가장 애를 많이 먹었던 url 관련 업로드 실패 에러를 해결해 준 react-native-url-polyfill, react-native-get-random-values, uuid 이 세가지 때문에 이미지 업로드 성공

import ImageUploader from "../component/MeetingComponent/ImageUploader";
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { S3_BUCKET, REGION, AWS_ACCESS, AWS_SECRET } from '@env';
import RNFS from 'react-native-fs';
import { Buffer } from "buffer";
import 'react-native-url-polyfill/auto';
import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';

 

 .env에 정의한 값들로 S3Client를 초기화 해준다.

const s3Client = new S3Client({
  region: REGION,
  credentials: {
    accessKeyId: AWS_ACCESS,
    secretAccessKey: AWS_SECRET,
  },
});

 

  • imageUri : 선택한 이미지의 경로를 전달 받음.
  • imageUri.split('/').pop() : 이미지 URI 마지막 부분을 가져와서 파일 이름을 추출함
  • file:// 을 제거하여 로컬 경로로 변환
  • RNFS.readFile : AWS S3에 업로드하기 위해 파일을 Base64 문자열로 변환
  • binaryData : Base64 인코딩된 데이터를 버퍼(Binary) 형식으로 변환 / AWS S3 업로드 시 텍스트가 아닌 바이너리 데이터를 전송해야 함.
  • result : S3로 이미지 업로드 실행하고 성공하면 result에 업로드 결과 저장
  • 성공 시 이미지 URL 반환 / 반환된 URL은 firestore database에 저장하여 나중에 게시판이나 게시글에서 이미지를 불러올 때 사용
const uploadImageToS3 = async (imageUri: string) => {
    try {
      console.log('선택된 이미지 경로:', imageUri);
  
      const fileName = imageUri.split('/').pop(); 
      const filePath = imageUri.replace('file://', ''); 
  
      const base64Image = await RNFS.readFile(filePath, 'base64');
  
      const binaryData = Buffer.from(base64Image, 'base64');
  
      const uploadParams = {
        Bucket: S3_BUCKET,
        Key: fileName,
        Body: binaryData,  
        ContentType: 'image/jpeg',
      };
  
      const result = await s3Client.send(new PutObjectCommand(uploadParams));
      console.log("이미지 업로드 성공:", result);
  
      Alert.alert("이미지 업로드 성공", `파일 이름: ${fileName}`);
  
      return `https://${S3_BUCKET}.s3.${REGION}.amazonaws.com/${fileName}`;
    }

 

사진을 선택하고 게시글을 선택했을 때 정상적으로 S3에 이미지가 업로드된다. fn_logo는 이미지를 선택하지 않고 작성된 게시글에 띄울 기본 이미지이다.

 

Firestore Database에도 게시글 내용들뿐만 아니라 S3에 업로드된 이미지 url을 잘 저장함 - 나중에 이미지를 불러올 때 이미지 url을 불러오면 된다

 

사진을 선택하지 않은 게시글과 사진을 선택한 게시글이 게시판에 잘 출력된다