본문으로 건너뛰기
Chandler Nguyen
AI8분 읽기

AI

네이티브는 겉껍데기가 아니다: DIALØGUE iOS 앱을 다시 만든 이야기

DIALØGUE iOS 앱을 처음엔 웹 제품의 이식판으로 출시했다가, 네이티브로 다시 만들었어요. 탭 세 개, 잠금 화면 오디오, 동기화되는 자막, 끈질긴 오프라인, 그리고 Siri까지. 폰 크기로 줄인 웹 앱은 결국 그냥 웹 앱이니까요.

몇 달 전, DIALØGUE iOS 앱을 웹 제품의 이식판으로 출시했어요. 그러고 나서 거의 전부를 네이티브 앱으로 다시 만들었습니다.

지금은 App Store에서 공개 중이에요. 궁금하시면 한번 만져보셔도 좋아요. 이 아래는 무엇이 바뀌었고, 왜 바뀌었는지에 대한 이야기입니다.

말장난처럼 들릴 수 있어요. 그런데 두 버전을 손에 들고 비교해 보면 확실히 달라요. 첫 번째 버전은 폰 크기로 줄인 웹 앱이었습니다. 같은 탭, 같은 생성 마법사, 같은 대시보드. 컴파일도 되고, 돌아가고, 심사도 통과했어요. 그런데도 웹사이트가 앱 코스튬을 입은 느낌이었습니다.

폰 크기로 줄인 웹 앱은 그래도 여전히 웹 앱이에요. 네이티브는 웹 레이아웃 위에 칠한 페인트 한 겹이 아닙니다. 디바이스와 맺는, 완전히 다른 '계약'이에요. 바로 그 계약을 제가 건너뛰었던 거고요. 그 계약을 지키려고 다시 만들면서 탭도, 오디오도, 듣는 화면도, 오프라인 동작도, 앱이 시작되는 방식까지도 다 바뀌었습니다. 그게 실제로 무슨 뜻이었는지, 화면 하나하나 짚어볼게요.

이식판은 대시보드였다

첫 버전은 앱의 일이 "생성기를 노출하는 것"이라고 은연중에 전제했어요. DIALØGUE는 AI로 팟캐스트를 만드니까, 이렇게 생각한 거죠. 웹 화면을 전부 올리면 끝이겠지.

그렇게 해서 나오는 건 대시보드입니다. 탭 다섯 개, 여러 단계짜리 마법사, 온갖 것에 대한 패널. 팟캐스트 앱을 여는 사람은 대시보드를 조작하려는 게 아니에요. 아이디어를 오디오로 바꾸고, 자기가 만든 걸 듣고, 전에 돌렸던 쇼를 다시 시작하려고 엽니다. 이식된 인터페이스가 지키고 있던 건 웹 앱의 레이아웃이었어요. 그 세 가지 일은 지키지 못했고요.

그래서 다시 만들기는 가장 먼저 보이는 것에서 시작했습니다.

탭을 세 개로. 폰은 탭이 많을수록 벌을 주니까

옛 앱은 탭 다섯 개로 열렸어요. Library, Studio, Create, Credits, Profile. 웹 앱을 이식하면 이렇게 됩니다. 웹 화면 하나하나가 저마다 탭 하나씩을 따내거든요.

다시 만든 앱은 세 개예요. Listen, Create, You.

두 탭은 살아남지 못했습니다. Credits는 '목적지'이기를 그만뒀어요. 잔액을 들여다보려고 앱을 여는 사람은 없으니까요. Credits는 "You" 안으로 옮겼고, 정말 중요한 순간 — 생성하려는 바로 그때 잔액이 모자라는 순간 — 에는 그 자리에서 구매 시트가 뜨도록 했습니다. Studio는 '장소'이기를 그만뒀어요. 그건 Series가 됐습니다. 저장된 설정(호스트, 톤, 포맷, 언어, 소스 패턴)으로, Create 안에 살고 Listen에서는 컬렉션으로 나타나요. 컨트롤룸인 척하는 탭이 아니라요. Library와 Profile은 더 수수한 "Listen"과 "You"가 됐고요.

데스크톱에서는 탭이 하나 더 생겨도 공짜예요. 폰에서는 탭 하나하나가 주의력에 매기는 세금입니다. 다시 만들기는 그 세금을 갚은 거예요.

반복해서 쓸 수 있는 팟캐스트 설정을 저장하는 DIALØGUE iOS Series 화면
Series — 전용 탭을 가진 컨트롤룸이 아니라, Create 안에 저장된 설정.

iOS가 기대하는 방식 그대로의 오디오

"네이티브는 계약이다"라는 말이 추상론이 아니게 되는 지점이 바로 여기예요.

이식판이 오디오에 까막눈이었던 건 아니에요. 이미 잠금 화면에 재생, 일시정지, 건너뛰기가 떴고, 전화가 오면 멈췄고, 이어폰을 빼면 정지했어요. 이건 기본 중의 기본이고, 다 있었습니다.

못 했던 건, 화면이 잠긴 뒤에 '진짜 오디오 앱'처럼 행동하는 것이었어요. 잠금 화면에서 재생 위치를 끌 수 없었어요. 거기엔 커버 아트도 없었고요 — 텍스트만 있었죠. AirPlay 버튼도, 슬립 타이머도 없었고, 건너뛰기는 좋든 싫든 15초 고정이었습니다.

다시 만들기는 그 틈을 플랫폼을 '우회해서'가 아니라 플랫폼과 '함께' 메웠어요. 이제 잠금 화면은 에피소드마다 바뀌는 아트워크와, 원하는 지점 어디로든 끌 수 있는 스크러버를 갖췄습니다. AirPlay가 있고, 소리를 뚝 끊는 대신 서서히 페이드아웃하는 슬립 타이머가 있고, 10초에서 60초까지 직접 정하는 건너뛰기 간격이 있어요 — 그 값은 잠금 화면 버튼도 같이 움직입니다. 시스템 컨트롤은 앱과 맞아야 하니까요. 오디오 세션은 자기 자신을 spoken audio(말소리)로 선언해서, OS가 그것을 음악이 아니라 말소리로 다루게 합니다.

이 중 화려한 건 하나도 없어요. 그게 핵심이고요. 폰에서, 잠금 화면과 AirPlay를 무시하는 오디오는 '미니멀'한 게 아닙니다. 사람들이 실제로 듣는 바로 그 순간 — 걸으면서, 운전하면서, 폰을 주머니에 넣은 채 — 고장 나 있는 거예요.

AI 팟캐스트만 만들 수 있는 자막

여기가, 그냥 잘 만든 iOS 위생 수준이 아니라 진짜로 우리만의 것인 부분이에요.

에피소드가 재생되는 동안, 앱은 동기화된 자막을 보여줍니다. 지금 읽히는 줄이 강조되고, 그 줄이 가운데 오도록 자동으로 스크롤되고, 아무 줄이나 탭하면 그 순간으로 곧장 점프해요. 일반 팟캐스트 앱은 이걸 진짜로는 못 합니다. 무엇이 언제 말해졌는지를 모르니까요. DIALØGUE는 알아요 — 스크립트를 직접 생성했으니, 에피소드의 구조를 처음부터 알고 있는 거죠.

솔직한 기술적 디테일은, 줄을 탭할 수 있는 건 오디오에 세그먼트별 정확한 타이밍이 있을 때뿐이라는 거예요. 타이밍이 대략적일 때는 줄은 여전히 표시되지만, 시크(그 위치로 건너뛰기)는 안 됩니다. 그리고 되는 척하지 않아요. 같은 세그먼트 타이밍이 스크러버 위에 챕터 눈금을 그대로 그려줘서, 에피소드를 오디오처럼 들으면서도 시스템이 만든 것의 '지도'를 보며 훑어볼 수 있어요. 스크립트가 두 호스트의 대화로 쓰였기 때문에, 자막은 어느 줄을 어느 호스트가 말했는지까지 보여줍니다.

이게 바로, 플레이어에 자막을 끼워 넣는 것과, 생성된 스크립트를 듣는 경험 전체의 '진실의 출처(source of truth)'로 다루는 것의 차이예요.

이걸 가능하게 하는 게 둘 있는데, 둘 다 화면에는 안 나타나요. 백엔드는 모든 세그먼트에 시작 시각과 끝 시각을 찍고, 그 타이밍이 정확한지 추정일 뿐인지를 표시합니다 — 그래서 앱은 정확한 타이밍의 줄은 탭하게 해주고, 추정인 줄에서는 조용히 '꾸며내지 않을' 수 있어요. 그리고 당신의 재생 위치는 기기뿐 아니라 서버에도 저장돼서, "이어 듣기"가 제대로 작동합니다. 웹에서 에피소드를 시작해 폰에서 마저 들을 때도요.

탭하면 시크되는 자막 카드를 갖춘 DIALØGUE iOS 동기화 자막 화면
동기화 자막 — 줄을 탭해서 시크. 앱이 직접 스크립트를 생성하고 타이밍을 알기에 가능한 일.

진짜 출퇴근길을 버텨내는 오프라인

앱은 처음부터 에피소드를 다운로드할 수 있었어요. 이건 새로운 게 아니고, 그 부분은 정확히 말하고 싶어요. 다시 만들기가 더한 건 '끈질김'입니다 — 다운로드 기능과, 믿을 수 있는 오프라인의 차이죠.

중단된 다운로드는 이제 처음부터 다시 하는 대신 멈춘 지점부터 재개돼요. 앱이 시스템의 재개 데이터를 에피소드마다 저장해 두었다가 거기서부터 다시 시작하거든요. Wi-Fi 전용 옵션은 셀룰러를 진짜로 금지해서, 대기열에 든 다운로드는 몰래 데이터를 태우는 대신 Wi-Fi를 기다립니다. 다운로드는 네트워크에 우르르 몰리는 대신, FIFO 큐로 한 번에 최대 세 개까지만 돌아가요. 기기에 뭐가 있는지 보고 지울 수 있는 스토리지 화면도 있고요. 그리고 불안정한 연결에서 실패하는 일시적 fetch는 백오프를 두고 재시도합니다 — 세 번까지, 0.5초에서 상한까지 늘어나며, 사용자가 취소한 건 절대 재시도하지 않아요.

재시도는 쉬워요. 어려운 건, 취소를 누른 사용자와 싸우지 않으면서 재시도하는 것입니다. 바로 그 부분이, 끔찍한 지하철 신호에서도 오프라인이 빙빙 도는 대신 '단단하다'고 느끼게 해줘요.

다운로드한 에피소드 컨트롤을 갖춘 DIALØGUE iOS 오프라인 청취 화면
오프라인은 늘 있었어요. 다시 만들기가 그걸 끈질기게 만들었습니다 — 재개, Wi-Fi 전용, 스토리지 컨트롤, 상한이 있는 큐.

즉각적으로. 스피너는 '고장'으로 읽히니까

폰에서 지연은 숫자가 아니라 '느낌'이에요. 콜드 스타트의 스피너는, 아무 문제가 없어도 "이 앱은 고장 났다"로 읽힙니다.

이식판은 콜드 스타트 때마다 커버 이미지를 전부 다시 다운로드해서, 라이브러리가 스피너의 벽으로 열렸어요. 다시 만들기는 커버 아트용으로 메모리와 디스크 공유 캐시를 더했습니다 — 디스크 계층은 재실행을 버텨내고, 메모리 계층은 스크롤을 매끄럽게 유지하고, 잠금 화면은 아트워크에 같은 캐시를 재사용해요. 에피소드를 다시 여는 건 예전엔 네트워크 왕복을 기다렸지만, 이제 세그먼트와 자막이 에피소드마다 캐시돼서 즉시 표시되고, 그 뒤 백그라운드에서 조용히 새로고침됩니다. 0.5초마다 도는 재생 틱도 리스트 행에서 떼어냈어요. 타이머가 라이브러리 전체를 다시 그리게 만드는 걸 멈추려고요.

이건 스크린샷을 찍을 수 있는 기능이 아니에요. 앱과 웹사이트 '사이의 틈'입니다.

에피소드가 준비되면 알려준다

팟캐스트 생성은 몇 초가 아니라 몇 분이 걸려요 — 리서치가 있고, 아웃라인이 있고, 스크립트가 있고, 그다음에 오디오죠. 이식판은 그동안 내내 진행 바를 보게 했어요. 네이티브 앱은 그렇게 안 합니다.

당신의 허락이 있으면, 에피소드가 준비된 바로 그 순간에 푸시 알림을 보냅니다. 그래서 폰을 잠그고, 다른 일을 하다가, 진동이 오면 돌아오면 돼요. 기기 토큰은 서버 측에 저장되고, 알림 작업만 그걸 읽을 수 있으며, 설정에서 전부 끌 수 있습니다. 테이블 하나, 워커 하나, Apple의 푸시 서비스 — 작은 배관이에요. 하지만 그건 제품의 체감 형태를 "이 화면에서 기다리세요"에서 "다 되면 알려드릴게요"로 바꿉니다.

워크플로는 앱 밖에서도 시작될 수 있다

네이티브 앱은 자기 창 안에서만 사는 게 아니에요. 다시 만들기는 App Intents를 통해 Siri와 단축어 지원을 더했습니다. 그래서 "팟캐스트 만들기", "이어 듣기", "내 팟캐스트 열기"가 말로, 단축어 앱 안에서, 그리고 Spotlight에서 작동해요 — 특별한 entitlement는 필요 없습니다. "이어 듣기"가 무엇을 해야 하는지(지금 에피소드를 이어갈지, 아무것도 안 불러와졌으면 라이브러리를 열지)에 대한 판단은, 그것만 따로 유닛 테스트할 수 있는 아주 작은 순수 함수로 만들었어요. 이런 게, Siri 동작이 슬금슬금 어긋나는 걸 막아줍니다.

그리고 첫 실행 때 절제된 세 페이지짜리 환영 화면(create, voices, 어디서든 듣기)이 딱 한 번 나옵니다. 또 딥 링크 덕분에, 탭한 링크는 홈 탭에 사용자를 던져 놓는 대신 알맞은 화면을 열어요. 사소한 것들이죠. 하지만 그것들이, 폰 위에 그냥 '얹혀 있는' 앱과 그 폰에 '속한' 앱의 차이입니다.

어디서 멈췄는지에 대해 한마디. 홈 화면 위젯도, Live Activities도, CarPlay도 아직 없어요 — 각각 자기만의 extension이나 Apple이 부여하는 entitlement가 필요하고, 저는 듣기 코어를 먼저 출시하기로 했습니다. 여기서 "네이티브"는 방향이지, 끝난 체크리스트가 아니에요.

이번 일에서 제가 얻은 교훈

뭔가를 새 플랫폼으로 이식할 때 솔깃한 수는, 거기서 돌아가게 만들어 놓고 "완료"라고 부르는 거예요. 돌아가긴 할 겁니다. 그리고 동시에 '빌려온 것' 같은 느낌도 날 거고요.

네이티브는 디바이스와 맺는 계약이에요. 잠금 화면을, 오디오 출력 경로의 변화를, 오프라인이라는 현실을, 사람들이 이미 쓰고 있는 시스템 화면을 존중하는 것. 이식은 당신의 옛 레이아웃을 존중합니다. 네이티브 앱은 플랫폼의 관습을 존중해요 — 그게 이미 출시한 탭을 지우고 화면을 다시 쓰는 걸 뜻하더라도요.

휘둘러 자랑할 만한 설치 수나 리텐션 수치는 없어요 — 지금 버전은 App Store에서 공개 중이고, 그게 솔직한 현 상태입니다. 진짜 시험은 스크린샷이 네이티브해 보이느냐가 결코 아니었어요. 누군가 에피소드를 만들고, 폰을 잠근 채 산책하며 그걸 듣고, 한 편 더 만들러 돌아오느냐. 그게 시험입니다.

모바일용으로 만드는 분이라면, 어디에 선을 긋는지 정말 궁금해요. "폰에서 돌아간다"로 충분한 건 언제이고, 플랫폼의 계약이 다시 만들기를 강요하는 건 언제일까요?

자주 묻는 질문

DIALØGUE iOS 다시 만들기에서 무엇이 바뀌었나요?

앱은 웹 제품의 이식판에서 네이티브 재구축으로 바뀌었어요. 정보 구조는 탭 다섯 개에서 세 개(Listen, Create, You)로 줄었습니다. 듣는 경험에는 탭하면 시크되는 동기화 자막, 챕터 마커, 잠금 화면 스크러빙과 아트워크, AirPlay, 슬립 타이머, 설정 가능한 건너뛰기 간격이 더해졌어요. 오프라인 다운로드는 끈질겨졌고, 앱은 커버 아트와 세그먼트를 캐시해 즉각적인 느낌을 주고, Siri/단축어로 핵심 동작을 앱 밖에서 시작할 수 있고, 에피소드가 준비되면 푸시 알림이 알려줍니다.

왜 탭 다섯 개가 세 개가 됐나요?

폰이 탭이 하나 늘 때마다 벌을 주기 때문이에요. Credits는 아무도 가고 싶어 하지 않는 곳이라, "You"와, 실제로 잔액이 모자랄 때 나타나는 구매 시트로 접어 넣었습니다. Studio는 Series가 됐어요 — 독립된 탭이 아니라 Create 안에 저장된 설정이죠. Library와 Profile은 더 수수한 "Listen"과 "You"가 됐고요.

다시 만들기로 더해진 네이티브 iOS 기능은 무엇인가요?

잠금 화면 스크러빙과 동적 아트워크, AirPlay, 음량 페이드가 있는 슬립 타이머, 잠금 화면 컨트롤까지 같이 움직이는 설정 가능한 건너뛰기 간격(10~60초), 스크러버 위의 챕터 눈금, 탭하면 시크되는 동기화 자막, 끈질긴 오프라인 다운로드(재개, Wi-Fi 전용, 스토리지 관리, 상한 있는 큐), 즉시 렌더링을 위한 커버 아트와 세그먼트 공유 캐시, Siri/단축어 인텐트, "에피소드 준비됨" 푸시 알림, 웹과 폰을 넘나들며 이어 듣게 해주는 서버 측 재생 위치, 딥 링크, 그리고 첫 실행 온보딩이에요.

동기화 자막은 모든 에피소드에서 작동하나요?

자막 줄을 탭해서 시크할 수 있는 건 오디오에 세그먼트별 정확한 타이밍이 있을 때뿐이에요. 타이밍이 대략적일 때는 줄은 그대로 표시되지만 시크는 안 되고, 되는 척도 하지 않습니다. 자막이 가능한 건 DIALØGUE가 스크립트를 직접 생성했기 때문이라, 구조도 누가 무엇을 말했는지도 알아요.

Studio와 Series의 차이는 무엇인가요?

Studio는 손잡이가 잔뜩 달린 컨트롤룸을 연상시켰어요. Series는 그냥 저장된 설정입니다 — 호스트, 톤, 포맷, 언어, 소스 패턴 — 으로, 전부를 다시 설정하지 않고 다음 에피소드를 시작하게 해줘요. 독립된 탭이 아니라 Create 안의 프리셋이에요.

NotebookLM의 오디오 개요와는 어떻게 다른가요?

NotebookLM은 소스를 빠른 오디오 개요로 바꾸는 데 정말 유용하고, 무료예요. DIALØGUE는 생성 위에 '네이티브로 완결된 듣기 제품'이 되려고 합니다. 오디오를 만들기 전의 아웃라인과 스크립트 리뷰, 음성 선택, 탭하면 시크되는 동기화 자막, 챕터, 잠금 화면과 AirPlay 컨트롤, 오프라인 다운로드, Siri, 그리고 반복해서 만드는 쇼를 위한 Series까지요. 솔직한 차이는 "누가 더 좋은 오디오를 생성하느냐"보다, "에피소드가 존재한 뒤에 그것에 무슨 일이 일어나느냐" 쪽에 있어요.

다시 만들기로 오프라인 청취가 더해진 건가요?

오프라인 다운로드는 이미 있었어요. 다시 만들기가 그걸 끈질기게 만들었습니다. 중단된 다운로드는 처음부터가 아니라 재개하고, Wi-Fi 전용 옵션과 스토리지 화면이 있고, 다운로드는 한 번에 최대 세 개까지 돌아가고, 일시적인 네트워크 실패는 취소를 누른 사용자와 싸우지 않으면서 백오프를 두고 재시도해요.

저는 지금으로선 이 정도입니다.

그럼, Chandler 드림