블로그 목록
apps

expo-camera로 앱에 카메라 화면 직접 붙이기 — CameraView로 사진 촬영하기

사진을 받는 가장 쉬운 방법은 expo-image-picker로 시스템 카메라를 띄우는 거다. 근데 그건 OS 기본 촬영 화면으로 튕겼다가 돌아오는 구조라, 앱 안에 촬영 UI를 그대로 두고 싶거나 프리뷰 위에 가이드선·오버레이를 얹고 싶으면 안 맞는다. 명함 스캔이나 얼굴 등록처럼 "앱 화면 안에서 바로 찍는" 경험이 필요할 때는 expo-camera로 카메라 프리뷰를 직접 붙여야 한다.

예전 Camera 컴포넌트는 deprecated 됐고, 지금은 CameraView로 갈아타야 한다. 처음에 옛날 예제 보고 Camera로 짰다가 경고만 잔뜩 봤다.

설치

npx expo install expo-camera

app.json 플러그인에 권한 설명 문구를 넣어두면 iOS 심사에서 막히지 않는다.

{
  "plugins": [
    ["expo-camera", { "cameraPermission": "사진 촬영을 위해 카메라를 사용합니다." }]
  ]
}

권한부터 처리하기

카메라는 권한이 핵심이다. useCameraPermissions 훅이 상태와 요청 함수를 같이 돌려줘서 편하다. 권한이 없는 상태를 화면으로 꼭 처리해야 한다. 그냥 비워두면 검은 화면만 뜨고 사용자는 앱이 멈춘 줄 안다.

import { CameraView, useCameraPermissions } from 'expo-camera';

const [permission, requestPermission] = useCameraPermissions();

if (!permission) return <View />; // 아직 로딩 중
if (!permission.granted) {
  return (
    <View>
      <Text>카메라 권한이 필요합니다.</Text>
      <Button title="권한 허용" onPress={requestPermission} />
    </View>
  );
}

프리뷰와 촬영

CameraView에 ref를 달고 takePictureAsync()를 호출하면 끝이다. facing으로 전면·후면을 토글한다.

const cameraRef = useRef<CameraView>(null);
const [facing, setFacing] = useState<'back' | 'front'>('back');
const [photo, setPhoto] = useState<string | null>(null);

async function takePhoto() {
  const result = await cameraRef.current?.takePictureAsync({ quality: 0.7 });
  if (result) setPhoto(result.uri);
}

// <CameraView ref={cameraRef} style={{ flex: 1 }} facing={facing} />
// <Button title="전환" onPress={() => setFacing(f => (f === 'back' ? 'front' : 'back'))} />
// <Button title="촬영" onPress={takePhoto} />

takePictureAsync가 돌려주는 uri는 앱 캐시 디렉토리의 임시 파일이다. 서버 업로드나 저장이 필요하면 그 uri를 FormData에 넣거나 expo-file-system으로 옮기면 된다. quality를 1로 두면 파일이 꽤 커지니 업로드할 거면 0.6~0.7 정도가 적당했다.

정리

  • 옛 Camera는 버리고 CameraView + useCameraPermissions 조합으로 간다.
  • 권한 미허용 상태를 반드시 별도 화면으로 처리한다. 검은 화면은 버그로 보인다.
  • 단순히 사진 한 장 받는 거면 expo-image-picker가 더 빠르다. 프리뷰 위에 오버레이를 얹거나 촬영 흐름을 직접 통제해야 할 때만 CameraView를 꺼낸다.

도구를 고를 때 "앱 안에서 UI를 통제할 필요가 있나"를 먼저 따져보면 둘 중 뭘 쓸지 바로 갈린다.