블로그 목록
앱

expo-screen-capture로 민감한 화면 캡처 막기 — 스크린샷·화면 녹화 차단하고 감지하기

결제 내역이나 일회용 비밀번호 같은 화면을 다루다 보면, 이걸 그대로 스크린샷으로 남겨도 되나 싶은 순간이 온다. 금융·헬스케어 쪽 앱 심사에서는 아예 민감한 화면 캡처 방지를 요구하기도 한다. 직접 네이티브 모듈을 건드리자니 Android는 FLAG_SECURE, iOS는 화면 녹화 감지 API를 따로 다뤄야 해서 부담스러웠는데, expo-screen-capture가 이걸 한 번에 감싸준다.

설치

npx expo install expo-screen-capture

개발 빌드나 EAS Build가 필요하다. Expo Go에서는 네이티브 플래그가 동작하지 않으니 참고.

특정 화면에서만 캡처 막기

가장 깔끔한 방법은 훅이다. 화면이 포커스될 때 막고, 벗어나면 자동으로 푼다.

import { usePreventScreenCapture } from 'expo-screen-capture';

function PaymentScreen() {
  usePreventScreenCapture();

  return <ReceiptDetail />;
}

이 한 줄이면 Android에서는 스크린샷·최근 앱 미리보기·화면 녹화가 다 막히고, iOS에서는 녹화 중일 때 화면이 가려진다. 컴포넌트가 언마운트되면 알아서 해제되니까 "다른 화면 가니 캡처가 계속 막혀 있더라" 같은 실수가 안 생긴다.

전역으로 켜고 끄고 싶으면 함수형 API도 있다.

import {
  preventScreenCaptureAsync,
  allowScreenCaptureAsync,
} from 'expo-screen-capture';

await preventScreenCaptureAsync();
// ...민감한 작업...
await allowScreenCaptureAsync();

막지 말고 "감지"만 하기

iOS 스크린샷은 OS 차원에서 완전히 막을 수 없다. 대신 캡처가 일어난 직후에 이벤트를 받을 수 있어서, 경고를 띄우거나 서버에 로그를 남기는 식으로 대응한다. 권한을 먼저 요청해야 콜백이 온다.

import { useEffect } from 'react';
import * as ScreenCapture from 'expo-screen-capture';
import { Alert } from 'react-native';

function useScreenshotWarning() {
  useEffect(() => {
    let sub: ScreenCapture.Subscription;
    (async () => {
      const { status } = await ScreenCapture.requestPermissionsAsync();
      if (status !== 'granted') return;
      sub = ScreenCapture.addScreenshotListener(() => {
        Alert.alert('안내', '이 화면은 캡처 공유를 삼가주세요.');
      });
    })();
    return () => sub?.remove();
  }, []);
}

정리

  • 민감한 화면만 보호하고 싶으면 usePreventScreenCapture() 한 줄이 제일 안전하다. 해제를 깜빡할 일이 없다.
  • Android는 캡처 자체를 막을 수 있지만, iOS 스크린샷은 못 막으니 addScreenshotListener로 감지해 안내하는 쪽으로 설계하자.
  • 리스너는 권한 요청이 선행돼야 하고, 언마운트 때 remove()로 꼭 정리할 것.

캡처를 100% 봉쇄하는 기능이 아니라, 플랫폼이 허용하는 선에서 막고 나머지는 감지해 대응하는 도구라고 생각하면 기대치가 맞다.