Skip to content

UI/UX 개편: 연결 안내·9개 언어·잠금 화면 위젯·SE/iPad 대응·평가 요청 - #23

Merged
kangddong merged 22 commits into
developfrom
Feature/develop-dev
Oct 27, 2026
Merged

kangddong merged 22 commits into
developfrom
Feature/develop-dev

Conversation

@kangddong

Copy link
Copy Markdown
Collaborator

요약

ASC 추세(2023-09 ~ 2026-10-25)를 근거로 다음 버전 UI/UX를 개편합니다.

  • 유입: 신규 유입이 정점(2024-01) 대비 약 95% 줄었습니다.
  • 해외 비중: 사용자의 98%가 해외인데, 스토어와 앱 일부가 한국어로만 보였습니다.
  • 사용 패턴: 사용자는 앱을 거의 열지 않고(활성 기기당 월 약 2세션) 위젯·알림으로 확인합니다.
  • 전환율: 0.56%로, 유틸리티 동종 앱 하위 25%보다 낮습니다.

1. 미연결 첫 화면 → 연결 안내

  • 스피너와 "Not connected.."만 보이던 화면에 DualSense 연결 3단계 안내, 대기 표시, 공식 지원 안내를 넣었습니다.
  • 블루투스 설정 화면으로 바로 보내는 공개 API가 없어, 설정 이동 버튼 대신 경로를 안내합니다.
  • 배터리 정보를 주지 않는 컨트롤러(배터리 상태 unknown)는 0% 링 대신 "배터리 정보를 제공하지 않는 컨트롤러" 안내를 보여 줍니다.

2. 다국어

  • en에 빠진 키 9개, ja에 빠진 키 8개를 채웠습니다. 구매 화면에 termOfUse·privacy Policy가 키 이름 그대로 보이던 문제입니다.
  • Tester 연결 문구, 구매 화면 제목, 위젯 갤러리 이름·설명의 하드코딩을 키로 바꿨습니다.
  • 위젯 타깃에 현지화 파일을 새로 만들었습니다.
  • es, pt-BR, ru, tr, fr, de를 추가했습니다. 9개 언어 모두 키 집합이 같습니다(앱 52, InfoPlist 2, 위젯 9).

3. 홈·잠금 화면 위젯

  • 연결이 끊기면 0% 대신 "Not connected / Last: 42%"로 표시합니다.
  • 충전 중 표시, 기기 이름, 마지막 갱신 시각을 넣었습니다.
  • 잠금 화면 위젯(원형·사각형·인라인, iOS 16+)을 추가했습니다. iOS 17 containerBackground도 적용했습니다.
  • small·medium·large와 iPad extraLarge를 그대로 지원합니다.
  • WidgetSharedState에서 App Group 쓰기를 한곳으로 모았고, 상태가 바뀔 때만 타임라인을 다시 읽게 합니다.
  • 타임라인 엔트리 25개가 모두 같은 날짜로 만들어지던 코드를 정리했습니다.

4. 화면 크기 대응

  • 400×400 고정이던 배터리 링을 가용 영역에 비례하게 바꿨습니다(최대 360pt). SE에서 화면 밖으로 넘치고 Refresh 버튼이 탭바에 가리던 문제입니다.
  • 고정 폰트 크기를 Dynamic Type 텍스트 스타일로 바꿨습니다.
  • 구매 화면:
    • Dynamic Type 글꼴을 적용했습니다.
    • 콘텐츠 폭을 가운데 최대 560pt로 제한했습니다(iPad).
    • 긴 제목은 닫기 버튼과 겹치지 않게 두 줄로 내려갑니다.
  • Tester: 트리거·어깨 버튼 간격을 화면 폭에 맞췄습니다.

5. 평가 요청

  • 누적 연결 3회째부터 앱 버전당 한 번 SKStoreReviewController.requestReview(in:)를 부릅니다.
  • 평가 차례인 실행에서는 Pro 소개 팝업을 건너뛰고 평가를 먼저 띄웁니다.
  • 시작 흐름·광고·모달이 끝나기를 최대 30초 기다리고, 띄우지 못하면 횟수를 소모하지 않습니다.

기타

  • DEBUG 전용 스크린샷 픽스처 ScreenshotFixture를 추가했습니다. 실행 인자는 -ACScreenshot, -ACMockBattery(-1이면 정보 없음), -ACMockCharging, -ACMockVendor, -ACTab, -ACPaywall입니다. 시뮬레이터에는 컨트롤러를 연결할 수 없어 연결 상태를 이것으로 만듭니다. 릴리스 빌드에는 들어가지 않습니다.
  • docs/store-listing.md: App Store 등록 정보 현지화 초안을 추가했습니다(en-US·ja·es-MX·pt-BR·ru·tr·fr-FR·de-DE와 ko 개정안). 키워드 오타 kensin을 genshin으로 고쳤습니다. ASC에는 아직 올리지 않았습니다.
  • CLAUDE.md에 지원 언어, 위젯 공유 키, 픽스처, 평가 요청 규칙을 반영했습니다.

확인한 것 (iOS 27.0 시뮬레이터: iPhone 17 Pro / iPhone SE 3 / iPad Pro 11)

  • CI와 같은 명령(generic simulator, 서명 없음)으로 Controllers, ControllersWidgetExtension 빌드가 성공합니다. 통합 시점 비교에서 새 컴파일 경고는 없었습니다.
  • 9개 언어의 Localizable/InfoPlist/위젯 Localizable 키 집합이 같습니다.
  • 픽스처로 미연결, 연결·충전 42%, 배터리 정보 없음 상태를 en·ko·ja와 새 언어로 실행해 봤습니다. SE·iPad에서 화면이 넘치지 않습니다.
  • 홈 화면 small·medium 위젯과 잠금 화면 원형·사각형 위젯을 실제로 배치해서 연결·미연결·정보 없음 표시를 확인했습니다. 로컬 서명 빌드에서 App Group 공유가 됩니다.
  • 위젯 갤러리 이름은 영어 시스템에서 "Controller Battery"로 보입니다(before: 한국어).
  • 평가 요청: 시작 흐름을 짧게 만든 임시 패치로 "Review requested" 로그와 평가 시트가 뜨는 것을 확인했습니다. 임시 패치는 커밋하지 않았습니다.

before/after 화면 비교는 로컬 정적 페이지로 따로 정리했습니다(레포에는 넣지 않음).

확인 못 한 것 (실기기 필요)

  • DualSense 실기기에서 연결·충전 상태 갱신, 백그라운드 BGTask 뒤 위젯 갱신
  • 실제 시작 흐름(알림·UMP·ATT 응답)을 거친 뒤 평가 시트 노출
  • 잠금 화면 인라인 위젯(시뮬레이터 자동화로 배치 못 함)
  • SE에서 ru·de 연결 안내는 화면보다 길어 스크롤해야 합니다

출시 전 함께 할 일

  • 버전 번호 올리기
  • docs/store-listing.md 검토 후 ASC 등록 정보 입력(이름·부제는 새 버전 제출 때만 반영) + 영어 스크린샷
  • es를 "Ajustes"(스페인 표기)로 둘지, 멕시코용 es-419("Configuración")을 분리할지 결정

🤖 Generated with Claude Code

kangddong and others added 22 commits October 27, 2026 03:46
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
시뮬레이터에는 컨트롤러를 연결할 수 없어 화면 상태를 실행 인자로 만든다.
-ACScreenshot YES 로 시작 흐름(알림 권한·광고 동의·ATT·광고·Pro 팝업)을 건너뛰고,
-ACMockBattery/-ACMockCharging/-ACMockVendor 로 연결 상태를, -ACTab 으로 시작 탭을,
-ACPaywall 로 구매 화면을 띄운다. 릴리스 빌드에는 들어가지 않는다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
en/ja에 빠진 키 때문에 구매 화면에 키 이름이 그대로 노출됐다. 최초 다운로드의 98%가 해외라 영향이 크다.
Tester 연결 상태와 구매 화면 제목을 키로 바꾸고, 고정 크기(spacing 400, 40/26pt 폰트)를
가용 폭·Dynamic Type·readableContentGuide 기준으로 바꿨다.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
위젯이 연결 여부와 잔량만 받아서 미연결도 0%로 보이고, 충전 여부·기기 이름·갱신 시각을 알 수 없었다.
앱이 App Group 에 연결·잔량·충전 상태·기기 이름·갱신 시각을 함께 쓰고 위젯 타임라인을 다시 읽게 한다.
미연결이면 마지막으로 알던 값은 남겨 위젯이 "마지막: 42%"를 보여 줄 수 있게 한다.
같은 상태(잔량 1% 미만 변화)면 15분 안에는 reload 를 생략해 WidgetKit 갱신 예산을 아낀다.
포어그라운드(ControllerModel)·백그라운드(FetchGameControllerOperation)·DEBUG 스크린샷 픽스처가 모두 이 헬퍼를 쓴다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
사용자는 앱을 거의 열지 않고 위젯으로 확인하는데, 위젯이 홈 화면 크기만 지원하고 미연결·충전·갱신 시각을 구분하지 못했다.
- small/medium: 잔량 링·퍼센트·충전 번개·갱신 시각, 미연결이면 흐린 컨트롤러 아이콘과 마지막 잔량
- iOS 16+ 잠금 화면 accessoryCircular/Rectangular/Inline 추가 (iOS 15 에서는 홈 크기만)
- iOS 17+ containerBackground 적용
- 타임라인이 25개 엔트리를 모두 같은 시각으로 만들던 버그를 엔트리 1개 + 30분 뒤 갱신으로 정리
- 갤러리 이름·설명과 위젯 문구를 위젯 타깃 Localizable(ko/en/ja)로 옮김 (사용자 98%가 해외)
- 링 색은 충전 알림 기준값 이하에서 빨강

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
평가가 2건뿐이라, 컨트롤러를 세 번 이상 연결한(앱이 쓸모 있었던) 사용자에게 버전당 한 번
SKStoreReviewController로 평가를 요청한다. Pro 팝업·광고·시작 흐름 팝업과 겹치지 않게
2초 뒤 조건을 다시 보고, 요청·건너뜀은 NSLog로 남긴다. DEBUG에서 -ACReviewTest YES로 경로를 탈 수 있다.

충전 중이면 퍼센트 옆에 번개를 보여 주고, 스크린샷 픽스처의 isCharging도 반영한다.
픽스처 모드에서는 시뮬레이터의 가상 컨트롤러 연결을 무시해 '모의 값 없음 = 미연결'을 지킨다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
미연결 상태가 스피너와 'Not connected..'만 보여 줘서, 앱을 거의 열지 않는 사용자에게
첫 화면에서 연결 방법을 알려 주지 못했다. 3단계 페어링 안내와 대기 표시, 공식 지원 문구를 넣었다.
블루투스 설정으로 바로 가는 공개 API가 없어 설정 이동 버튼은 두지 않았다.

배터리 링이 400pt로 고정돼 iPhone SE에서 넘치고 iPad에서 작아 보여서, 가용 영역에 맞춰
지름(최대 360pt)·아이콘·선 굵기를 정하고 텍스트 스타일로 Dynamic Type을 따르게 했다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
iOS 27 시뮬레이터는 배터리 정보가 없는 가상 컨트롤러("Gamepad")를 연결된 것으로 넘겨준다.
스크린샷 모드에서는 GameControllerManager 이벤트를 받지 않고 실행 인자 상태만 보여 준다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
iOS 27 시뮬레이터는 배터리 정보가 없는 가상 컨트롤러("Gamepad")를 연결된 것으로 넘겨준다.
스크린샷 모드에서는 GameControllerManager 이벤트를 받지 않고 실행 인자 상태만 보여 준다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
기존 위젯은 supportedFamilies 기본값(small·medium·large·extraLarge)을 썼으므로 large를 다시 지원해
홈 화면의 기존 위젯이 사라지지 않게 한다. extraLarge(iPadOS 15+)는 large 레이아웃을 재사용한다.
BATTERY_STATE가 unknown(-1)인 컨트롤러는 0%로 보이지 않고 "배터리 정보 없음"으로 표시한다(ko/en/ja).
accessoryRectangular는 이름 접미사(Wireless Controller/Controller)를 떼 말줄임을 피한다.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
배터리 상태가 unknown이고 잔량이 0인 컨트롤러(iOS 27 시뮬레이터 가상 Gamepad, 일부 비공식 컨트롤러)가
연결 화면에 0% 링으로 그려져 배터리가 바닥난 것처럼 보였다. 이 경우 링 대신 정보 없음 안내와 기기 이름,
공식 지원(DualSense) 문구를 보여 준다. 0%여도 충전·방전 중이면 진짜 0%라 기존처럼 그린다.

스크린샷 픽스처는 -ACMockBattery -1로 같은 상태를 만든다. argument 도메인이 -1을 값이 아닌 키로
읽어서 이 값만 실행 인자에서 직접 꺼낸다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
무료 사용자는 매 실행 첫 연결에서 Pro 팝업을 보는데, 평가 요청은 Pro 팝업을 띄운 실행이면
건너뛰어서 대부분의 사용자에게 실행되지 않았다. 평가 요청은 버전당 한 번이라, 누적 연결 3회 이상이고
이번 버전에 아직 요청하지 않은 실행(ControllerModel.isReviewRequestDue)에서는 ProPromotionManager가
Pro 팝업을 건너뛴다. 연결 횟수를 먼저 세서 두 곳이 같은 값을 본다.

시작 흐름(알림·광고 동의·ATT)이 끝나지 않았거나 광고·모달이 떠 있으면 바로 건너뛰지 않고 최대 30초
더 기다리며 다시 확인한다. 끝내 못 띄우면 횟수를 소모하지 않아 다음 연결에서 다시 시도한다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	Controllers/Controllers/Supporting Files/en.lproj/Localizable.strings
#	Controllers/Controllers/Supporting Files/ja.lproj/Localizable.strings
#	Controllers/Controllers/Supporting Files/ko.lproj/Localizable.strings
# Conflicts:
#	Controllers/Controllers/Sources/Controller/ControllerModel.swift
상위 다운로드 국가(러시아·브라질·튀르키예·프랑스·독일·스페인어권) 사용자가 영어로 보던 문제를 해소한다.
Localizable·InfoPlist(ATT 설명 포함)·위젯 문구를 번역하고 pbxproj variant group과 knownRegions에 등록했다.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
readableContentGuide 는 iPad 세로에서 거의 전체 폭이 돼서 버튼이 화면 끝까지 늘어났다.
가운데 정렬된 레이아웃 가이드(최대 560pt, 좌우 여백 15pt)로 바꾼다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
제목을 큰 글자(largeTitle)로 바꾼 뒤 일본어처럼 긴 제목이 오른쪽 위 닫기 버튼과 겹쳤다.
양쪽을 같은 만큼 띄워 가운데를 유지하고, 길면 두 줄로 내려가게 한다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
이번 UI/UX 개편으로 지원 언어, 위젯이 읽는 App Group 키, DEBUG 실행 인자, 평가 요청 규칙이 바뀌어
문서가 실제 코드와 달라졌다. 하드코딩 한국어 문구가 남아 있다는 설명도 더 이상 맞지 않아 지운다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kangddong
kangddong merged commit 53fb378 into develop Oct 27, 2026
1 check passed
@kangddong
kangddong deleted the Feature/develop-dev branch October 27, 2026 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant