원격 안드로이드 조종 화면
휴대폰 브라우저로 원격 안드로이드 에뮬레이터를 조종하는 화면에서 키보드 입력 오류를 고치고, 화면 안에서 채팅과 메모장을 쓰게 했다.
무엇을 만들었나
휴대폰 브라우저로 컴퓨터 위의 안드로이드 에뮬레이터를 조종하는 화면을 다듬었다. 글자가 저절로 반복 입력되던 오류를 모의 입력 환경에서 재현해 고쳤고(실제 기기에서의 원인 확정은 아니다), 그 수정이 만든 입력 먹통 문제까지 같은 날 복구했다. 화면을 떠나지 않고 채팅과 메모장을 쓸 수 있는 패널도 추가했다.
구현 방식과 보안 설계는 ‘기술 상세’에 있습니다.
구조와 설계
오픈소스 안드로이드 화면 공유 웹 클라이언트(TypeScript, Express)에 기능을 더했다. 소프트키보드 입력은 숨은 textarea와 미러 버퍼의 변경분만 서버로 보내는 구조인데, IME가 지워진 버퍼를 복원하는 동작을 가짜 DOM 하네스로 모사해 수정 전 전송 9회 반복을 수정 후 1회로 줄였다(코드 경로상 반복이 가능함을 입증한 것이며 실기기 원인 확정은 아니다). 1차 폭주 가드가 입력을 영구 정지시키는 회귀를 만들자 '어긋나면 멈추지 말고 복구' 원칙으로 상태 기계를 다시 설계했다. 채팅 패널은 서버가 외부 채팅 서비스 로그인과 세션을 전담하는 프록시 API로, 메모장은 크기 상한과 원자적 교체를 둔 파일 저장 API로 구현했다. 실제 휴대전화 화면에서의 배치와 터치 동작은 확인하지 못했다.
사용 기술
TypeScript, Node.js, Express, 브라우저 DOM·Fetch API·IME composition 이벤트, Webpack, ADB, macOS launchd, ESLint
보안·안정성 설계
- 채팅 패널의 외부 서비스 인증은 서버가 전담한다. 세션 쿠키는 서버가 보관하고, 401을 받으면 한 번만 재로그인해 재시도하며, 채널은 서버 설정으로 고정해 요청에서 다른 채널을 지정할 수 없다.
- 필수 설정이 없으면 API가 503을 반환하고 클라이언트는 기능 확인에 성공한 경우에만 툴바 버튼을 만든다. 소스와 빌드 결과에서 비밀값 문자열 점검 결과는 0건이었다.
- 전송 메시지는 길이·형식을 검증하고, 메시지 본문은 텍스트로 렌더링하며 첨부 링크는 HTTP/HTTPS만 허용했다.
- 메모장 저장은 UTF-8 기준 256KB 상한을 검증하고, 초과·필드 누락·비문자열 요청은 HTTP 400으로 거부한다. 저장 파일은 빌드 결과물이 아닌 저장소 밖 위치에 두고, 쓰기는 큐로 순서대로 처리하며 임시 파일 작성 후 이름 변경으로 교체한다.
- 채팅·메모장 패널에서 입력한 키 이벤트가 원격 기기로 전달되지 않도록 전파를 막았다.
- 소프트키보드 진단 로그는 이상 상황에만 최근 12회 플러시 요약을 남기며 입력 원문은 기록하지 않는다. 같은 한 글자 삽입이 2초 안에 8회를 넘으면 해당 입력만 차단하고 2초 뒤 자동 해제한다.
작업 기록
에뮬레이터 전원 패널 배치 수정
기기 목록 화면의 에뮬레이터 전원 패널(허용된 두 대의 상태 표시, 켜기·끄기와 끄기 재확인)이 목록 위에 있어 모바일에서 잘못 눌리던 문제를 고쳤다. 목록이 늦게 생성돼도 패널이 화면 맨 아래에 남도록 했고, 빌드는 통과했지만 실제 화면 배치는 아직 확인하지 못했다.
원격 화면 툴바에 Notes 메모장 추가
단일 텍스트 메모장을 추가하고 입력을 서버 쪽 파일에 자동 저장하게 했다. 256KB 초과와 잘못된 요청은 400으로 거부함을 확인했다.
소프트키보드 반복 입력 결함 수정과 회귀 복구
같은 글자가 저절로 반복 전송되던 결함을 모의 IME 하네스로 재현·수정하고, 그 가드가 만든 엔터 후 입력 먹통 회귀를 같은 날 복구해 서비스에 반영했다. 소스 변경은 한 파일이었다.
원격 화면 안 채팅 패널 구현
오른쪽 툴바에서 Discord 채널 대화를 읽고 쓰는 패널을 만들고, 인증은 서버가 전담하게 연결했다. 입력 검증, 채널 고정, 401 재로그인 횟수 제한을 임시 서버 테스트로 확인했다.
이 페이지는 작업 기록 문서 4건을 바탕으로 정리했습니다. 고객 정보, 접속 주소, 비밀값은 공개 전에 걸러 냅니다.