Skip to main content
← 블로그

할 일에 장소를 붙였습니다

VauDium ·

Apple Maps API로 주소 자동완성을 만들고, 지도 미리보기까지. 간단할 줄 알았는데 아니었습니다.

할 일에 장소를 붙였습니다

Fecit에는 원래 장소 입력란이 있었습니다. 텍스트를 자유롭게 쓸 수 있는 칸. “강남역 스타벅스”라고 쓰든, “집”이라고 쓰든 상관없는 자유 입력이었습니다.

그런데 주소를 정확히 쓰고 싶을 때가 있더라고요. 약속 장소나 처음 가는 곳. 그때마다 지도 앱을 열어서 주소를 복사하고 붙여넣는 건 번거로웠습니다.

그래서 자동완성을 붙이기로 했습니다.

Apple Maps를 선택한 이유

Google Maps가 가장 먼저 떠오르지만, 무료 범위가 좁고 결제 설정이 필요합니다. Apple Maps Server API는 하루 25만 건까지 무료이고, 글로벌 커버리지도 충분합니다. iOS와 Android 모두 지원하는 앱이니까 플랫폼에 종속되지 않는 것도 중요했고요.

한 가지 까다로운 점은 인증이 2단계라는 거였습니다. JWT를 만들어서 보내면 끝인 줄 알았는데, 먼저 JWT로 access token을 발급받고, 그 토큰으로 실제 API를 호출해야 합니다. 처음에 401 에러가 나서 한참을 헤맸습니다. 키 설정이 잘못된 줄 알고 Apple Developer 포털을 몇 번이나 확인했는데, 알고 보니 인증 방식 자체를 잘못 이해한 거였습니다.

서버 프록시

Apple Maps API 키를 앱에 넣을 수는 없으니까, 서버를 거치는 구조로 만들었습니다.

앱 → FastAPI 서버 → Apple Maps Server API

서버에서 JWT를 생성하고, access token을 캐싱하고, 앱에서는 자체 API를 호출하기만 하면 됩니다. 토큰은 30분간 재사용하니까 매번 발급하지 않습니다.

자동완성 UI

300밀리초 디바운스를 걸고, 2글자 이상 입력하면 검색합니다. 한글은 조합 중에 onChangeText가 계속 호출되는데, 디바운스가 이걸 자연스럽게 처리해줍니다.

드롭다운은 기존에 만들어둔 템플릿 추천 드롭다운 패턴을 따랐습니다. 입력란 아래에 검색 결과가 뜨고, 선택하면 주소가 입력됩니다.

여기서 예상 못한 문제를 하나 만났습니다.

높이가 안 늘어나는 TextInput

자동완성에서 긴 주소를 선택하면 텍스트가 여러 줄이 됩니다. multiline이 켜져 있으니까 당연히 높이가 늘어날 줄 알았는데, 안 늘어납니다. 텍스트는 줄바꿈이 되는데 입력란 크기는 한 줄 그대로.

신기한 건, 글자를 하나라도 직접 지우면 그때서야 늘어난다는 겁니다.

React Native의 iOS New Architecture(Fabric)에서 프로그래밍적으로 value를 바꿀 때 TextInput이 intrinsic content size를 재계산하지 않는 버그였습니다. 직접 타이핑하면 네이티브 텍스트 편집 플로우가 동작해서 높이가 맞춰지지만, JS에서 value prop을 바꾸면 다른 코드 경로를 타서 높이 재계산이 누락됩니다.

해결 방법은 보이지 않는 Text 컴포넌트를 하나 더 두고, onTextLayout으로 실제 줄 수를 측정해서 TextInput의 minHeight를 직접 설정하는 것이었습니다. 우회지만 안정적으로 동작합니다.

좌표 저장과 지도 미리보기

주소만 저장하면 아쉬우니까, Apple Maps가 응답에 포함하는 좌표도 함께 저장하기로 했습니다. addressLatitude, addressLongitude 필드를 Task 모델에 추가하고, 자동완성으로 선택할 때 좌표가 같이 들어갑니다.

좌표가 있으면 주소 입력란 아래에 미니 지도가 나옵니다. react-native-maps로 100px 높이의 작은 맵을 보여주고, 터치하면 전체화면 지도로 넘어갑니다.

주소를 비우면 좌표도 같이 초기화됩니다. 지도도 사라지고요. 직접 텍스트로 쓴 주소에는 좌표가 없으니 지도가 안 나옵니다. 자동완성을 쓸 때만 보이는 보너스 같은 느낌입니다.

현재 위치 기반 검색

처음에 “강남”을 검색했더니 미국 LA의 강남역이 나왔습니다. Apple Maps가 검색 위치를 모르니까 글로벌하게 결과를 주는 거였습니다.

expo-location으로 현재 위치를 가져와서 검색 요청에 좌표를 같이 보내니까, 한국에서 검색하면 한국 결과가 나옵니다. 위치 권한이 없어도 검색은 되고, 결과가 조금 덜 정확할 뿐입니다.

돌아보며

단순한 자동완성인 줄 알았는데, 인증 방식 이해, TextInput 높이 버그, 좌표 저장, 위치 기반 검색까지 생각보다 할 게 많았습니다.

그래도 결과는 만족스럽습니다. 주소를 선택하면 작은 지도가 뜨는 게 생각보다 기분이 좋더라고요. 할 일에 장소가 붙으면 뭔가 더 구체적으로 느껴집니다. “발표 준비”보다 “강남역 스타벅스에서 발표 준비”가 더 실감나는 것처럼요.


할 일에 장소가 생기면, 그 일이 조금 더 현실이 됩니다.