iOS에서 백그라운드 GPS 기록을 잃지 않고 하는 법
iOS는 언제든 기록 앱을 일시 중단하거나 종료할 수 있고, 미리 알려 줄 의무가 없다. 어디를 지나갔는지 받아 적는 것이 일인 앱에게 그것이 무슨 뜻인지, 그리고 실제로 한 번의 주행을 지켜 주는 것은 무엇인지.
기록을 시작하고 휴대폰을 주머니에 넣고 세 시간을 달린 뒤 꺼내 보면 앱에는 20분이 찍혀 있다. 휴대폰 기반 기록 앱에 대한 가장 흔한 심각한 불만이 이것이고, 원인이 GPS인 경우는 거의 없다.
iOS가 당신의 앱에 실제로 하고 있는 일
백그라운드에 들어간 iOS 앱은 그냥 느리게 도는 것이 아니다. 상태 사이를 옮겨 다닌다. 여전히 실행 중, 일시 중단됨(메모리에는 얼어붙어 있으나 아무것도 실행하지 않음), 그리고 종료됨(사라짐). 시스템은 메모리 압박, 발열 상태, 배터리, 그리고 자기 나름의 판단에 따라 앱을 이 상태들 사이로 옮기며, 미리 알려 줄 의무가 없다.
위치 백그라운드 모드를 가진 앱은 위치 갱신이 들어오는 동안 계속 실행될 자격을 얻는다. 애초에 이런 앱이 동작하는 원리가 그것이다. 일반적인 앱에 비하면 강력한 보장이다. 그러나 절대적인 보장은 아니다. 진짜 메모리 압박이 오면, 무거운 게임이나 카메라 앱이 뜨거나 램이 적은 기기라면, 기록 앱은 주행 도중에도 여전히 죽을 수 있다.
여기에서 정말 중요한 고장이 나온다. 앱이 주행을 메모리에 들고 있으면서 당신이 정지 버튼을 누를 때까지 아무것도 적지 않고 기다리고 있었다면, 마지막 저장 이후의 모든 것이 사라진다. 손상된 것이 아니다. 그냥 사라진 것이고, 오류 하나 뜨지 않는다. 그것을 알고 있던 프로세스가 더 이상 존재하지 않기 때문이다.
유일한 진짜 보호책: 도착하는 대로 적어 둔다
이것을 피해 갈 영리한 방법은 없다. 보호책은 애초에 저장되지 않은 데이터를 갖고 있지 않는 것이다.
Roam에서는 위치 콜백 하나가 배치 하나이고 데이터베이스 트랜잭션 하나다. 그리고 점들과 그 주행의 누적 수치가 함께 커밋된다. 주행이 끝나기를 기다리는 버퍼가 없고, 기록 경로 어디에도 점을 조용히 버리는 갈래가 없다. 커밋할 수 없는 배치는 삼켜지는 대신 오류를 일으키고 알람에 세워진다. 40킬로미터 지점에서 앱이 죽어도 40킬로미터는 이미 휴대폰 안에 있다.
누적 수치를 점들과 같은 트랜잭션에서 커밋한다는 것은 보이는 것보다 더 중요하다. 요약 행이 디스크에 없는 점들의 집합을 설명하는 일이 절대 생길 수 없다는 뜻이고, 그래서 강제 종료 이후에도 둘이 어긋나 있는 구간이 없다. 게다가 복구가 2만 8천 개의 점을 다시 재생하면서 어디까지 갔는지 계산할 필요도 없다. 그 행을 읽으면 된다.
같은 생각의 나머지 절반은 이것이다. 무엇도 삭제되지 않는다. 필터링, 평활화, 자동 일시정지는 데이터베이스에서 행을 지우지 않는다. 그것들은 점에 붙는 플래그로 기록되고, 원본 스트림은 도착한 그대로 남는다. 그래서 어떤 휴리스틱이 실제 주행을 잘못 판단했을 때 원래 표본이 아직 거기 있어서 다시 계산해 낼 수 있다. 자기가 동의하지 않은 표본을 조용히 버리는 앱은 자기가 틀렸다는 증거까지 없애 버린 것이다.
종료된 뒤 다시 일어서기
위치 권한을 "항상"으로 주었다면, 의미 있는 위치 변화가 발생했을 때 iOS가 종료된 앱을 백그라운드에서 다시 띄워 줄 수 있다. 이것은 진짜 구명줄이고, 아주 많은 기록 앱을 물어뜯은 함정을 하나 달고 온다.
그렇게 다시 띄워진 순간 앱에게는 시스템이 다시 중단시키기 전까지의 아주 짧고 예측 불가능한 시간만 주어진다. 그리고 결정적으로, 그 중단은 어떤 중단 지점에서든 일어날 수 있는데 요즘의 Swift에서 그것은 곧 모든 `await` 지점을 뜻한다. 다시 띄워진 뒤에 위치 관리자를 재구성하기 전에 비동기로 상태를 불러오는 앱은 그 도중에 얼어붙을 수 있고, 재무장 전에 중단된 프로세스는 GPS로부터 다시는 아무 소식도 듣지 못한다. 겉으로는 실행 중인 것처럼 보인다. 실제로는 아무것도 받고 있지 않다.
Roam의 재무장이 일부러 동기적으로 되어 있는 이유가 정확히 이것이다. 위치 관리자를 다시 만들고 갱신을 다시 시작하는 일이 첫 await 앞에서 끝나기 때문에, 그 실수는 권장되지 않는 정도가 아니라 아예 집어넣을 수 없게 된다. 또한 두 번 호출해도 안전하도록 쓰여 있는데, 백그라운드 재실행과 전면 실행이 겹치면 정확히 그런 일이 벌어지기 때문이다.
분명히 해 둘 것이 있다. "항상"은 보험이지 필수 조건이 아니다. "앱을 사용하는 동안"으로도 기록은 잘 된다. 그리고 이 앱은 더 강한 권한을 넘겨야 하는 것처럼 굴지 않고, 권한 안내문에 그 사실을 그대로 적어 둔다.
그리고 그것은 보장이 아니라 보험이며, 이 구분은 고집을 부릴 가치가 있다. Roam 자체의 설정에도 그 가정이 문장 그대로 적혀 있다. 다시 실행되지 않을 수도 있으며, 내구성만이 이 앱이 하는 유일한 약속이라고. iOS의 그 무엇도 종료된 앱을 다시 데려올 의무를 시스템에 지우지 않는다. 종료와 재실행 사이에 일어난 일은 아무도 기록하지 않았고, 어떤 API도 나중에 그것을 건네주지 않는다. 그러니 손에 남는 것은 종료 시점까지의 주행과 재실행 이후의 주행, 그리고 그 사이의 정직한 구멍이다. 이것을 매끄러운 이어 달리기처럼 설명하는 앱은 플랫폼이 제공하지 않는 무언가를 설명하고 있는 것이다.
사용자가 할 수 있는 것
- 긴 기록을 할 거라면 위치 권한을 "항상"으로 준다. 종료가 아무 대가도 치르지 않는 일이 되느냐, 남은 주행 전부를 앗아가느냐의 차이다.
- 가능하면 저전력 모드를 꺼 둔다. 켜져 있으면 백그라운드 작업이 잘려 나갈 가능성이 커진다.
- 주행 중에 앱 전환기에서 앱을 위로 밀어 닫지 않는다. 강제 종료는 사용자가 의도했다고 iOS에 알리는 행위이고, 그러면 백그라운드 재실행은 일어나지 않는다.
- 기록 앱을 두 개 동시에 돌리지 않는다. 두 앱이 GPS를 깨워 두면 소모 전력도, 둘 중 하나를 죽게 만드는 메모리 압박도 두 배가 된다.
- iOS를 업데이트한 뒤에는 권한을 확인한다. 업그레이드 과정에서 "항상"이 별다른 예고 없이 "사용하는 동안"으로 내려가는 일이 가끔 있다.
쓰고 있는 앱이 안전한지 확인하는 법
특별한 도구 없이 10분이면 직접 시험해 볼 수 있다. 기록을 시작하고 5분쯤 걸은 다음, 앱 전환기에서 앱을 강제 종료하고 다시 연다. 그 5분이 남아 있으면 그 앱은 가면서 쓰고 있었던 것이다. 기록이 비어 있거나 잘려 있으면 데이터를 메모리에 들고 있었던 것이고, 긴 주행에서 얼마를 잃게 되는지 이제 정확히 알게 된 셈이다.
기록 앱은 선언하는 것도 가능한 한 적어야 한다. 백그라운드 모드가 하나 늘어날 때마다 오용을 이유로 종료당할 여지가 생기고 앱 심사자가 물어볼 거리가 생긴다. Roam이 선언하는 것은 위치 하나뿐이며, 저장소에는 그 목록이 한 항목이라도 늘어나면 빌드를 실패시키는 빌드 게이트가 들어 있다.
자주 묻는 질문
아이폰이 백그라운드에서 왜 기록을 멈췄나요?
거의 언제나 메모리 압박 때문에 iOS가 앱을 중단하거나 종료했거나, 앱 전환기에서 강제 종료되었기 때문입니다. 위치 백그라운드 모드는 일반 앱보다 기록 앱을 훨씬 오래 살려 두지만 절대적인 보장은 아닙니다. 그래서 살아남는 것보다 앱이 측위점 하나하나를 어떻게 다루는지가 더 중요합니다.
주행을 기록하려면 위치 권한 "항상"이 필요한가요?
아닙니다. "앱을 사용하는 동안"만으로도 화면을 끈 채 기록할 수 있습니다. 위치 백그라운드 모드가 갱신이 들어오는 동안 앱을 살려 두기 때문입니다. "항상"은 앱이 종료되었을 때 iOS가 백그라운드에서 다시 띄울 수 있게 해 주는 것이므로, 필수 조건이라기보다 긴 주행을 위한 보험입니다.
백그라운드 GPS가 배터리를 많이 먹나요?
실제로 전력을 씁니다. 수신기가 계속 돌고 앱은 측위가 올 때마다 깨어납니다. 요즘 휴대폰이라면 몇 시간짜리 주행은 여유 있게 감당합니다. 문제가 되는 것은 하루 종일 이어지는 행사이고, 바로 거기서 가면서 쓰는 앱이냐 아니냐가 마지막 몇 분을 잃느냐 하루를 통째로 잃느냐를 가릅니다.
내 기록 앱이 데이터를 잃는지 어떻게 시험하나요?
기록을 시작하고 5분쯤 걸은 뒤 앱 전환기에서 강제 종료하고 다시 열어 보세요. 그 5분이 살아 있으면 그 앱은 가면서 씁니다. 살아 있지 않으면 주행을 메모리에 들고 있었던 것입니다.
주행을 잃지 않는 기록 앱
Roam은 측위점이 도착하는 그 순간, 주행 중인 누적 수치와 같은 트랜잭션으로 휴대폰에 기록합니다. 신호가 끊긴 구간은 직선으로 잇지 않고 끊긴 구간 그대로 남깁니다. 누적 상승은 GPS 고도가 아니라 기압 센서에서 읽습니다. 계정도, 로그인도, 동기화도 없습니다. 한 번의 주행을 온전히 기록하고, 보고, 다시 재생하는 것은 무료입니다.