크라우니AI 런처 — 웹서비스 카드 배선 (I2)
개요
crowny-browser.m 네이티브 런처(crowny://app/런처)에 8종 game.crowny.org 웹서비스(아카데미/광고스튜디오/코드생태계/세일즈/커머스/자동화/카피/뉴스레터) 카드를 배선하는 I2 작업(서브에이전트 병렬분 중 하나). SSOT는 src/앱목록.psv(I1 담당), 본 작업은 .m 소비측 5건.
무엇을 했는지
대상: /Users/ef/CrownyBrowser/native/crowny-browser.m (8364줄 → 수정 후 재계산 필요)
- appListEntries() — cols[1]이
url:접두면 entry에@"url"키 추가(접두 제거한 URL). 기존 로컬앱(name/desc만) 동작 불변. - mouseDown: isLauncher 분기 — url 키 있는 엔트리는 crowny://app/<name> 대신 URL로 라우팅.
#ifdef CROWNY_HYBRID → self.onNav(url) (raw URL, WKWebView 탭)
- #else → self.onNav(@"crowny://web/"+url) (M4 파이프라인)
- launcherCardRects: — 2열→3열 그리드. rows=ceil(n/3), 행높이(ch)를 가용높이 기준 적응형 계산(최소 64pt 클램프) — 17개 카드로 늘어나도 화면 밖으로 안 잘림. drawRect/mouseDown이 이 함수를 공유하므로 히트테스트 자동 동기화.
- launcherAccentForApp — 8개 신규 앱 이름에 각각 다른 액센트색(골드/러스트코랄/틸/앰버/바이올렛/스틸블루/플럼/포레스트) 추가.
- 학습배지 —
gLauncherLearnBadges(static NSMutableDictionary) + dispatch_once 기반 1회 비동기 NSURLSession fetch. game.crowny.org/api/ai/manifest(실패 시 127.0.0.1:9775 폴백, 5s 타임아웃) → services[].route 마지막 경로조각 기준으로 {records, total_hits} 캐시. 완료 시 메인스레드 setNeedsDisplay. drawRect는 캐시만 읽음(동기 네트워크 없음). 카드 우하단에 "지능 N·활용 M"(11pt, 반투명) 표시, 카드 높이 80pt 미만이면 겹침 방지로 생략. 카드 폭 260px 미만이면 제목 20→16pt·설명 13→11pt로 축소 + 제목 말줄임(truncating tail).
빌드 검증
cd /Users/ef/CrownyBrowser/native
make → CrownyBrowser (460096 bytes, -DCROWNY_HYBRID) — 컴파일 성공, 경고 2건(기존 무관 unused-function)
make universal → CrownyBrowser-Universal (460104 bytes, -DCROWNY_HYBRID -DCROWNY_PRODUCT_UNIVERSAL) — 컴파일 성공, 경고 동일 2건
make crownyonly → CrownyBrowser-Crowny-Full (390552 bytes, WebKit 0) — 컴파일 성공, 경고 6건(전부 기존 CROWNY_HYBRID 전용 헬퍼 unused, 신규코드 무관), otool WebKit링크: 0 확인
앱 재기동은 하지 않음(가드레일 — 메인 세션 통합검증에서 수행).
관련 파일
/Users/ef/CrownyBrowser/native/crowny-browser.m— 5건 수정 (appListEntries, launcherAccentForApp+학습배지 함수 2개, launcherCardRects, drawRect 런처 카드 렌더, mouseDown isLauncher 분기)/Users/ef/CrownyBrowser/src/앱목록.psv— 아직 8종 url: 행 미추가(I1 담당 SSOT, 이 세션에서 확인 시점엔 부재)/Users/ef/CrownyBrowser/native/Makefile— 참고만(미수정)
잔여 이슈
- src/앱목록.psv에 8종 url: 행이 아직 없음 — I1이 추가해야 런처에 실제로 카드가 보임(공통계약 6열 포맷:
이름|url:<URL>|-|-|-|설명). 이 세션은 .m 소비측만 구현, PSV 자체는 건드리지 않음. - 학습배지는 game.crowny.org/api/ai/manifest 라이브 응답에 의존 — 로컬 검증 시 실제 fetch 성공/실패 E2E는 미실측(빌드 컴파일 검증만 완료).
- 학습배지 dispatch_once가 첫 호출 view만 weak 캡처 — 런처 탭이 여러 개 동시에 열린 멀티탭 edge case는 첫 탭만 리드로우, 나머지는 다음 재드로우 계기(리사이즈 등)까지 배지 미반영 가능(허용 범위로 판단, 스펙 요구사항 밖).
- appListRow()(renderScriptForService/ppmPathForService/actionScriptForService)는 url 엔트리에 대해 호출되지 않는 경로라 미수정 — url 엔트리는 crowny://app/<name>으로 절대 진입하지 않으므로 안전.