스크린샷을 통해 모바일 앱을 React Native로 복제하는 도구를 만들었습니다
요약
스크린샷을 입력값으로 사용하여 모바일 앱 UI를 React Native 코드로 복제하는 새로운 도구를 소개합니다. 단순 생성을 넘어, 생성된 화면을 다시 스크린샷으로 찍어 원본과 비교하며 정밀도를 높이는 반복 루프 방식을 핵심 기술로 사용합니다.
핵심 포인트
- 스크린샷 기반의 이미지 입력을 통해 모바일 앱의 마크업 부재 문제를 해결
- 생성-렌더링-비교-수정의 반복 루프를 통해 UI 정밀도 극대화
- 내비게이션 크롬 분석을 통해 화면 간 이동 흐름(Tabs, Stack) 구현
- Expo Router 설정을 위한 app-spec.json 기반의 내비게이션 그래프 생성
스크린샷을 통해 모바일 앱을 React Native로 복제하는 도구를 만들었습니다
몇 주 전, 저는 앱을 복제하고 싶었습니다. 웹사이트가 아니라 실제 모바일 앱 말입니다. 그리고 이것이 완전히 다른 문제이며, 이에 대한 좋은 해결책이 아무도 가지고 있지 않다는 것을 매우 빠르게 깨달았습니다.
상황은 이렇습니다. 웹사이트를 복제하는 것은 이제 기본적으로 해결된 잔재주에 불과합니다. 개발자 도구(dev tools)를 열면 DOM 전체가 그곳에 있고, CSS, 폰트, 에셋 URL(asset URLs)이 모두 있습니다. 모델이 그 모든 것을 읽고 복사본을 내뱉습니다. 이를 매우 잘 수행하는 도구들도 있습니다.
하지만 모바일 앱은 그 어떤 것도 제공하지 않습니다. 읽을 마크업(markup)도 없고, 복사할 스타일시트(stylesheet)도 없습니다. 당신이 얻는 것은 픽셀(pixels)뿐입니다. 그게 전부입니다. 따라서 모든 웹사이트 복제 기술은 iOS나 Android 앱을 대상으로 하는 순간 무용지물이 됩니다.
그래서 저는 어떤 앱에서든 항상 얻을 수 있는 것이 무엇인지 스스로에게 물었습니다. 답은 다소 멍청해 보일 수 있지만, 이것이 전체 아이디어의 핵심입니다. 바로 스크린샷(screenshots)입니다. 앱은 언제나 스크린샷을 찍을 수 있습니다. 탈옥(jailbreak)도, 디컴파일(decompiling)도, SDK도 필요 없습니다. iPhone 앱의 스크린샷과 Android 앱의 스크린샷은 저에게 똑같은 것, 즉 이미지(image)입니다.
그래서 스크린샷이 입력값(input)이 되었습니다.
스크린샷의 문제점
이미지에는 숫자가 없습니다. PNG 파일에서 "16px 패딩(padding)"을 읽어낼 수는 없으며, 추측해야만 합니다. 그리고 모델이 한 번 추측하게 내버려 두면, 누구나 본 적 있는 현상이 발생합니다. 느낌은 비슷하고 분위기는 맞지만, 간격(spacing)이 어긋나고 색상이 약간 틀려서 짝퉁처럼 느껴지는 것입니다.
따라서 이 도구의 핵심은 "화면을 생성하는" 단계가 아닙니다. 그것은 루프(loop)입니다. 화면을 구축하고, 렌더링(render)하고, 자신의 출력물을 스크린샷으로 찍은 뒤, 이를 원본과 나란히 놓고 차이점이 있는 부분을 수정합니다. 그런 다음 다시 반복하며, 두 개가 실제로 일치할 때까지 계속 진행합니다. 이 루프가 웹에서는 DOM이 무료로 제공했을 측정 작업을 수행하는 것입니다.
사람들이 계속해서 영리한 부분이라고 부르는 것이 바로 이 부분이며, 솔직히 이 부분이 결과물이 AI 슬롭(AI slop, AI가 생성한 저질 콘텐츠)처럼 보이는 것을 막아줍니다.
내비게이션 (Navigation)
출시 당일에 누군가 정적 스크린샷만으로는 한 화면에서 다음 화면으로 어떻게 이동했는지 알 수 없는데, 내비게이션 (Navigation)은 어떻게 처리하느냐고 물었습니다. 타당한 질문이며, 이 부분이 가장 어려운 지점입니다.
스크린샷의 순서를 따르지는 않습니다. 그것은 너무 신뢰할 수 없기 때문입니다. 대신 내비게이션 크롬 (navigation chrome)을 읽습니다. 여러 스크린샷에 걸쳐 하단 바가 지속적으로 나타나면 탭 (tabs)을 의미합니다. 헤더에 뒤로 가기 셰브론 (back chevron)이 있으면 스택 푸시 (stack push)를 의미합니다. 또한 레이블 (labels)을 매칭하므로, "Settings"라고 적힌 행은 헤더에 "Settings"라고 적힌 화면으로 연결됩니다. 이 모든 정보는 단 하나의 화면이 빌드되기 전에 app-spec.json (내비게이션 그래프, 토큰 및 스크린 포함)에 저장되며, Expo Router 설정은 해당 그래프로부터 생성됩니다.
조건부 흐름 (Conditional flows)은 여전히 취약한 부분이며, 저는 이 점을 솔직하게 인정합니다. 특정 상태에서만 도달할 수 있는 화면은 힌트가 필요하며, 그렇지 않으면 근사치로 처리됩니다.
제가 실제로 신경 쓴 부분
대부분의 이러한 도구들은 작동하지 않는 빈 껍데기(dead shell) 단계에서 멈춥니다. 화면은 렌더링되지만, 어떤 버튼도 아무런 동작을 하지 않습니다. 저는 그런 것을 싫어합니다.
그래서 이 도구는 모든 동작을 두 가지 범주로 나눕니다: 서버가 필요한가, 아니면 기기(device)에서 실행되는가? 백엔드 (backend)가 필요한 모든 것은 명확한 TODO와 함께 모킹 (mocked) 처리됩니다. 기기 내에서 실행되는 모든 것은 실제로 구현됩니다. Todoist 클론에서는 작업을 추가하면 저장됩니다. Spendee 클론에서는 지출을 기록하면 잔액이 변경됩니다. 앱을 닫았다가 다시 열어도 데이터는 그대로 남아 있습니다. 사진이 아니라 진짜 앱입니다.
작동 증명
스크린샷은 거짓말을 합니다. 정지된 이미지에서는 아무 동작도 하지 않는 버튼이 작동하는 버튼과 똑같이 보입니다. 그래서 저는 클론이 제대로 작동하는지 확인하기 위해 스크린샷을 믿지 않습니다.
모든 클론에는 헤드리스 브라우저 (headless browser)에서 앱을 구동하여 모든 화면을 로드하고, 각 기능을 실행하며, 오류가 발생하거나 기능이 고장 나면 실패로 처리하는 스크립트가 포함되어 있습니다. 만약 "작업 추가, 새로고침, 데이터 유지" 흐름이 깨지면 빌드는 실패합니다. "스크린샷으로는 괜찮아 보이는데"와 같은 버그는 없습니다.
할 수 없는 것
여러분이 직접 발견하게 하기보다 차라리 이렇게 말씀드리는 편이 낫겠습니다:
- 백엔드(Backend)가 없습니다. 데이터는 모의 데이터(Mocked)이거나 기기 내(On-device)에 존재합니다.
- 브랜드 아이콘은 복제되는 것이 아니라 유사하게 구현됩니다.
- 실제로 캡처한 화면만 복제합니다.
사용 방법
이 프로젝트는 MIT 라이선스의 오픈 소스입니다. Claude Code 스킬로 배포되지만(이것이 참조 설정입니다), 단일 소스(Single source of truth)로부터 생성되므로 Cursor, Codex, Windsurf, Gemini 및 그 외 수많은 도구에서도 작동합니다.
다음 로드맵은 스크린샷을 네이티브 SwiftUI 및 Compose로 변환하는 것이며, 그 후 정확한 값이 필요한 경우를 위해 APK를 디컴파일(Decompiling)하는 기능을 추가할 예정입니다.
저장소(Repo): https://github.com/Birkenpapier/ai-app-cloner
직접 사용해 보신다면, 어떤 부분에서 한계가 있는지 정말 알고 싶습니다. 이상한 것을 복제해 보고 무엇이 제대로 작동하지 않았는지 저에게 알려주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기