갈피노트
Back to Home
iOS Development • 2026년 4월 7일

안써본 기능도 AI가 뚝딱. 아이폰 GPS '항상 허용' 테스트앱 만들기.

#iOS #CoreLocation #지오펜싱 #GPS #SwiftUI #ClaudeCode #xcodebuildmcp #vibecodin

[이미지는 chatGPT가. 뭐야. 야 너, 왜 이렇게 좋아졌어]

iOS 개발을 해오면서, GPS 권한 중에 '항상 허용'을 써본 적이 단 한 번도 없다.

생각해보면 그럴 만도 한게, '앱 사용 중 허용'으로도 대부분의 기능이 다 되니까. 굳이 '항상 허용'을 써야 하는 케이스가 별로 없었다.

그리고 내가 '항상 허용'을 싫어했다.

왜 내 위치를 항상 알고 싶은건데?! 난 알려주고 싶지 않다고.

하지만 그것도 월급 앞에선 무력하다. 해보란다.

그래 뭐.

귀찮으니까 클로드 코드한테 시켜봤다.

만들어달라고 한 것

요구사항은 단순하게 정리.

- 점심 먹으러 갈 식당이랑 식사 후 갈 카페 위치를 등록

- 폰 들고 그 장소에 도착하면 알림이 뜨는 앱

- iOS 16, Swift, SwiftUI

- 설정한 위치의 반경 10미터, local notification

- 빌드 테스트는 xcodebuildmcp로 알아서

xcodegen이 깔려있고 xcodebuildmcp를 붙여놓은 덕분에 클로드가 알아서 project.yml 만들고, xcodegen으로 프로젝트 생성하고, 시뮬레이터에 빌드해서 띄워줬다.

세상 참... 좋아졌다.

그런데 '항상 허용'이 안 나오네?

테스트 앱이 떴는데, 권한 요청 버튼을 눌렀더니 '앱 사용 중', '한 번 허용', '허용 안함'만 나오는 거다.

"항상 허용 안 나오는데?"

클로드: "iOS 13부터는 첫 다이얼로그에 '항상 허용'이 안 나옵니다."

이런건 얘가 지 멋대로 말할 때가 있다. 그래, 내가 메시지를 잘못 던졌지.

- 음, 진짜야? 한 번 더 검색해봐.

Tavily MCP 사용해서 한 번 더 체크.

오... 진짜였다.

iOS 13부터 Apple이 개인정보 보호 명목으로 다이얼로그를 두 단계로 쪼개놨다.

1. 먼저 '앱 사용 중 허용'을 받고

2. 나중에 앱이 백그라운드에서 위치를 사용하는 권한요청을 해야 시스템이 두 번째 다이얼로그를 띄워서 '항상 허용으로 변경'을 묻는다.

// 1단계
manager.requestWhenInUseAuthorization()
// 사용자가 '앱 사용 중 허용' 선택 후, 별도 액션으로
// 2단계
manager.requestAlwaysAuthorization()

지오펜싱 백그라운드 처리

앱이 종료되거나 백그라운드에 있을 때 처리 때문에 배터리가 많이 달지 않을까 생각했다.

일단,

지오펜싱은 시스템 데몬locationd)이 처리한다.

앱: CLCircularRegion 등록
→ locationd에 region 정보 전달
→ 앱은 끝. 더 이상 GPS 안 씀
locationd: GPS/Wi-Fi/Cell tower 조합으로 위치 추적
→ 등록된 region boundary 교차 감지
→ 앱 프로세스를 wake-up (terminated 상태면 relaunch)
→ didEnterRegion 콜백 호출

그러니까 앱은 startMonitoring(for:) 한 번만 호출하고 손 떼면, 나머지는 다 시스템이 알아서 한다. 와, 이게 되네.

배터리는?

연속 GPS 추적startUpdatingLocation()은 배터리 잡아먹는 주범일 줄 알았다.

내가 Google Maps 타임라인 항상허용 켜봐서 아는데... 아니었다.

지오펜싱은 이벤트 드리븐 방식이라 거의 안 먹는다.

GPS를 상시 켜는 게 아니라 Wi-Fi/Cell/GPS를 조합해서 boundary 교차만 감지하는 거니까. 사용자가 boundary를 넘고 20초 정도 그 자리에 있어야 트리거되도록 해서 노이즈도 줄인다.

10m 반경처럼 극소 범위는 시스템이 정밀 GPS를 더 자주 켤 수 있어서 약간 더 먹긴 한다는데, 그래도 연속 추적 대비 무시할 수준이라고.

### 앱이 죽어있어도 알림이 온다고?

여기서 또 궁금증.

"앱이 메모리에서 완전히 해제되어도 알림이 와?"

답은 "온다, 단 조건이 있다."

locationd가 boundary 교차를 감지하면 iOS가 앱을 백그라운드에서 relaunch한다.

application(_:didFinishLaunchingWithOptions:)이 호출되고, launchOptions.location 키가 들어온다.

그러면서 위험경고를 하는데, 앱이 빠르게 CLLocationManager delegate를 연결해야 pending region event를 받을 수 있다는 거다.

오... 이런거 처음 받아봤어.

처음에 LocationManagerContentView@StateObject로 만들었는데, 클로드가 이건 위험하다고 했다.

SwiftUI View body가 평가되는 시점에 따라 delegate 연결이 늦어질 수 있어서.

그래서 App 레벨로 끌어올렸다.

라는걸 추천하길래 그대로 작업 지시.

@main
struct AlwaysGPSTestApp: App {
@StateObject private var locationManager = LocationManager()
var body: some Scene {
WindowGroup {
ContentView(locationManager: locationManager)
}
}
}

점심에 순대국 먹으러 가서 알림 확인하고, 카페 들려서 알림 확인하고 왔다.

스크린샷은 찍었는데, 배경화면이 덕밍아웃이라 알림 스크린샷 첨부는 패스.

결론

아직 모바일 앱을 Native, Swift와 SwiftUI로 만드는 건 잘 못한다는 생각을 하고 있었는데,

오늘은 이상하게 잘 만들어줬다는 결론.

잡다한 설명이나 경고도 주고 말이야.

얘도 바이오리듬같은게 있나? 주말에 좀 쉬었니?

Comments