모바일 로그인 입력을 손본 뒤 Android 기기에서만 커서가 사라지는 문제가 남았다. 입력창을 처음 누르면 잘 보이는데 비밀번호 보기 버튼을 누르거나 앱을 잠깐 내렸다 돌아오면 커서는 없고 키보드만 열렸다. 에디터에서 같은 순서를 반복해도 재현되지 않아 코드보다 기기 문제처럼 느껴졌다.
그래도 “Android에서 이상하다”로 두면 고칠 수 없었다. 포커스가 사라지는 정확한 순서를 만들고, 화면 생명주기와 입력 필드 상태를 같이 기록했다.
재현 순서의 고정
처음에는 커서가 가끔 사라진다고만 적었다. 동작을 나누자 특정 조건이 보였다.
1. 로그인 화면 진입
2. 비밀번호 입력 필드 선택
3. 비밀번호 표시 토글
4. 앱을 백그라운드로 이동
5. 다시 돌아와 입력 필드 선택
단순 탭에서는 괜찮았고 입력 필드의 타입이 바뀌거나 포커스가 복구되는 과정에서 주로 발생했다. 재현 절차가 생기니 로그를 어디에 넣을지도 정할 수 있었다.
입력 타입 변경에 따른 필드 재생성
비밀번호 표시를 바꾸려고 contentType을 수정한 뒤 텍스트를 다시 설정하는 코드가 있었다. 이 과정에서 캐럿 위치와 활성 상태가 초기화됐다. 현재 선택 범위를 보존하고 타입 변경 뒤 다시 활성화했다.
int caret = passwordField.caretPosition;
passwordField.contentType = showPassword
? TMP_InputField.ContentType.Standard
: TMP_InputField.ContentType.Password;
passwordField.ForceLabelUpdate();
passwordField.caretPosition = Mathf.Min(caret, passwordField.text.Length);
passwordField.ActivateInputField();
실제 기기에서는 같은 프레임에 키보드 상태도 바뀌어 다음 프레임에 활성화하는 처리가 필요했다.
앱 복귀와 화면 활성화의 구분
OnEnable은 화면 오브젝트가 켜질 때 호출되고, OnApplicationFocus는 앱이 포커스를 되찾을 때 호출된다. 두 곳에서 모두 무조건 첫 필드를 선택하니 사용자가 입력하던 필드와 충돌했다. 마지막으로 활성화된 필드를 기억하고 앱 복귀 시점에는 사용자가 입력 중이었을 때만 복원했다.
로그에는 비밀번호 값 같은 민감한 내용 대신 필드 이름, 선택 여부, 앱 포커스, 키보드 활성 여부만 남겼다. 기기 로그에서도 필요한 문맥은 충분했다.
개발 전 과정의 플랫폼 차이
이 작업 전에는 에디터에서 기능이 되면 대부분 끝났다고 생각했다. 하지만 입력은 OS 키보드와 Unity 이벤트가 만나는 경계였다. 에디터 테스트는 로직을 확인했고, 실제 기기 테스트는 생명주기와 플랫폼 동작을 확인했다.
커서 하나를 고치면서 재현 절차, 안전한 로그, 앱 포커스까지 보게 됐다. 이후 모바일 문제를 만날 때는 플랫폼 이름으로 뭉뚱그리지 않고 어떤 생명주기와 외부 시스템이 끼어드는지부터 찾게 됐다.
유사 문제 대응 기준
작업 당시에는 눈앞의 오류를 먼저 고쳤지만, 이후 기술 문서와 맞춰 보며 확인 순서를 조금 더 구체화했다.
HTML 문서의 focus, form, history 동작은 브라우저가 관리하는 상태다. 앱 코드가 보이는 컴포넌트만 바꿔도 현재 focus와 history entry가 자동으로 의도대로 정리된다고 볼 수 없다. 모바일 키보드나 Safari 외부 이동에서 차이가 커지는 이유도 이 경계에 있다.
사용자 조작을 재현할 때는 클릭 결과만 보지 않고 focus가 어디에 남았는지, history가 한 번 추가됐는지, 복귀 시 문서가 새로 만들어졌는지까지 확인하는 편이 낫다.
다음에 Android 입력 커서 소실 같은 문제를 보면 아래 순서부터 확인하려고 한다.
- focus 획득·해제 이벤트 순서
- 키보드 표시 전후 viewport 높이
- selection·cursor 위치 보존
- 자동 완성과 수동 입력의 구분
브라우저·WebView·설치형 PWA를 같은 환경으로 묶지 말고 지원 범위별 fallback을 둬야 한다.
공식 참고 자료
- W3C HTML 5.2 — 폼·포커스·autocomplete·탐색 동작
- W3C WCAG 2.1 — 확대·reflow·orientation·입력 접근성