앱 또는 시스템에서 발생한 이벤트를 감지하고 처리할 수 있는 컴포넌트로, 일반적으로 Intent 객체를 사용하여 메세지를 수신한다. 해당 객체에는 처리할 이벤트에 대한 정보와 데이터를 담고 있다.
주로 비동기적으로 메세지를 주고받을때나, 앱이 실행 중이 아닌 상태에서 특정 이벤트를 감지하기 위해 사용된다.
ON/OFFON/OFF 감지 : 화면 ON/OFFAlarmManager를 사용해 특정 시간에 전송Broadcast를 수신할 수 있어 앱간 통신 가능Broadcast를 순차적으로 실행할 수 있으며, 중간에 데이터 변경 가능BroadcastReceiver는 앱이 실행 중일 때만 동작함sendBroadcast() 사용 시 다른 앱이 가로챌 수 있어 LocalBroadcastManager또는 sendBroadcast(intent, permission) 이렇게 사용해야함BroadcastReceiver는 일회성 이벤트 감지용으로 긴 작업을 수행하면 ANR이 발생할 수 있어, 긴 작업의 경우 IntentService와 함께 사용해야함Android 8.0(API 26)부터 Mainfest에 등록된 Broadcast중 일부는 동작이 제한되었으며, registerReceiver()를 사용한 동적 등록이 필요함Android 14부터는 Cache 상태인 앱에는 시스템 Broadcast가 즉시 전달되지 않을 수 있다.Broadcast는 Cache 상태에서 빠져나와야 전달되고, 중요도 높은 Broadcast를 수신한 경우에는 Cache 상태를 잠시 해제함앱이 실행중이지 않아도 이벤트 감지가 가능하다. 다만 정적 등록에 대한 제한사항이 존재한다.
Manifest
<!-- 시스템 혹은 다른 앱의 broadcast를 수신하는 경우에는,
android:exported = "true" 설정이 필요하다. -->
<receiver android:name=".BootReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
BoostReceiver
class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
Log.d("BootReceiver", "디바이스 부팅 완료됨!")
}
}
}
앱이 실행 중일 때만 동작하며, 앱 종료 시 Receiver 해제가 필요하다. 특정 Activity 또는 Service 내에서만 작동하도록 제한할 수 있다.
ex) 네트워크 상태 변경 감지
class MainActivity : AppCompatActivity() {
private val networkReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("NetworkReceiver", "네트워크 상태 변경됨!")
}
}
override fun onResume() {
super.onResume()
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
registerReceiver(networkReceiver, filter)
}
override fun onPause() {
super.onPause()
unregisterReceiver(networkReceiver)
}
}
registerReceiver()를 사용하여 실행 중일 때만 이벤트 감지
unregisterReceiver()로 해제하지 않으면 메모리 누수가 발생할 수 있어 주의 요망
앱 내부에서만 데이터를 주고받을 때 사용하며, 외부 앱의 Broadcast를 막아 보안성을 높일 수 있다.
val intent = Intent("com.example.ACTION_CUSTOM")
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
BroadcastReceiver에서 감지
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("LocalBroadcast", "내부 이벤트 발생 감지됨!")
}
}
val filter = IntentFilter("com.example.ACTION_CUSTOM")
LocalBroadcastManager.getInstance(context).registerReceiver(receiver, filter)
모든 등록된 BoradcastReceiver에 동시에 비순차적으로 전달되며, 리시버가 다른 리시버에게 데이터를 넘기지 못하기 때문에 데이터 변경이 불가능하다.
주로 알람, 네트워크 변경 등 빠른 이벤트 전달이 필요한 경우 적합하다.
val intent = Intent("com.example.CUSTOM_ACTION")
sendBroadcast(intent) // 여러 개의 리시버가 동시에 처리
BroadcastReceiver에서 감지
class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d("MyReceiver", "Broadcast 수신됨!")
}
}
다만 위처럼 그냥 사용하면 보안상 이슈가 있을 수 있어, sendBroadcast(Intent, String permission) 형태로 사용하여 특정 권한이 있는 앱만 수신 가능하도록 설정해 사용하는게 좀 더 바람직 하다.
val intent = Intent("com.example.SECURE_ACTION")
sendBroadcast(intent, "com.example.MY_CUSTOM_PERMISSION")
manifest
<permission
android:name="com.example.MY_CUSTOM_PERMISSION"
android:protectionLevel="signature"/>
<receiver android:name=".SecureReceiver">
<intent-filter>
<action android:name="com.example.SECURE_ACTION"/>
</intent-filter>
<permission android:name="com.example.MY_CUSTOM_PERMISSION"/>
</receiver>
우선순위를 적용하여 순차적으로 전달할 수 있으며, 여러개의 BroadcastReceiver가 우선순위에 따라 순서대로 실행된다. 다음 리시버로 데이터를 넘길 수 있기 때문에(setResultData(), getResultData()) 데이터 변경이 가능하다.
해당 방식도 위와 동일하게 permission을 매개변수로 추가하여 보안을 강화할 수 있다.
주로 우선순위를 두고 특정 리시버에서 데이터를 조작해야할 경우 적합하다.
val intent = Intent("com.example.ORDERED_ACTION")
sendOrderedBroadcast(intent, null)
manifest 설정
<receiver android:name=".FirstReceiver" android:priority="2">
<intent-filter>
<action android:name="com.example.ORDERED_ACTION"/>
</intent-filter>
</receiver>
<receiver android:name=".SecondReceiver" android:priority="1">
<intent-filter>
<action android:name="com.example.ORDERED_ACTION"/>
</intent-filter>
</receiver>
첫번째 리시버
class FirstReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d("FirstReceiver", "FirstReceiver 실행됨!")
setResultData("데이터 변경됨") // 다음 리시버에게 데이터 전달 가능
}
}
두번째 리시버
class SecondReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val data = getResultData()
Log.d("SecondReceiver", "SecondReceiver 실행됨! 받은 데이터: $data")
}
}