Gitsunmin

하이브리드 앱 통합 프레임워크

← Works
하이브리드 앱 통합 프레임워크 아이콘

하이브리드 앱 통합 프레임워크

마켓보로

2023.08 ~ 2023.12

마켓보로의 여러 서비스 앱을 단일 Flutter 코드베이스로 통합하기 위해 설계한 하이브리드 앱 프레임워크입니다. Flutter를 얇은 Shell로, 기존 React·Vue·Nuxt 웹 자산을 WebView로 렌더링하고, JS Bridge(`window.nativeBridge`)로 네이티브 기능을 웹에 노출합니다. Dart 3.0 Sealed Class Flavor 시스템으로 2개 서비스 × 3개 환경(LOCAL/TEST/PROD) = 6개 빌드 타깃을 관리하며, Firebase Remote Config로 배포 없이 버전 게이팅을 원격 제어합니다.

Flutter Dart Firebase Firebase Remote Config
9:41100%
Architecture
Flutter ShellDart · Flavor System
Native
WebView Bridge
Web View
InAppWebViewwindow.nativeBridge 주입
Bridge
HTTP / REST / GraphQL
Web Application
Web Application모든 웹 프레임워크 호환
Web
Firebase Remote Config
9:41플레이버 시스템100%
2 서비스 × 3 환경 = 6 빌드 타깃
LOCAL마켓봄vendor.debug
TEST마켓봄vendor.debug -α
PROD마켓봄vendor
LOCAL식봄gred.debug
TEST식봄gred.debug -α
PROD식봄gred
sealed class Flavor { ... }
9:41JS Bridge100%
Web Application
window.nativeBridge.getVersion()
window.nativeBridge.getBuildNumber()
Cookie: MODE=APP
JavaScript Bridge
Flutter Native
version: "3.2.1"
build: "45"
isDebug: false
onLoadStop 시 자동 주입
아키텍처

Flutter Shell + WebView

Flutter를 얇은 네이티브 래퍼로, 기존 웹 자산을 WebView로 렌더링합니다. React, Vue, Nuxt 등 모든 웹 프레임워크와 호환되어 중복 개발 없이 iOS · Android 네이티브 기능을 활용할 수 있습니다.

  • 모든 웹 프레임워크 호환
  • Firebase Remote Config 연동
  • 쿠키 기반 앱 환경 전달
플레이버

6개 빌드 타깃, 단일 코드베이스

Dart 3.0 Sealed Class로 Flavor를 타입 안전하게 표현합니다. exhaustive switch가 누락된 환경 분기를 컴파일 타임에 잡아냅니다.

  • LOCAL / TEST / PROD × 2 서비스
  • Flavor별 독립 Firebase 프로젝트
  • 버전 접미사(-alpha) 자동 관리
JS Bridge

window.nativeBridge — 네이티브 기능 노출

WebView 로드 완료 시 window.nativeBridge 객체를 주입합니다. 웹이 앱 버전·카메라·갤러리 저장 등을 직접 호출할 수 있습니다.

  • 앱 버전 / 빌드 번호 조회
  • 카메라 · 갤러리 접근
  • 딥링크 · 카카오톡 실행

참고: 이 프로젝트는 개발 단계에서 사업 우선순위의 변경으로 배포 전 중단되었습니다. 이하 내용은 구현된 설계와 아키텍처의 기록입니다.

고지: 보안상의 이유 및 기업 기밀 보호를 위해, App ID · 쿠키명 · 파일 경로 등 일부 항목은 실제 프로젝트와 다르게 표기되어 있습니다.

배경

마켓보로에는 마켓봄 프로(현 마켓봄), 식봄, 마켓봄 등 여러 개의 네이티브 앱이 이미 존재했습니다. 이 앱들은 서비스 도메인은 달랐지만, 모두 웹뷰(WebView) 기반이라는 공통 구조를 갖고 있었습니다. 즉, 각 앱은 내부적으로 웹 앱을 띄우는 얇은 네이티브 Shell에 불과했고, 실제 비즈니스 로직은 웹 레이어에 있었습니다.

문제는 이 Shell들이 앱마다 별도의 코드베이스로 관리되고 있었다는 점입니다. 기능적으로 거의 동일한 코드가 서비스 수만큼 복제되어 있었고, 하나의 공통 기능을 수정할 때마다 모든 앱에 동일한 변경을 반복해야 했습니다. 이는 유지보수 비용을 불필요하게 높이는 구조였습니다.

이 문제를 해결하기 위해 모든 앱을 단일 Flutter 프로젝트로 통합하고, 빌드 타깃(Flavor)만 변경하여 각 서비스 앱을 생성하는 구조를 목표로 삼았습니다. 먼저 유통사 앱과 식봄 앱 두 개를 통합하는 것을 첫 번째 마일스톤으로 설정하고 아키텍처 설계와 구현에 착수했습니다.

Flutter를 얇은 네이티브 Shell로, 기존 웹 앱을 flutter_inappwebview로 렌더링하는 하이브리드 아키텍처를 채택했습니다. React, Vue, Nuxt 등 프레임워크에 무관하게 모든 웹 자산을 그대로 활용할 수 있는 것이 핵심입니다. 서비스 구분은 Flavor로, 환경 구분은 빌드 타깃으로 — 단일 Flutter 프로젝트가 6개 빌드 변형을 모두 커버하는 구조입니다.

아키텍처

┌──────────────────────────────────────┐
│          Flutter Native Shell        │  ← Dart / Flavor 시스템
│  ┌─────────────────────────────────┐ │
│  │  flutter_inappwebview (WebView) │ │  ← JS Bridge
│  │  ┌───────────────────────────┐  │ │
│  │  │      Web Application      │  │ │  ← 모든 웹 프레임워크 호환
│  │  └───────────────────────────┘  │ │
│  └─────────────────────────────────┘ │
│  Firebase Remote Config / Analytics  │
└──────────────────────────────────────┘

단일 Flutter 프로젝트 안에서 4개의 핵심 관심사를 분리합니다.

모듈역할
Flavor 시스템서비스·환경별 6개 빌드 타깃을 타입 안전하게 분기
JavaScript Bridge네이티브 기능을 웹에 window.nativeBridge API로 노출
버전 게이팅Firebase Remote Config로 강제·권장 업데이트를 원격 제어
URL 라우팅모든 URL 스킴을 scheme-first 분기로 처리

Flavor 시스템 — Dart 3.0 Sealed Class

Dart 3.0의 Sealed Class를 활용하여 서비스·환경 조합별 빌드 타깃을 타입 안전하게 분기합니다. Sealed Class의 exhaustive switch로 런타임 분기 누락을 컴파일 타임에 감지합니다.

각 Flavor는 독립된 Firebase 프로젝트, 앱 ID, 버전 접미사를 가지며, flutter_flavor가 빌드 타임 값 주입을, Sealed Class가 런타임 타입 안전 분기를 담당하는 이중 구조입니다.

JavaScript Bridge

WebView 로드 완료 시점에 Flutter가 JS 객체를 주입합니다. 웹 앱은 이 브릿지를 통해 앱 버전·빌드 번호·실행 환경 등 네이티브 정보를 조회할 수 있습니다.

앱 실행 환경 식별을 위한 쿠키(실행 모드·기기 플랫폼·앱 버전·빌드 번호)도 플랫폼에 맞게 자동 세팅하여 웹 앱이 WebView 환경임을 인지할 수 있게 합니다.

URL 라우팅 & 딥링크

shouldOverrideUrlLoading에서 URL 스킴을 우선 분류하고 처리합니다.

스킴처리 방식
kakaolink: / intent://카카오톡 앱 실행 (미설치 시 스토어 폴백)
tel: / sms: / mailto:시스템 앱 위임
data:image/*;base64,...base64 디코딩 → 갤러리 저장
일반 HTTP(S)기본 WebView 탐색 허용

버전 게이팅 — Firebase Remote Config + pub_semver

앱 재개 시마다 원격 버전을 가져와 강제 업데이트·점검 중·권장 업데이트·정상 진입의 네 가지 상태로 분기합니다. Dart 3.0 패턴 매칭으로 각 분기를 타입 안전하게 처리합니다.

담당 역할 & 기여

  • Flutter 하이브리드 앱 아키텍처 설계 및 전체 구현
  • Dart 3.0 Sealed Class 기반 Flavor 시스템 도입 — 컴파일 타임 안전성 확보
  • JS Bridge 설계 (앱 정보 조회·카메라·갤러리·딥링크)
  • Firebase Multi-Project 구성 (Flavor별 독립 google-services.json)
  • Firebase Remote Config 기반 원격 버전 게이팅 설계
  • iOS·Android 동시 배포를 위한 파이프라인 구성 (12개 빌드 타깃)

기술 스택

기술스택은 퇴사 시점 기준으로 작성되었습니다.

기술역할
Flutter 3.x크로스플랫폼 네이티브 Shell
Dart 3.0Sealed Class, Pattern Matching
flutter_inappwebview웹 자산 렌더링 (모든 웹 프레임워크 호환)
flutter_flavor멀티 플레이버 환경 분리
Firebase Remote Config원격 기능 플래그 · 버전 게이팅
firebase_analytics앱 이벤트 트래킹
pub_semverSemantic Versioning 비교
shared_preferences로컬 데이터 영속성
permission_handler네이티브 권한 요청
image_gallery_saverbase64 이미지 갤러리 저장
url_launcher딥링크 · 외부 앱 실행

기술 선택 이유

  • Flutter + WebView 하이브리드: 기존 웹 자산 재사용으로 중복 개발 최소화, 동시에 iOS/Android 네이티브 기능 활용
  • Sealed Class Flavor: when / switch 분기 누락을 컴파일러가 감지 — 환경별 설정 실수를 원천 차단
  • Firebase Remote Config: 핫픽스 없이 앱 동작을 원격 제어 — 긴급 대응 속도 향상

성과

  • 식봄·마켓봄(구 마켓봄 프로) 2개 서비스를 단일 Flutter 프로젝트로 통합하는 아키텍처 설계·구현
  • 6개 Flavor(LOCAL/TEST/PROD × 2 서비스)로 환경별 빌드 분리 구조 설계
  • Firebase Remote Config 기반 원격 버전 게이팅 설계 — 앱 배포 없이 긴급 설정 변경이 가능한 구조 완성
  • Sealed Class 패턴 도입으로 Flavor 관련 컴파일 타임 안전성 확보

관련 링크

  • 내부 프레임워크로 별도 공개 링크 없음