시스템 · 앱 이벤트를 받는 컴포넌트.
class BootReceiver : BroadcastReceiver() {
override fun onReceive(ctx: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
WorkManager.getInstance(ctx).enqueue(syncRequest) // 일은 넘긴다
}
}
}
onReceive는 10초 안에 끝나야 한다
메인 스레드에서 불린다 10초를 넘기면 ANR 로 죽는다
onReceive 가 반환되는 순간 프로세스는 죽어도 되는 상태가 된다
- 여기서 코루틴을 띄우면 끝나기 전에 프로세스가 사라질 수 있다
올바른 형태: 판단만 하고 실제 작업은 WorkManager 로 넘긴다
// 조금 더 시간이 필요하면 goAsync()
override fun onReceive(ctx: Context, intent: Intent) {
val pending = goAsync()
CoroutineScope(Dispatchers.IO).launch {
try { doShortWork() } finally { pending.finish() } // 약 10초까지
}
}
매니페스트 등록은 대부분 막혔다
Android 8.0(O) 부터 대부분의 암시적 브로드캐스트를 매니페스트에 정적으로 등록할 수 없다
-
**왜 — 앱 수십 개가 CONNECTIVITY_CHANGE 하나에 동시에 깨어나**
- 배터리를 태우는 문제가 심각했다
-
예외로 남은 것 — BOOT_COMPLETED · LOCKED_BOOT_COMPLETED · MY_PACKAGE_REPLACED 등
// 그래서 대부분은 코드에서 동적 등록 + 반드시 해제
override fun onStart() {
super.onStart()
ContextCompat.registerReceiver(
this, receiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED),
ContextCompat.RECEIVER_NOT_EXPORTED // ★ Android 13+ 필수
)
}
override fun onStop() { super.onStop(); unregisterReceiver(receiver) }
unregisterReceiver 를 빠뜨리면
- "Activity has leaked IntentReceiver" 경고 + 메모리 누수
앱 내부 이벤트에는 쓰지 않는다
-
같은 앱 안의 통신에 브로드캐스트를 쓰면
- 시스템을 거치므로 느리다
- 타입 안전하지 않다 (Intent extra 문자열 키)
- 다른 앱에 새어 나갈 위험이 있다
-
SharedFlow · StateFlow · Repository 로 푼다
- LocalBroadcastManager 는 폐기됐다
면접 함정
- ❌ "onReceive에서 네트워크를 호출한다" → 메인 스레드 + 10초 제한 + 프로세스 종료 위험, 셋 다 걸린다.
- ❌ "동적 등록이면 앱이 꺼져도 받는다" → 등록한 컴포넌트가 살아 있는 동안만이다.
순서가 있는 브로드캐스트
sendOrderedBroadcast
- android:priority 순서로 하나씩 전달된다
- 앞의 수신자가 abortBroadcast() 로 중단할 수 있다
느리고 거의 쓰이지 않는다 — SMS 처리 같은 특수 사례
앱 간 통신에 쓸 때의 보안
// 보내는 쪽 — 권한으로 수신자를 제한한다
sendBroadcast(intent, "com.example.permission.MY_EVENT")
// 받는 쪽 — 명시적 패키지 지정
intent.setPackage("com.example.partner")
아무 제한 없이 sendBroadcast 하면
- 다른 앱이 그 브로드캐스트를 엿들을 수 있다
- extra 에 담긴 정보가 새어 나간다
Android 13 exported 강제
// 동적 등록에도 플래그가 필수가 됐다
ContextCompat.registerReceiver(ctx, receiver, filter,
ContextCompat.RECEIVER_NOT_EXPORTED) // 내 앱만 보낼 수 있다
// 또는 RECEIVER_EXPORTED (시스템 브로드캐스트를 받으려면 이쪽)
안 주면 targetSdk 34+ 에서 SecurityException 으로 크래시한다 시스템 브로드캐스트(BATTERY_CHANGED 등) 는 EXPORTED 여야 받는다