23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
Android Auto는 스마트폰의 앱을 차량의 디스플레이에 최적화된 형태로 보여주는 플랫폼입니다.
안드로이드 8(API 26) 이상의 휴대폰에 Android Auto 앱을 설치하고(대부분의 휴대폰에 기본 설치되어 있음) 호환 차량에 휴대폰을 연결하면,
운전자가 차량 화면을 통해 휴대폰의 지원 앱들을 사용할 수 있습니다.
휴대폰이 차량 UI에 투영되는 형태로 동작하며, 미디어 재생, 내비게이션, 메시징 등 운전에 적합한 앱 기능을 제공합니다.
Android Auto는 자체적으로 앱의 백엔드 로직을 가지고 있지 않고, 휴대폰 앱에 정의된 서비스를 호출해 콘텐츠를 표시하거나 제어합니다.
예를 들어 운전자가 차량 화면에서 음악 앱 아이콘을 탭하면, 차량 내 Android Auto 인터페이스가 음악앱(휴대폰)에 연결하여 음악 목록을 가져오고 재생 제어를 수행합니다.
Android Auto의 구성 요소는 크게 휴대폰 측 앱 서비스와 차량 측 UI로 나눌 수 있습니다.
휴대폰 측에서는 음악 재생을 처리하는 MediaBrowserService 와 Media3, ExoPlayer 같은 플레이어가 동작하고,
차량 측에서는 Android Auto가 제공하는 표준화된 UI 템플릿(리스트, 플레이어 컨트롤 등)을 통해 콘텐츠를 표시합니다.
이러한 구조 덕분에 앱 개발자는 차량용 별도 UI를 만들 필요 없이, 미디어 목록과 플레이어 제어만 적절히 제공하면 Android Auto가 알아서 표준 UI로 보여주게 됩니다.
요약하면, Android Auto는 휴대폰 앱을 차량과 연결해주는 브리지 역할을 합니다.
운전자는 차량 화면과 음성으로 앱을 제어하고, 실제 로직과 미디어 처리는 휴대폰 앱이 담당하는 형태입니다.
이를 통해 운전 중에도 운전자 친화적인 방식으로 음악앱의 음악 스트리밍 서비스를 즐길 수 있습니다.
차량 자체에 내장된 안드로이드 OS 입니다. 쉽게 말해, 차 안에 안드로이드 태블릿이 내장되어 있다고 보면 됩니다.
사용자들은 휴대폰이 아닌 차량의 PlayStore 에서 직접 앱을 설치하며, 앱이 차량의 하드웨어에서 독립적으로 실행됩니다.
예를 들어 볼보, 폴스타 등의 일부 차량은 Android Automotive OS 를 탑재하고 있어서, 휴대폰 연결 없이도 차량 자체에서 음악앱을 설치해 음악 스트리밍을 할 수 있습니다.
두 환경의 주요 차이점은 구동 위치와 앱 배포 방식입니다.
Android Auto 는 휴대폰 앱을 필요로 하고 차량은 단순히 디스플레이/컨트롤 역할을 하지만, Android Automotive OS 는 차량이 독립적인 안드로이드 디바이스로서 앱이 직접 구동됩니다.
따라서 Android Auto 용 앱은 일반 휴대폰 앱에 차량 연결용 서비스만 추가하면 되지만,
Android Automotive OS 용 앱은 차량전용으로 Bundling 및 배포가 필요하며 일부 UI 컴포넌트(예: 설정/로그인 화면 등)를 차내에서 구현해야 합니다.
구분 | Android Auto | Android Automotive OS |
|---|---|---|
구동 위치 | 스마트폰 앱 실행 | 차량 자체 OS (Android Automotive OS) |
앱 설치 위치 | 스마트폰 Google PlayStore | 차량 내장 PlayStore (Automotive 전용) |
차량 역할 | UI 표시 및 제어 중계 | 앱 실행, 미디어 재생, 하드웨어 제어 모두 차량 내 처리 |
연결 방식 | USB, Bluetooth, Wireless (Projection) | 독립적, 스마트폰 없이 사용 가능 |
대표 차량 | 대부분의 Android Auto 지원 차량 | Volvo, Polestar, GM 등 Automotive OS 탑재 차량 |
호환 차량 리스트: https://www.android.com/intl/ko_kr/auto/compatibility/#compatibility-vehicles
지원 앱 카테고리: Media, Messaging, Navigation 등 Google 승인 카테고리만 가능합니다.
특정 카테고리만 지원하며, Auto Car Head Unit 의 앱메뉴에서는 Auto 에서 사용가능한 앱만 표시됩니다.
UI 직접 제어 불가: Android Auto 가 제공하는 템플릿 UI만 사용 가능
휴대폰에서 전달하는 data 를 통해 Android Auto 에서 직접 UI 표시
운전자 안전 규정 준수 필수: 입력 제한, 항목 제한, 갱신 빈도 제한 등 적용
Google의 Android Auto 플랫폼에서는 운전자 안전을 최우선으로 고려하기 때문에 앱 개발 시 여러 가지 제한사항과 준수해야 할 가이드라인이 존재하며, 구글 심사 시 엄격하게 심사된다고 알려져 있습니다.
화면에 표시되는 목록 수 제한 (20개 이하 권장)
화면 갱신 빈도 제한 (3초 이상 간격 권장)
복잡한 사용자 입력 제한 (텍스트 입력 불가, 최소한의 버튼 제공)
etc.
가이드 라인: https://developers.google.com/cars/design/design-foundations/interaction-principles
Auto 용 앱으로 등록을 위해서는 음악을 재생하는 Service 에 아래와 같은 설정이 필요합니다.
<service android:name=".AdotMusicService"
android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>experted=true 설정
Auto system 에서 해당 Service binding 을 위해 필요
intent-filter 설정
Auto system 에서 해당 Service 를 인식하기 위한 필수 사항
class AdotMusicService : MediaBrowserServiceCompat() {
private lateinit var mediaSession: MediaSessionCompat
override fun onCreate() {
super.onCreate()
mediaSession = MediaSessionCompat(this, "AdotMusicService").apply {
// Callback 요청은 Auto 시스템에서 의해서 호출됨. 다른 곡 재생, play/stop 등 media 재생관련 처리를 여기서 진행
setCallback(object : MediaSessionCompat.Callback() {
override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) { /* 곡 재생 처리 */ }
override fun onPlay() { /* 재생 처리 */ }
override fun onPause() { /* 일시정지 처리 */ }
override fun onSeekTo(pos: Long) { /* 시크 처리 */ }
})
isActive = true
}
sessionToken = mediaSession.sessionToken
}
override fun onBind(intent: Intent?): IBinder? = if (isCarMode) super.onBind(intent) else null
// MediaBrowserServiceCompat 의 주요 함수 1.
override fun onGetRoot(clientPackageName: String, clientUid: Int, rootHints: Bundle?): BrowserRoot {
return BrowserRoot("root_id", null)
}
// MediaBrowserServiceCompat 의 주요 함수 2.
override fun onLoadChildren(parentId: String, result: Result<MutableList<MediaItem>>) {
val mediaItems = getChildrenForParent(parentId)
result.sendResult(mediaItems)
}
}Android Auto, Wear OS, Android TV 같은 외부 기기나 다른 앱이 당신의 앱의 오디오/비디오 콘텐츠를 탐색하고 제어할 수 있게 해주는 서비스 역할
미디어 플레이어와의 연결 허브
* MediaSessionCompat 를 함께 사용하여, 플레이, 일시정지, 다음곡 같은 제어를 받음
* Android Auto 는 MediaBrowserServiceCompat 를 통해 미디어 앱을 인식
역할 | 클래스 | 설명 |
|---|---|---|
미디어 탐색 서비스 | MediaBrowserServiceCompat | Auto, Wear, TV 같은 외부 클라이언트 연결 지점 |
미디어 제어 세션 관리 | MediaSessionCompat | Play, Pause, Next 등을 앱의 Player 와 연결 |
클라이언트 연결/탐색 | MediaBrowserCompat | 클라이언트가 앱의 MediaBrowserServiceCompat 연결 |
함수명 | 호출 시점 | 역할 |
|---|---|---|
onGetRoot() | Android Auto가 서비스에 연결할 때 최초 호출 | 미디어 트리 최상위 노드의 ID를 반환 |
onLoadChildren() | 특정 parentId 하위 미디어 요청 시 호출 | 하위 MediaItem 리스트를 반환 |
onSearch() | 차량 UI 또는 Google Assistant를 통한 음성 검색 시 호출 | 쿼리 결과를 준비 (결과 리스트는 별도로 onLoadChildren() 에서 반환) |
onPlayFromMediaId() | 특정 MediaItem 선택 시 호출 | 해당 미디어를 재생 |
MediaSessionCompat.Callback은 MediaBrowserServiceCompat와 연결된 MediaSession의 제어를 처리합니다.
Android Auto에서 사용자 입력(재생, 일시정지, 다음 곡 등)은 MediaSession을 통해 앱에 전달됩니다.
함수명 | 역할 | 비고 |
|---|---|---|
onPlay() | 재생 요청 처리 | MediaSession 활성화, Player resume 호출 |
onPause() | 일시정지 요청 | Player pause 호출 |
onSeekTo() | 특정 위치 이동 | Player seek 호출 |
onPlayFromMediaId() | 특정 미디어 ID 재생 요청 | MediaBrowser로 선택 시 호출 |
onPlayFromSearch() | 검색 결과 재생 요청 | Google Assistant 음성 명령 시 필수 |
Android 에서 제공하는 CarConnection class 를 통해 Auto 연결 상황을 observing 할 수 있습니다.
class AutoConnectionManagerImpl : AutoConnectionManager {
private val _connectType = MutableStateFlow(AutoConnectionType.NONE)
override val connectType = _connectType.asStateFlow()
private lateinit var carConnection: CarConnection
private lateinit var observer: Observer<Int>
override fun initialize(context: Context) {
carConnection = CarConnection(context)
observer = Observer { type ->
when (type) {
CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> AutoConnectionType.DISCONNECT // 연결 끊김
CarConnection.CONNECTION_TYPE_PROJECTION -> AutoConnectionType.CONNECT // 연결됨
else -> AutoConnectionType.DISCONNECT
}.apply {
_connectType.value = this // update
}
}
// Observe car connecting state
carConnection.type.observeForever(observer)
}
override fun destroy() {
if (::carConnection.isInitialized) {
carConnection.type.removeObserver(observer) // 앱 종료 시 종료
}
}
}차량 Android Auto UI → MediaBrowser 연결 → onGetRoot() 호출 → Root tree ID 획득
ID 는 리스트 형태로 전달 가능하며, 각 ID 들은 하위 카테고리의 ID 가 됨
차량 UI에서 카테고리 선택(하위 카테고리 ID) → onLoadChildren() 호출 → 카테고리에 해당 하는 MediaItem 리스트 반환
전달한 MediaItem 은 Auto UI 상에 리스트로 노출됨(List or Grid)
Google Assistant 를 통한 검색 요청 → onSearch() 호출 → 검색한 결과 리스트 전달 → Auto 에 검색결과 노출
검색 결과에 대한 분석은 Google Assistant 에서 처리하여 앱에 data 전달
"아이유의 너랑나 틀어줘"
artist: "아이유"
title: "너랑나"
사용자가 곡 선택 → onPlayFromMediaId() 호출 → Player에 재생 요청
MediaSession → PlaybackState, Metadata 업데이트 → 차량 UI에 실시간 반영
Auto 메인화면에 노출
추천목록은 앱내부에서 Control 할 수 없고 앱내부에서 설정한 리스트 아이템에서 재생가능한 아이템 중 임의로 pick 하여 노출
확인 시 모든 카테고리의 첫번째, 두번째 item 을 모아서 노출되고 있으나, Auto 시스템 마다 다를 수 있음
MediaSession 을 통해 queue 에 media item 지정 시 보여지는 화면
title 도 별도 지정 가능
하위 카테고리 Tree 구조를 가지는 화면
GRID/LIST type 으로 UI 표시 가능
Media Item 구성할 때 지정(Description)
Depth 의 지정은 제한되어 있지 않으나, Depth 가 클수록 사용자는 운전중 많은 interaction 이 필요하므로 지양 필요
최대 카테고리 개수는 시스템에서 내려주며, 현재 확인 시 최대 4개. 4개 이상은 카테고리로 지정할 수 없음
Play, Next, Previous 이외의 버튼(e.g. Favorite, Suffle, Repeat mode 등)은 Custom Action 을 추가하여 가능
// Add repeat custom action
customActionState.repeatMode?.let { repeatMode ->
addCustomAction(
PlaybackStateCompat.CustomAction.Builder(
CUSTOM_ACTION_REPEAT,
context.getString(R.string.music_noti_repeat),
when (repeatMode) {
Repeat.NONE -> AdotIcons.System.Close.Line
Repeat.ONE -> AdotIcons.Media.RepeatOnce.Line
Repeat.ALL -> AdotIcons.Media.Repeat.Line
}
)
.setExtras(bundleOf(CUSTOM_ACTION_REPEAT_EXTRA_CURRENT to repeatMode.name))
.build()
)
} MediaSession 을 통해 Error 상황을 사용자에게 노출할 수 있음
mediaSession?.setPlaybackState(
PlaybackStateCompat.Builder()
.setState(
PlaybackStateCompat.STATE_ERROR, // error
0L,
0f,
)
.setErrorMessage(errorCode, message) // 사용자에게 노출됨 message 지정
.build()
)Auto System 에서 앱의 Service 에 Binding 하여 여러 요청을 진행하기 때문에 binder 객체를 반드시 전달 해야합니다.
class AdotMusicService : MediaBrowserServiceCompat() {
...
// exported 상태인 Service 이므로 Auto system 연결 시에만 Binding 가능하도록 함
override fun onBind(intent: Intent?): IBinder? = if (isCarMode) super.onBind(intent) else null
}Auto System 에서 Media App 으로 동작 시 음악 재생은 AudioManager.AUDIOFOCUS_GAIN 으로 요청되어야 Auto System 에서 Media 로 인식하여 올바르게 동작합니다.
다른 Focus 로 요청 시에 Media 로 인식하지 않아 차량에서 Media 재생이 아닌 다른 형태로 재생사운드가 노출되고, 차량의 Media Control Key(핸들등에 존재하는 재생/이전/다음 버튼)가 동작하지 않습니다.
Google Assistant 를 통한 발화동작으로 "아이유 노래 틀어줘" 와 같은 발화시도 시 앱으로 event 가 전달되게 설정하려면 Manifest 설정이 필요합니다.
// Manifest 에 아래 intent-filter 등록을 하지 않으면 onPlayFromSearch() 호출이 되지 않는다.
<activity
android:name=".ui.MusicPlayerActivity"
...>
<!-- MediaSession callback 에서 Google Assistant 를 통한
onPlayFromSearch callback 을 받기 위해 추가. service 에 등록 시 미동작 -->
<intent-filter>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>Service 에 등록하면 onPlayFromSearch() 미호출. 아무 activity 에나 추가하면 동작됩니다.
onGetRoot 에서 android.media.browse.SEARCH_SUPPORTED 를 bundle 에 포함하여 전달하는 경우 발화 시도 시 onSearch 함수가 호출됩니다.
결과 지정 시 Player 화면에 '검색 결과' 버튼이 노출되며 클릭 시, 지정한 리스트가 노출됩니다.
/**
* onGetRoot 에서 [MediaConstants.BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED] 설정 시 호출됨
* "검색결과" 항목이 Auto 의 Playback 에 생김
* "아이유 노래 틀어줘" -> "아이유" query 가 넘어옴
*/
override fun onSearch(
query: String,
extras: Bundle?,
result: Result<MutableList<MediaBrowserCompat.MediaItem>>
) {
// result parameter 에 검색결과 list 설정 필요
result.sendResult(searchList)
}차량에 항상 연결하여 개발을 진행하기엔 어려움이 존재합니다.
그래서 Android 에서는 PC 환경에서 사용가능한 Desktop Head Unit(DHU) emulator 를 제공하고 있습니다.
Android Studio 에서 DHU 설치
휴대폰에서 Android Auto 개발자 모드 활성화 + 헤드 유닛 서버 시작
일반 개발자 모드 활성화와 같이 개발자 메뉴 활성화를 위해 'Android Auto' 설정의 '버전 정보' 여러번 클릭
이후 우측 상단 메뉴 클릭 후 '헤드 유닛 서버 시작' 메뉴 선택
정상 실행 시 헤드 유닛 서비스가 Notification 에 노출
CLI 를 통한 DHU 실행
// port 지정(고정값)
adb forward tcp:5277 tcp:5277
// DHU 실행
mac: /Users/xxx/Library/Android/sdk/extras/google/auto/desktop-head-unit
windows: C:\Users\xxx\AppData\Local\Android\Sdk\extras\google\auto\desktop-head-unitDHU 실행 경로는 Android SDK 가 설치된 PC 환경마다 다르므로 확인이 필요합니다.
https://developers.google.com/cars/design/android-auto?hl=ko
https://developers.google.com/cars/design/design-foundations?hl=ko
https://developer.android.com/training/cars/testing?hl=ko
SKT 에이닷 앱의 Android Auto 연동 내부 개발 및 테스트 환경 기준으로 작성되었으며, 실제 상용 배포된 기능은 아닙니다. Android Auto 의 이해와 Media 서비스 개발 시 참고용으로 작성되었습니다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.