Use Cases (업데이트: 2026. 6. 2.)

Claude Code와 React Native 실전 가이드: Expo, 네이티브, 릴리스 점검

Claude Code로 React Native를 안전하게 개발하는 법. Expo 선택, 권한, Metro, 에뮬레이터, 접근성, 릴리스 점검.

Claude Code와 React Native 실전 가이드: Expo, 네이티브, 릴리스 점검

Claude Code에 맡기기 전에 모바일 경계를 정한다

React Native에서 Claude Code가 유용한 이유는 화면 하나를 빠르게 만드는 데서 끝나지 않습니다. 프로젝트를 읽고, TypeScript를 수정하고, 검증 명령을 실행하고, 네이티브 재빌드가 필요한지 설명하고, 마지막에 검증 기록까지 남길 수 있기 때문입니다. 모바일 개발은 일반 Web 컴포넌트보다 경계가 많습니다. iOS 권한 문구, Android package, Metro 해석 오류, development build, 에뮬레이터 차이, 접근성, 릴리스 전 점검이 모두 연결됩니다.

약한 요청은 “React Native 앱 만들어줘”입니다. 좋은 요청은 이 프로젝트가 Expo인지, Expo development build가 필요한지, 아니면 ios/android/를 직접 관리하는 bare React Native인지 먼저 말합니다. 그리고 수정 가능한 파일, 확인이 필요한 명령, 반드시 테스트할 기기를 명시합니다.

공식 기준은 Claude Code overview, Claude Code permissions, Expo Documentation, Expo development builds, React Native environment setup, React Native Native Modules, Metro troubleshooting, React Native accessibility입니다. Claude Code가 처음이라면 Claude Code 시작 가이드를 먼저 보고, 팀에서는 권한 설정 가이드로 운영 경계를 잡는 것이 좋습니다.

project map부터 만든다

project map은 agent에게 주는 짧은 운영 설명서입니다. 여기서 harness는 “에이전트의 작업 발판”이라는 뜻입니다. Claude Code가 어디까지 움직여도 되는지, 성공을 어떻게 확인할지, 어떤 동작은 자동으로 하면 안 되는지 정합니다. 이 지도가 없으면 Claude Code는 동작하는 코드를 만들 수는 있지만, 네이티브 재빌드나 플랫폼 차이, 릴리스 제약을 놓치기 쉽습니다.

flowchart LR
  A["Project map"] --> B["Claude Code task"]
  B --> C["JS/TS implementation"]
  B --> D["Native config"]
  C --> E["Metro and unit tests"]
  D --> F["Dev build / emulator"]
  E --> G["Accessibility check"]
  F --> G
  G --> H["Release checklist"]

실제 작업 전에는 다음 정도의 메모면 충분합니다.

# React Native task map

App type: Expo app using TypeScript and Expo Router.
Native runtime: Expo Go for pure JS changes, development build for native libraries.
Targets: Android emulator first, iOS simulator on macOS before release.
Allowed files: app/, components/, hooks/, app.config.ts, metro.config.js, __tests__/.
Do not change: package manager, app slug, bundle identifiers, signing files, .env files.
Verification: npm run lint, npm test, npx expo-doctor, Android emulator smoke test.
Handoff: list changed files, commands run, platform not tested, and any native rebuild needed.

최신 Expo 템플릿은 AI coding agent를 위한 컨텍스트 파일을 포함할 수 있습니다. 그래도 기존 앱에는 오래된 README, 이전 Expo SDK 전제, 정리되지 않은 네이티브 설정이 섞여 있을 수 있습니다. 일반 튜토리얼보다 실제 저장소를 먼저 읽히는 편이 안전합니다.

Expo와 bare React Native를 의식적으로 선택한다

React Native 공식 문서는 프레임워크를 쓰는 경로와 Android Studio/Xcode를 직접 설정하는 경로를 구분합니다. 새 앱은 Expo가 빠른 경우가 많고, 이미 네이티브 SDK, 복잡한 Gradle, Pod 설정, 벤더 요구가 있는 앱은 bare React Native가 현실적입니다.

판단 기준Expo가 맞는 경우bare React Native가 맞는 경우
시작 속도신규 MVP, 내부 도구, 학습 프로젝트, Expo SDK로 충분한 기능기존 iOS/Android 코드를 유지해야 함
네이티브 기능Camera, SecureStore, 알림, config plugin으로 가능한 설정커스텀 SDK, 결제 단말, 특수 Bluetooth, 세밀한 빌드 설정
Claude Code 범위주로 app/, components/, app.config.ts, 테스트ios/, android/, Codegen, Pods, Gradle, 생성 파일
검증Expo Go 또는 development build, npx expo-doctornpm run android, pod install, Xcode/Android Studio 빌드

Expo Go에서 동작했다고 릴리스도 안전하다고 보면 안 됩니다. Expo 문서에서 Expo Go는 고정된 네이티브 라이브러리를 가진 빠른 실험 환경으로 설명됩니다. 네이티브 코드가 포함된 라이브러리를 추가하면 development build를 쓰고, Claude Code가 새 바이너리 필요 여부를 보고하게 해야 합니다.

깨끗한 Expo 테스트 프로젝트는 이렇게 시작합니다.

npx create-expo-app@latest rn-claude-lab
cd rn-claude-lab
npx expo install expo-camera expo-secure-store @react-native-community/netinfo
npm install --save-dev @testing-library/react-native jest-expo @types/jest
npx expo start

Android Emulator는 a, macOS의 iOS Simulator는 i로 엽니다. 네트워크가 막힌 환경에서는 npx expo start --tunnel을 쓸 수 있지만, 보통 LAN이나 에뮬레이터보다 느립니다.

모바일 작업에 맞게 Claude Code 권한을 좁힌다

React Native 프로젝트에서는 명령 하나가 큰 부작용을 만들 수 있습니다. expo prebuild, pod install, gradlew clean, eas build는 필요한 순간이 있지만, 작은 UI 수정 중에 조용히 실행되면 안 됩니다.

Claude Code permissions는 allow, ask, deny를 나눌 수 있습니다. 공유 .claude/settings.json에서는 안전한 확인 명령을 허용하고, 네이티브 재생성과 릴리스 빌드는 확인을 받으며, secrets와 push 명령을 막는 방식이 좋습니다.

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Bash(npm test)",
      "Bash(npm run lint)",
      "Bash(npx expo-doctor)",
      "Bash(adb devices)"
    ],
    "ask": [
      "Edit",
      "Bash(npx expo prebuild*)",
      "Bash(eas build*)",
      "Bash(cd ios && bundle exec pod install)"
    ],
    "deny": [
      "Read(.env)",
      "Read(.env.local)",
      "Bash(git push*)",
      "Bash(rm -rf*)"
    ]
  }
}

이 설정은 도구를 믿지 않는다는 의미가 아닙니다. 모바일 특유의 넓은 부작용을 리뷰 가능한 단위로 묶기 위한 장치입니다. 네이티브 재빌드가 필요하면 Claude Code가 먼저 이유를 말해야 합니다.

카메라 권한 화면을 구현한다

첫 번째 실제 예시는 체크인, 재고 관리, 내부 도구에서 자주 쓰는 QR 스캐너입니다. Expo Camera는 CameraViewuseCameraPermissions를 제공합니다. Claude Code에는 권한 확인 중, 미허용, 카메라 사용 가능 상태를 분리하고, accessibility label을 넣고, 스캔 후 중복 발화를 막으라고 요청합니다.

// components/CameraQrCheck.tsx
import { CameraView, useCameraPermissions } from 'expo-camera';
import { useState } from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';

type ScanResult = {
  data: string;
  type: string;
} | null;

export function CameraQrCheck() {
  const [permission, requestPermission] = useCameraPermissions();
  const [scan, setScan] = useState<ScanResult>(null);

  if (!permission) {
    return (
      <View style={styles.center}>
        <Text>Checking camera permission...</Text>
      </View>
    );
  }

  if (!permission.granted) {
    return (
      <View style={styles.center}>
        <Text style={styles.title}>Camera access is required</Text>
        <Text style={styles.body}>
          Allow camera access to scan QR codes on this device.
        </Text>
        <Pressable
          accessibilityRole="button"
          accessibilityLabel="Allow camera access"
          disabled={!permission.canAskAgain}
          onPress={requestPermission}
          style={({ pressed }) => [
            styles.button,
            pressed && styles.buttonPressed,
            !permission.canAskAgain && styles.buttonDisabled,
          ]}
        >
          <Text style={styles.buttonText}>Allow camera</Text>
        </Pressable>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <CameraView
        style={styles.camera}
        barcodeScannerSettings={{ barcodeTypes: ['qr'] }}
        onBarcodeScanned={
          scan
            ? undefined
            : ({ data, type }) => {
                setScan({ data, type });
              }
        }
      />
      <View style={styles.result}>
        <Text accessibilityLiveRegion="polite" style={styles.title}>
          {scan ? `Scanned ${scan.type}` : 'Point the camera at a QR code'}
        </Text>
        {scan ? <Text selectable>{scan.data}</Text> : null}
        {scan ? (
          <Pressable
            accessibilityRole="button"
            accessibilityLabel="Scan another QR code"
            onPress={() => setScan(null)}
            style={styles.button}
          >
            <Text style={styles.buttonText}>Scan again</Text>
          </Pressable>
        ) : null}
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: '#111827' },
  center: { flex: 1, justifyContent: 'center', gap: 12, padding: 24 },
  camera: { flex: 1 },
  result: { gap: 12, padding: 16, backgroundColor: '#f9fafb' },
  title: { fontSize: 18, fontWeight: '700', color: '#111827' },
  body: { fontSize: 15, lineHeight: 22, color: '#374151' },
  button: {
    alignItems: 'center',
    borderRadius: 8,
    backgroundColor: '#2563eb',
    paddingHorizontal: 16,
    paddingVertical: 12,
  },
  buttonPressed: { opacity: 0.75 },
  buttonDisabled: { backgroundColor: '#9ca3af' },
  buttonText: { color: '#ffffff', fontWeight: '700' },
});

expo-camera 설치 후 Expo 프로젝트에 바로 붙일 수 있습니다. 다만 권한 문구와 네이티브 설정은 app config에 남겨야 합니다. 일부 변경은 JavaScript reload가 아니라 새 native build가 필요합니다.

// app.config.ts
import type { ConfigContext, ExpoConfig } from 'expo/config';

export default ({ config }: ConfigContext): ExpoConfig => ({
  ...config,
  name: config.name ?? 'rn-claude-lab',
  slug: config.slug ?? 'rn-claude-lab',
  ios: {
    ...config.ios,
    bundleIdentifier: 'com.example.rnclaudelab',
    infoPlist: {
      ...config.ios?.infoPlist,
      NSCameraUsageDescription: 'Scan QR codes for check-in.',
    },
  },
  android: {
    ...config.android,
    package: 'com.example.rnclaudelab',
    permissions: ['CAMERA'],
  },
  plugins: ['expo-camera'],
});

Expo config plugins는 prebuild와 native build 흐름에서 설정을 반영합니다. Claude Code에 “app.config.ts를 수정하면 development build가 필요한지 반드시 보고하라”고 요청하면, Expo Go에서는 됐지만 내부 배포 빌드에서 실패하는 일을 줄일 수 있습니다.

Metro 오류는 잡음이 아니라 증거다

두 번째 실제 예시는 Metro의 Unable to resolve module 오류입니다. monorepo에서 특히 자주 발생합니다. Metro 공식 troubleshooting에는 cache reset이 있지만, 캐시 삭제는 진단의 전부가 아니라 첫 정리 단계입니다.

Claude Code에는 전체 오류, 실행 명령, 패키지 매니저, workspace 구조, 직전에 이동한 파일을 함께 줍니다. workspace 안의 Expo 앱은 다음 설정이 필요할 수 있습니다.

// metro.config.js
const path = require('path');
const { getDefaultConfig } = require('expo/metro-config');

const projectRoot = __dirname;
const workspaceRoot = path.resolve(projectRoot, '..');

const config = getDefaultConfig(projectRoot);

config.watchFolders = [workspaceRoot];
config.resolver.nodeModulesPaths = [
  path.resolve(projectRoot, 'node_modules'),
  path.resolve(workspaceRoot, 'node_modules'),
];

module.exports = config;

무조건 추가하면 안 됩니다. 일반 단일 패키지 Expo 앱에는 보통 필요 없습니다. Claude Code가 왜 watchFolders가 필요한지 설명하게 하고, 원인이 대소문자, 빠진 dependency, 오래된 Babel 설정, 잘못된 import라면 Metro 설정을 건드리지 않게 합니다.

네이티브 모듈은 코드보다 계획부터

세 번째 예시는 벤더 SDK나 플랫폼 API를 연결하는 작업입니다. React Native의 현재 Native Modules 문서는 Turbo Native Modules와 Codegen을 중심으로 설명합니다. 따라서 좋은 요청은 TypeScript 인터페이스를 먼저 고정하고, 그 다음 Android와 iOS 구현으로 넘어갑니다.

Camera, SecureStore, NetInfo처럼 Expo SDK로 충분하면 커스텀 native module을 만들지 않습니다. 결제 단말, 특수 Bluetooth, 사내 인증 SDK처럼 대체가 없을 때만 bare React Native나 Expo Modules를 검토합니다.

Implement a native bridge plan, not the full code yet.

Goal: expose a device serial reader to TypeScript.
First output:
1. TypeScript interface and error model.
2. Android/iOS files that would need edits.
3. Build commands for each platform.
4. Risks: permissions, threading, simulator limitations, release signing.
Do not edit ios/ or android/ until the plan is reviewed.

처음 10분은 느려 보여도 전체 작업은 빨라집니다. Kotlin, Swift, Pods, Gradle diff는 리뷰 비용이 높으므로 경계를 먼저 정해야 합니다.

테스트와 접근성을 같은 작업에 넣는다

React Native accessibility API는 VoiceOver와 TalkBack 같은 보조 기술에 정보를 전달합니다. 접근 가능한 View라면 label과 role은 마지막 장식이 아니라 구현 조건입니다.

먼저 권한이 없는 상태의 단위 테스트를 고정합니다.

// __tests__/CameraQrCheck.test.tsx
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react-native';
import { CameraQrCheck } from '../components/CameraQrCheck';

const mockRequestPermission = jest.fn();

jest.mock('expo-camera', () => ({
  CameraView: 'CameraView',
  useCameraPermissions: () => [
    { granted: false, canAskAgain: true },
    mockRequestPermission,
  ],
}));

describe('CameraQrCheck', () => {
  beforeEach(() => {
    mockRequestPermission.mockClear();
  });

  it('requests camera permission from the empty state', () => {
    render(<CameraQrCheck />);

    fireEvent.press(screen.getByText('Allow camera'));

    expect(mockRequestPermission).toHaveBeenCalledTimes(1);
  });
});

그 다음 실제 기기나 에뮬레이터에서 권한 다이얼로그, 거부 후 경로, 회전, 어두운 환경 스캔, 스크린 리더 라벨을 확인합니다. 핸드오프에는 어떤 플랫폼을 테스트했는지 써야 합니다. “Android emulator passed, iOS not tested”는 의미가 있고, “looks good”은 의미가 없습니다.

릴리스 전 체크를 명령으로 고정한다

React Native의 Dev Menu와 LogBox는 개발 도구이며 release build에서는 동작이 다릅니다. Claude Code는 완료 문장만 주는 것이 아니라 명령 결과를 함께 반환해야 합니다.

npm run lint
npm test -- --runInBand
npx expo-doctor
npx expo start -c
adb devices
adb shell input keyevent 82
npx expo run:android
# macOS only:
npx expo run:ios

EAS Build를 쓴다면 development, preview, production profile을 분리합니다. 작업이 명시하지 않는 한 bundle identifier, Android package, signing files, production profile은 Claude Code가 바꾸지 않게 해야 합니다.

실제 유스케이스와 실패 패턴

첫 번째 유스케이스는 신규 Expo MVP입니다. 로그인, QR 스캔, 안전한 로컬 저장, 간단한 API 연동, 내부 운영 화면은 screen, hook, test, config로 나누면 좋습니다. 매출과 연결되는 앱이라면 analytics와 CTA도 완료 조건에 넣습니다.

두 번째는 기존 bare React Native 앱의 오류 수정입니다. Metro 오류, Android에서만 발생하는 crash, iOS 권한 문구, native SDK 업그레이드는 Claude Code에 잘 맞습니다. 단, 오류 분류, 최소 diff, native rebuild 필요 여부를 반드시 요구해야 합니다.

세 번째는 native SDK 도입 전 조사입니다. 결제, 건강 데이터, Bluetooth, 엔터프라이즈 인증은 지원 OS, 권한, 스토어 심사 위험, simulator 한계, 테스트 기기 표를 먼저 만들어야 합니다. review workflow checklistTDD guide를 함께 쓰면 누락이 줄어듭니다.

반복되는 실패는 명확합니다. Expo Go 성공은 릴리스 증거가 아닙니다. cache reset은 root cause 분석이 아닙니다. 플랫폼 검증을 마지막으로 미루면 늦습니다. 접근성 label은 UI 리뷰 후에 붙이는 것이 아닙니다. native build 명령은 이유 없이 실행하면 안 됩니다. 이것은 AI 문제가 아니라 프로세스 문제입니다.

CTA: 모바일 워크플로를 템플릿화한다

React Native에서 가장 효과가 큰 것은 project map, permission file, verification command list, review checklist를 재사용 가능하게 만드는 것입니다. 개인 개발자는 무료 cheatsheet로 시작하고, 재사용 가능한 prompt와 설정 자료가 필요하면 ClaudeCodeLab products를 확인하세요. 실제 저장소에 Expo/bare React Native 규칙, CI, release gate, 팀 교육을 적용하려면 Claude Code training and consultation이 적합합니다.

함께 읽을 글로는 Claude Code React 개발 가이드Flutter/Dart 가이드가 있습니다.

이 흐름을 실제로 적용해 보니, Masa의 검증에서는 세 가지가 재작업을 가장 많이 줄였습니다. 구현 전에 Expo인지 bare인지 결정하기, app.config.ts 변경 시 development-build 메모를 요구하기, Android Emulator에서 권한과 Metro를 먼저 확인하기입니다. Camera와 SecureStore 같은 네이티브 기능에서는 코드 생성 속도보다 검증 경계가 더 중요했습니다.

#Claude Code #React Native #모바일 개발 #Expo #TypeScript
무료

무료 PDF: Claude Code 치트시트

이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.

개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.

Masa

작성자 소개

Masa

Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.