<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Media-Controls on ICE-ICE-BEAR-BLOG</title><link>https://ice-ice-bear.github.io/ko/tags/media-controls/</link><description>Recent content in Media-Controls on ICE-ICE-BEAR-BLOG</description><generator>Hugo -- gohugo.io</generator><language>ko</language><lastBuildDate>Fri, 03 Apr 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://ice-ice-bear.github.io/ko/tags/media-controls/index.xml" rel="self" type="application/rss+xml"/><item><title>MediaFloat: Android 플로팅 미디어 컨트롤의 구조 분석</title><link>https://ice-ice-bear.github.io/ko/posts/2026-04-03-mediafloat-android/</link><pubDate>Fri, 03 Apr 2026 00:00:00 +0900</pubDate><guid>https://ice-ice-bear.github.io/ko/posts/2026-04-03-mediafloat-android/</guid><description>&lt;img src="https://ice-ice-bear.github.io/" alt="Featured image of post MediaFloat: Android 플로팅 미디어 컨트롤의 구조 분석" /&gt;&lt;h2 id="개요"&gt;개요
&lt;/h2&gt;&lt;p&gt;Android에서 음악을 들으며 다른 앱을 쓸 때 미디어 컨트롤에 접근하려면 알림 바를 내리거나 앱을 전환해야 한다.
&lt;strong&gt;MediaFloat&lt;/strong&gt;는 이 문제를 단 하나의 방법으로 해결한다: 이전/재생·일시정지/다음 버튼을 항상 화면 위에 떠 있는 작은 오버레이 바로 표시하는 것이다.&lt;/p&gt;
&lt;p&gt;Kotlin + Jetpack Compose로 작성된 오픈소스 앱으로, Android 10 이상을 지원하며 Apache License 2.0으로 배포된다.
GitHub 저장소: &lt;a class="link" href="https://github.com/Leuconoe/MediaFloat" target="_blank" rel="noopener"
 &gt;Leuconoe/MediaFloat&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="핵심-아키텍처"&gt;핵심 아키텍처
&lt;/h2&gt;&lt;p&gt;MediaFloat의 구조는 세 가지 Android 시스템 기능의 조합으로 이루어진다.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 A["사용자 미디어 앱&amp;lt;br/&amp;gt;(YouTube, Spotify 등)"] --&gt;|"미디어 세션 발행"| B["NotificationListenerService&amp;lt;br/&amp;gt;(미디어 세션 감지)"]
 B --&gt;|"재생 상태 / 트랜스포트 액션"| C["ForegroundService&amp;lt;br/&amp;gt;(오버레이 런타임)"]
 C --&gt;|"WindowManager 오버레이"| D["Compose UI&amp;lt;br/&amp;gt;(플로팅 컨트롤 바)"]
 D --&gt;|"이전 / 재생 / 다음"| B
 E["사용자 설정&amp;lt;br/&amp;gt;(Main / Settings / Advanced)"] --&gt;|"위치, 크기, 테마"| C&lt;/pre&gt;&lt;h3 id="세-가지-핵심-권한과-역할"&gt;세 가지 핵심 권한과 역할
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;권한 / 접근&lt;/th&gt;
 &lt;th&gt;역할&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;SYSTEM_ALERT_WINDOW&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;다른 앱 위에 오버레이 윈도우를 띄움&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FOREGROUND_SERVICE&lt;/code&gt; + &lt;code&gt;FOREGROUND_SERVICE_SPECIAL_USE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;오버레이 런타임을 지속적으로 유지&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;POST_NOTIFICATIONS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Foreground service 알림 표시 (Android 13+)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Notification listener access&lt;/td&gt;
 &lt;td&gt;활성 미디어 세션 상태와 트랜스포트 액션 읽기&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="android-overlay-구현-방식"&gt;Android Overlay 구현 방식
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;SYSTEM_ALERT_WINDOW&lt;/code&gt; 권한은 Android에서 &amp;ldquo;다른 앱 위에 표시&amp;rdquo; 권한으로 불린다.
이 권한을 얻으면 &lt;code&gt;WindowManager.addView()&lt;/code&gt;를 통해 시스템 레이어에 뷰를 삽입할 수 있다.&lt;/p&gt;
&lt;p&gt;MediaFloat는 여기에 &lt;strong&gt;Jetpack Compose&lt;/strong&gt;를 결합한다.
전통적인 XML 레이아웃 대신 Compose의 &lt;code&gt;AndroidView&lt;/code&gt; 또는 &lt;code&gt;ComposeView&lt;/code&gt;를 &lt;code&gt;WindowManager&lt;/code&gt;에 붙이는 방식으로 플로팅 UI를 렌더링한다.&lt;/p&gt;
&lt;h3 id="foreground-service의-역할"&gt;Foreground Service의 역할
&lt;/h3&gt;&lt;p&gt;Android는 백그라운드에서 UI를 표시하는 컴포넌트를 엄격하게 제한한다.
오버레이가 앱이 백그라운드에 있을 때도 유지되려면 반드시 &lt;strong&gt;Foreground Service&lt;/strong&gt; 안에서 실행되어야 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Foreground Service는 사용자에게 보이는 알림을 반드시 표시해야 한다&lt;/li&gt;
&lt;li&gt;Android 13+에서는 &lt;code&gt;POST_NOTIFICATIONS&lt;/code&gt; 권한이 추가로 필요하다&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FOREGROUND_SERVICE_SPECIAL_USE&lt;/code&gt; 타입은 overlay처럼 특수 용도의 서비스에 요구된다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="notificationlistenerservice로-미디어-세션-감지"&gt;NotificationListenerService로 미디어 세션 감지
&lt;/h3&gt;&lt;p&gt;미디어 앱들은 재생 상태를 &lt;code&gt;MediaSession&lt;/code&gt; API를 통해 시스템에 등록한다.
MediaFloat는 &lt;code&gt;NotificationListenerService&lt;/code&gt;를 통해 이 세션을 감지하고, &lt;code&gt;MediaController&lt;/code&gt;로 트랜스포트 액션(이전/재생·일시정지/다음)을 전송한다.&lt;/p&gt;
&lt;p&gt;이 경로 덕분에 Spotify, YouTube, 팟캐스트 앱 등 어떤 미디어 앱이든 동일한 인터페이스로 제어할 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="앱-구조-단일-모듈-다섯-가지-surface"&gt;앱 구조: 단일 모듈, 다섯 가지 Surface
&lt;/h2&gt;&lt;p&gt;MediaFloat는 의도적으로 단일 모듈(single-module) 구조를 선택했다.
복잡성을 낮추고 런타임 동작과 복구 경로를 명확하게 유지하기 위함이다.&lt;/p&gt;
&lt;h3 id="다섯-가지-앱-화면"&gt;다섯 가지 앱 화면
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 Main["Main&amp;lt;br/&amp;gt;오버레이 시작/중지&amp;lt;br/&amp;gt;준비 상태 확인"]
 Settings["Settings&amp;lt;br/&amp;gt;버튼 가시성, 크기&amp;lt;br/&amp;gt;불투명도, 동작"]
 Advanced["Advanced&amp;lt;br/&amp;gt;언어, 테마&amp;lt;br/&amp;gt;사이드바, 영속 모드"]
 Support["Support&amp;lt;br/&amp;gt;설정 안내&amp;lt;br/&amp;gt;버전, 라이선스"]
 Debug["Debug&amp;lt;br/&amp;gt;런타임 진단&amp;lt;br/&amp;gt;트랜스포트 명령"]

 Main --- Settings
 Settings --- Advanced
 Advanced --- Support
 Support --- Debug&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Debug&lt;/strong&gt; 화면이 특히 흥미롭다. 런타임 준비 상태, 미디어 세션 상태 점검, 트랜스포트 명령 직접 전송, 최근 이벤트 로그 확인 기능을 제공한다. 개발자 도구를 앱 안에 통합한 사례다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="자동화-연동-exported-action"&gt;자동화 연동: Exported Action
&lt;/h2&gt;&lt;p&gt;MediaFloat는 외부 자동화 도구와 연동할 수 있는 exported intent action을 제공한다:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sw2.io.mediafloat.action.SHOW_OVERLAY
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Android의 &lt;code&gt;ShortcutManager&lt;/code&gt;를 통해 런처 단축키도 두 가지 노출한다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Launch widget&lt;/code&gt; — 오버레이 시작&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Stop widget&lt;/code&gt; — 오버레이 중지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tasker, MacroDroid, Android Shortcuts 같은 루틴 도구에서 이 action을 직접 호출할 수 있다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="다국어-지원"&gt;다국어 지원
&lt;/h2&gt;&lt;p&gt;v0.2.1은 &lt;code&gt;AppCompat&lt;/code&gt; app-language API를 사용해 Android 13 이상과 그 이하 버전 모두에서 언어 전환을 지원한다.
지원 언어: System default, English, Korean, Chinese, Japanese, Spanish, French.&lt;/p&gt;
&lt;p&gt;한국어가 기본 지원 언어 목록에 포함된 것이 인상적이다.
언어 선택은 &lt;strong&gt;Advanced&lt;/strong&gt; 화면에서 가능하고, 현재 언어는 &lt;strong&gt;Support&lt;/strong&gt; 화면에 반영된다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="현재-버전의-의도적-제약"&gt;현재 버전의 의도적 제약
&lt;/h2&gt;&lt;p&gt;v0.2.1은 다음 기능을 의도적으로 포함하지 않는다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;자유로운 크기 조절 (사이즈 프리셋만 지원)&lt;/li&gt;
&lt;li&gt;여러 컨트롤 패밀리 (수평 단일 레이아웃만 지원)&lt;/li&gt;
&lt;li&gt;버튼 조합 자유 선택 (이전/재생·일시정지/다음 레이아웃에 한정)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;README에서 &amp;ldquo;intentionally constrained&amp;quot;라고 명시한 것은, 기능 추가보다 안정성과 이해 가능성을 우선한 설계 철학을 보여준다.&lt;/p&gt;
&lt;p&gt;최근 커밋을 보면 v0.3.0 릴리스 준비와 thumbnail 지원, 사이드바 스페이싱 정규화 작업이 진행 중이다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="기술-스택-요약"&gt;기술 스택 요약
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;항목&lt;/th&gt;
 &lt;th&gt;내용&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;언어&lt;/td&gt;
 &lt;td&gt;Kotlin&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;UI&lt;/td&gt;
 &lt;td&gt;Jetpack Compose + Material 3&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;대상 플랫폼&lt;/td&gt;
 &lt;td&gt;Android 10+&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;빌드 시스템&lt;/td&gt;
 &lt;td&gt;Gradle&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;라이선스&lt;/td&gt;
 &lt;td&gt;Apache License 2.0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;주요 Android API&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;SYSTEM_ALERT_WINDOW&lt;/code&gt;, &lt;code&gt;ForegroundService&lt;/code&gt;, &lt;code&gt;NotificationListenerService&lt;/code&gt;, &lt;code&gt;MediaController&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="마치며"&gt;마치며
&lt;/h2&gt;&lt;p&gt;MediaFloat는 Android overlay 개발의 좋은 학습 사례다.
&lt;code&gt;SYSTEM_ALERT_WINDOW&lt;/code&gt; + Foreground Service + NotificationListenerService 세 가지 시스템 기능을 조합하는 패턴은, 플로팅 UI를 구현하는 Android 앱에서 공통적으로 사용된다.&lt;/p&gt;
&lt;p&gt;Jetpack Compose를 WindowManager overlay에 적용하는 구체적인 구현, 자동화 도구와 연동하는 exported action 패턴, 그리고 Debug 화면을 앱 내에 통합하는 방식이 주목할 만하다.&lt;/p&gt;
&lt;p&gt;저장소에서 직접 빌드해 볼 수 있으며, 릴리스 서명 설정도 문서화되어 있다.&lt;/p&gt;</description></item></channel></rss>