안드로이드의 동반 기기(companion device) 전용 API. 스마트워치·밴드를 위해 만들어졌는데, 차량 앱이 정확히 같은 형태다 — 특정 기기 딱 하나와 오래 붙어 있어야 한다.
왜 필요한가 — 안드로이드가 조여 온 배경
안드로이드는 배터리 때문에 백그라운드 동작을 계속 제한해 왔다.
Android 6 Doze — 화면이 꺼지고 정지해 있으면 네트워크·알람을 묶는다
Android 8 백그라운드 서비스 실행 제한
Android 10 백그라운드 위치 접근 제한
Android 12 BLE 스캔이 런타임 권한으로 분리
Android 14 포그라운드 서비스 타입 선언 의무화
Android 15 백그라운드에서 포그라운드 서비스 시작 차단
"연결을 계속 유지한다"를 직접 구현하려 하면 이 층들과 전부 싸워야 한다. CDM 은 그 싸움을 안 하게 해 주는 공식 통로다.
무엇을 주나
| 얻는 것 | 직접 구현했다면 |
|---|---|
| 근접 이벤트 | 앱이 계속 스캔해야 한다 (배터리) |
| 위치 권한 불필요 | BLE 스캔에 위치 권한을 요구받는다 |
| 자동 서비스 바인딩 | 상시 서비스를 붙들고 있어야 한다 |
| 백그라운드 제약 면제 | 사용자에게 배터리 예외 등록을 부탁해야 한다 |
시스템이 대신 스캔한다는 게 요점이다. 앱은 자고 있고, 차가 가까워지면 시스템이 앱을 깨운다.
자동으로 부여되는 권한 셋
페어링이 성공하면 매니페스트에 쓰지도, 사용자에게 묻지도 않았는데 아래가 부여된다.
REQUEST_COMPANION_RUN_IN_BACKGROUND 백그라운드 실행
REQUEST_COMPANION_USE_DATA_IN_BACKGROUND 백그라운드 네트워크
REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND ★ Android 15 우회
마지막 것이 결정적이다. Android 15 가 전면 차단한 "백그라운드에서 포그라운드 서비스 시작"을, 동반 기기 앱만 예외로 허용받는다. 이게 없으면 부팅 직후 차가 가까이 있어도 앱이 스스로 못 뜬다.
앱을 지우거나 disassociate() 를 호출하면 회수된다. 사용자가 명시적으로 "이 기기와 짝을 맺겠다"고 고른 대가로 주어지는 권한이라, 짝이 풀리면 같이 사라진다.
페어링 — 기기 목록을 우리가 안 그린다
associate() 를 호출하면 시스템이 기기 선택 UI 를 띄운다. 사용자가 목록에서 자기 차를 고르는 순간 위 권한들이 부여된다.
AssociationRequest → 필터(이름 패턴·MAC·서비스 UUID) + setSingleDevice(true)
↓
onAssociationPending(IntentSender) 시스템 UI 를 띄운다
↓ 사용자가 선택
onAssociationCreated(AssociationInfo) 이후는 info.id 로 관리한다
앱이 주변 기기 목록을 직접 보지 못한다는 게 이 설계의 프라이버시 근거다. 사용자가 고른 하나만 앱에 넘어간다. 그래서 위치 권한을 안 물어도 되는 것이다.
근접 감시 — API 36 에서 바뀌었다
구 startObservingDevicePresence(String) · onDeviceAppeared/Disappeared
API 36 startObservingDevicePresence(ObservingDevicePresenceRequest)
onDeviceEvent(DevicePresenceEvent)
구 API 는 deprecated 다. 구버전도 지원하려면 두 경로를 다 둔다.
남는 제약
권한은 필요 없지만 위치 서비스 자체는 켜져 있어야 한다. BLE 스캔이 시스템 위치 스택 위에서 동작하기 때문이다. 사용자가 위치를 꺼 두면 근접 감지가 멈춘다.