본문 바로가기
Android/Components

[안드로이드] App Components - Broadcast Receiver

by SungJe 2021. 6. 4.

Broadcast Receiver란?

안드로이드 개발자 사이트에서 Broadcast Receiver는 다음과 같이 설명하고 있다.

A broadcast receiver is a component that enables the system to deliver events to the app outside of a regular user flow, allowing the app to respond to system-wide broadcast announcements.
Link: Google Developer

즉, Broadcast Receiver는 시스템 또는 앱에서 발생한 이벤트에 대해 알림 역할을 수행한다. (e.g. 배터리 부족, 기기 충전)

Broadcast Receiver 수신

앱은 Manifest 선언 수신자와 Context 등록 수신자 두 가지 방법으로 브로드캐스트를 수신할 수 있다.

1. Manifest 선언 수신자

Manifest에 Broadcast Receiver를 선언하면 브로드캐스트가 전송될 때 앱이 아직 실행 중이 아니라면 시스템에서 앱을 실행한다.

1. 앱의 manifest에서 <receiver> 요소를 지정

<receiver android:name=".MyBroadcastReceiver"  android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
    </intent-filter>
</receiver>

2. BroadcastReceiver 서브클래스를 선언하고 onReceiver(Context, Intent) 메서드를 구현

private const val TAG = "MyBroadcastReceiver"

class MyBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        StringBuilder().apply {
            append("Action: ${intent.action}\n")
            append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n")
            toString().also { log ->
                Log.d(TAG, log)
                Toast.makeText(context, log, Toast.LENGTH_LONG).show()
            }
        }
    }
}    

2. Context 등록 수신자

1. BroadcastReceiver 인스턴스를 생성

val br: BroadcastReceiver = MyBroadcastReceiver()

2. IntentFilter를 생성하고 registerReceiver()를 호출하여 수신자 등록

val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).apply {
    addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED)
}
registerReceiver(br, filter)

3. 수신자가 더 이상 필요하지 않거나 Context가 더 이상 유효하지 않으면 unregisterReceiver()를 호출하여 등록을 취소

unregisterReceiver(br)

Broadcast Receiver 전송

Android는 브로드캐스트를 전송하는 세 가지 방법을 제공한다.

1. sendOrderedBroadcast(Intent, String)

한 번에 하나의 수신자에 브로드캐스트를 전송한다. 각 수신자는 차례로 실행되기 때문에 결과를 다음 수신자로 전파할 수 있다.

/* android.content.Context */
abstract fun sendOrderedBroadcast(
    intent: Intent!, 
    receiverPermission: String?
): Unit

Parameters

Parameters Description
intent Intent!: 브로드캐스트 인텐트, 인텐트와 일치하는 모든 리시버가 브로드캐스트를 수신한다.
receiverPermission String?: 선택적인 프로퍼티로 브로드캐스트 수신자가 보유해야 하는 사용 권한을 지정하는 문자열이다. null 값을 허용하며 null인 경우 권한이 필요없다.

2. sendBroadcast(Intent)

정의되지 않은 순서로 모든 수신자에 브로드캐스트를 전송한다. 상당히 효율적이지만 수신자가 다른 수신자의 결과를 읽거나 수신한 데이터를 전파할 수 없다.

/* android.content.Context */
abstract fun sendBroadcast(intent: Intent!): Unit

Parameters

Parameters Description
intent Intent!: 브로드캐스트 인텐트, 인텐트와 일치하는 모든 리시버가 브로드캐스트를 수신한다.

Example

Intent().also { intent ->
    intent.setAction("com.example.broadcast.MY_NOTIFICATION")
    intent.putExtra("data", "Notice me senpai!")
    sendBroadcast(intent)
}

3. LocalBroadcastManager.sendBroadcast

발신자와 동일한 앱에 있는 수신자에 브로드캐스트를 전송한다. 앱 간에 브로드캐스트를 전송할 필요가 없을 때 사용한다.

/* androidx.localbroadcastmanager.content.LocalBroadcastManager */
fun sendBroadcast(@NonNull intent: Intent): Boolean

Parameters

Parameters Description
intent Intent!: 브로드캐스트 인텐트, 인텐트와 일치하는 모든 리시버가 브로드캐스트를 수신한다.

Return

Return Description
Boolean 인텐트가 하나 이상의 브로드캐스트 리시버로 전송된 경우 true를 반환한다.

권한으로 브로드캐스트 제한

Permissions을 통해 특정 권한을 보유한 앱 집합으로 브로드캐스트를 제한할 수 있다.

Permissions을 사용하여 전송

sendBroadcast() 또는 sendOrderedBroadcast()를 호출할 때 권한 매개변수를 지정할 수 있다.

Sending App Source Code

sendBroadcast(Intent("com.example.NOTIFY"), Manifest.permission.SEND_SMS)

Sending App Manifest

<uses-permission android:name="android.permission.SEND_SMS"/>

Permissions을 사용하여 수신

registerReceiver()에 권한 매개변수를 지정하거나 manifest의 <receiver> 태그를 사용하여 권한을 지정하면 <uses-permission> 태그를 사용하여 권한을 요청한 브로드캐스트만 리시버에 인텐트를 전송할 수 있다.

Receiving App Source Code

var filter = IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)
registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null)

Receiving App Manifest

<receiver
    android:name=".MyBroadcastReceiver"
    android:permission="android.permission.SEND_SMS">

    <intent-filter>
        <action android:name="android.intent.action.AIRPLANE_MODE"/>
    </intent-filter>
</receiver>

Sending App Manifest

<uses-permission android:name="android.permission.SEND_SMS"/>

보안 고려사항 및 권장사항

  • 앱 외부의 컴포넌트에 브로드캐스트를 전송할 필요가 없다면 Support Library(androidx)에서 제공하는 LocalBroadcastManager를 사용하여 전송 및 수신한다.

  • 여러 앱이 자체 manifest에서 동일한 브로드캐스트를 수신하도록 등록하면 시스템에서 많은 앱을 실행하게 되며 기기 성능과 사용자 환경 모두에 상당한 영향을 줄 수 있다. manifest 선언보다 context 등록으로 사용하는 것이 좋다.

  • 브로드캐스트 작업의 네임스페이스는 전역이다. 작업 이름 및 기타 문자열이 고유한 네임스페이스에 작성되었는지 확인해야 한다. 의도하지 않게 다른 앱과 충돌할 수 있다.

  • 둘 이상의 리시버가 있다면 사용자 환경에 충돌이 발생하기 때문에 Broadcast Receiver에서 활동을 시작하지 않고 notification을 고려해야 한다.

참고 사이트