브로드캐스트 개요

Android 앱은 게시-구독 디자인 패턴과 유사하게 Android 시스템 및 기타 Android 앱에서 브로드캐스트 메시지를 주고받습니다. 시스템과 앱은 일반적으로 특정 이벤트가 발생할 때 브로드캐스트를 전송합니다. 예를 들어 Android 시스템은 시스템 부팅 또는 기기 충전과 같은 다양한 시스템 이벤트가 발생할 때 브로드캐스트를 전송합니다. 앱은 맞춤 브로드캐스트를 전송하여 다른 앱이 관심을 가질만한 사항 (예: 새 데이터 다운로드)을 관련 앱에 알릴 수도 있습니다.

앱은 특정 브로드캐스트를 수신하도록 등록할 수 있습니다. 브로드캐스트가 전송되면 시스템은 특정 유형의 브로드캐스트를 수신하도록 신청한 앱에 브로드캐스트를 자동으로 라우팅합니다.

일반적으로 브로드캐스트는 앱 전체에 걸쳐 그리고 일반 사용자 플로우 외부에서 메시징 시스템으로 사용될 수 있습니다. 그러나 브로드캐스트에 응답하고 백그라운드에서 시스템 성능 저하의 원인이 될 수 있는 작업을 실행하는 기회를 남용하지 않도록 주의해야 합니다.

시스템 브로드캐스트 정보

시스템이 비행기 모드로 전환하고 비행기 모드를 해제할 때와 같이 다양한 시스템 이벤트가 발생하면 시스템은 자동으로 브로드캐스트를 전송합니다. 구독한 모든 앱은 이러한 브로드캐스트를 수신합니다.

Intent 객체는 브로드캐스트 메시지를 래핑합니다. action 문자열은 발생한 이벤트를 식별합니다(예: android.intent.action.AIRPLANE_MODE). 인텐트에는 추가 필드에 번들로 제공되는 추가 정보가 포함될 수도 있습니다. 예를 들어 비행기 모드 인텐트에는 비행기 모드가 켜져 있는지 여부를 나타내는 불리언 추가 항목이 포함됩니다.

인텐트를 읽고 인텐트에서 작업 문자열을 가져오는 방법에 관한 자세한 내용은 인텐트 및 인텐트 필터를 참고하세요.

시스템 브로드캐스트 작업

시스템 브로드캐스트 작업의 전체 목록을 보려면 Android SDK의 BROADCAST_ACTIONS.TXT 파일을 참고하세요. 각 브로드캐스트 작업에는 연결된 상수 필드가 있습니다. 예를 들어 상수 ACTION_AIRPLANE_MODE_CHANGED의 값은 android.intent.action.AIRPLANE_MODE입니다. 각 브로드캐스트 작업에 관한 문서는 연결된 상수 필드에서 확인할 수 있습니다.

시스템 브로드캐스트 변경사항

Android 플랫폼이 발전함에 따라 시스템 브로드캐스트의 작동 방식이 주기적으로 변경됩니다. 모든 Android 버전을 지원하려면 다음 변경사항에 유의하세요.

Android 14

앱이 캐시된 상태에 있는 동안 시스템은 시스템 상태에 맞게 브로드캐스트 전송을 최적화합니다. 예를 들어 시스템은 앱이 캐시된 상태일 때 ACTION_SCREEN_ON과 같이 덜 중요한 시스템 브로드캐스트를 지연합니다. 앱이 캐시된 상태에서 활성 프로세스 수명 주기로 전환되면 시스템은 지연된 브로드캐스트를 전송합니다.

매니페스트에서 선언된 중요한 브로드캐스트는 전송을 위해 일시적으로 캐시된 상태에서 앱을 삭제합니다.

Android 9

Android 9 (API 수준 28)부터 NETWORK_STATE_CHANGED_ACTION 브로드캐스트는 사용자의 위치 또는 개인 식별 데이터에 관한 정보를 수신하지 않습니다.

앱이 Android 9.0 (API 수준 28) 이상을 실행하는 기기에 설치된 경우 시스템은 Wi-Fi 브로드캐스트에 SSID, BSSID, 연결 정보 또는 검색 결과를 포함하지 않습니다. 이 정보를 얻으려면 대신 getConnectionInfo()를 호출해야 합니다.

Android 8.0

Android 8.0 (API 수준 26)부터 시스템은 매니페스트에 선언된 수신자에 추가 제한을 적용합니다.

앱이 Android 8.0 이상을 타겟팅하면 매니페스트를 사용하여 대다수 암시적 브로드캐스트 (앱을 구체적으로 타겟팅하지 않는 브로드캐스트)의 수신자를 선언할 수 없습니다. 사용자가 앱을 적극적으로 사용할 때 개발자는 컨텍스트에 등록된 수신자를 계속 사용할 수 있습니다.

Android 7.0

Android 7.0 (API 수준 24) 이상에서는 다음과 같은 시스템 브로드캐스트를 전송하지 않습니다.

또한 Android 7.0 이상을 타겟팅하는 앱은 registerReceiver(BroadcastReceiver, IntentFilter)를 사용하여 CONNECTIVITY_ACTION 브로드캐스트를 등록해야 합니다. 매니페스트에 수신자를 선언해도 작동하지 않습니다.

브로드캐스트 수신

앱은 두 가지 방식으로, 즉 컨텍스트에 등록된 수신자 및 매니페스트에 선언된 수신자를 통해 브로드캐스트를 수신할 수 있습니다.

컨텍스트에 등록된 수신자

컨텍스트에 등록된 수신자는 등록 컨텍스트가 유효한 동안 브로드캐스트를 수신합니다. 이는 일반적으로 registerReceiver 호출과 unregisterReceiver 호출 사이에 있습니다. 시스템에서 상응하는 컨텍스트를 소멸하면 등록 컨텍스트도 무효화됩니다. 예를 들어 Activity 컨텍스트 내에 등록하면 활동이 활성 상태로 유지되는 한 브로드캐스트를 수신합니다. Application 컨텍스트에 등록하면 앱이 실행되는 동안 브로드캐스트를 수신합니다.

수신자를 컨텍스트에 등록하려면 다음 단계를 따르세요.

  1. 앱의 모듈 수준 빌드 파일에 AndroidX Core 라이브러리 버전 1.9.0 이상을 포함합니다.

    Groovy

    dependencies {
        def core_version = "1.13.1"
    
        // Java language implementation
        implementation "androidx.core:core:$core_version"
        // Kotlin
        implementation "androidx.core:core-ktx:$core_version"
    
        // To use RoleManagerCompat
        implementation "androidx.core:core-role:1.0.0"
    
        // To use the Animator APIs
        implementation "androidx.core:core-animation:1.0.0"
        // To test the Animator APIs
        androidTestImplementation "androidx.core:core-animation-testing:1.0.0"
    
        // Optional - To enable APIs that query the performance characteristics of GMS devices.
        implementation "androidx.core:core-performance:1.0.0"
    
        // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google
        implementation "androidx.core:core-google-shortcuts:1.1.0"
    
        // Optional - to support backwards compatibility of RemoteViews
        implementation "androidx.core:core-remoteviews:1.1.0"
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation "androidx.core:core-splashscreen:1.2.0-alpha02"
    }
    

    Kotlin

    dependencies {
        val core_version = "1.13.1"
    
        // Java language implementation
        implementation("androidx.core:core:$core_version")
        // Kotlin
        implementation("androidx.core:core-ktx:$core_version")
    
        // To use RoleManagerCompat
        implementation("androidx.core:core-role:1.0.0")
    
        // To use the Animator APIs
        implementation("androidx.core:core-animation:1.0.0")
        // To test the Animator APIs
        androidTestImplementation("androidx.core:core-animation-testing:1.0.0")
    
        // Optional - To enable APIs that query the performance characteristics of GMS devices.
        implementation("androidx.core:core-performance:1.0.0")
    
        // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google
        implementation("androidx.core:core-google-shortcuts:1.1.0")
    
        // Optional - to support backwards compatibility of RemoteViews
        implementation("androidx.core:core-remoteviews:1.1.0")
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation("androidx.core:core-splashscreen:1.2.0-alpha02")
    }
    
  2. BroadcastReceiver 인스턴스를 만듭니다.

    Kotlin

    val myBroadcastReceiver = MyBroadcastReceiver()
    

    자바

    MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
    
  3. IntentFilter 인스턴스를 만듭니다.

    Kotlin

    val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
    

    자바

    IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");
    
  4. broadcast receiver를 내보내고 기기의 다른 앱에 표시할지 여부를 선택합니다. 이 수신기가 시스템 또는 다른 앱(소유한 다른 앱 포함)에서 전송하는 브로드캐스트를 리슨하는 경우 RECEIVER_EXPORTED 플래그를 사용합니다. 대신 이 수신기가 앱에서 전송한 브로드캐스트만 수신 대기하는 경우 RECEIVER_NOT_EXPORTED 플래그를 사용합니다.

    Kotlin

    val listenToBroadcastsFromOtherApps = false
    val receiverFlags = if (listenToBroadcastsFromOtherApps) {
        ContextCompat.RECEIVER_EXPORTED
    } else {
        ContextCompat.RECEIVER_NOT_EXPORTED
    }
    

    자바

    boolean listenToBroadcastsFromOtherApps = false;
    int receiverFlags = listenToBroadcastsFromOtherApps
            ? ContextCompat.RECEIVER_EXPORTED
            : ContextCompat.RECEIVER_NOT_EXPORTED;
    
  5. registerReceiver()를 호출하여 수신자를 등록합니다.

    Kotlin

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)
    

    자바

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
    
  6. 브로드캐스트 수신을 중지하려면 unregisterReceiver(android.content.BroadcastReceiver)를 호출합니다. 수신자가 더 이상 필요하지 않거나 컨텍스트가 더 이상 유효하지 않으면 수신자의 등록을 취소해야 합니다.

broadcast receiver 등록 취소

broadcast receiver가 등록된 동안에는 등록된 컨텍스트에 대한 참조를 보유합니다. 수신자의 등록된 범위가 컨텍스트 수명 주기 범위를 초과하면 누수가 발생할 수 있습니다. 예를 들어 Activity 범위에 수신기를 등록했지만 시스템에서 Activity를 소멸할 때 수신기를 등록 취소하는 것을 잊어버린 경우 이러한 문제가 발생할 수 있습니다. 따라서 항상 broadcast receiver를 등록 취소하세요.

Kotlin

class MyActivity : ComponentActivity() {
    private val myBroadcastReceiver = MyBroadcastReceiver()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
        setContent { MyApp() }
    }

    override fun onDestroy() {
        super.onDestroy()
        // When you forget to unregister your receiver here, you're causing a leak!
        this.unregisterReceiver(myBroadcastReceiver)
    }
}

자바

class MyActivity extends ComponentActivity {
    MyBroadcastReceiver myBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
        // Set content
    }
}

최소 범위에서 수신자 등록

broadcast receiver는 결과에 실제로 관심이 있는 경우에만 등록해야 합니다. 가능한 한 가장 작은 수신기 범위를 선택합니다.

  • LifecycleResumeEffect 또는 활동 onResume/onPause 수명 주기 메서드: 브로드캐스트 수신기는 앱이 재개된 상태에 있는 동안만 업데이트를 수신합니다.
  • LifecycleStartEffect 또는 활동 onStart/onStop 수명 주기 메서드: 브로드캐스트 수신기는 앱이 재개된 상태에 있는 동안만 업데이트를 수신합니다.
  • DisposableEffect: broadcast receiver는 컴포저블이 컴포지션 트리에 있는 동안에만 업데이트를 수신합니다. 이 범위는 활동 수명 주기 범위에 연결되지 않습니다. 애플리케이션 컨텍스트에 수신기를 등록하는 것이 좋습니다. 이는 컴포저블이 이론적으로 활동 수명 주기 범위보다 오래 지속되어 활동을 유출할 수 있기 때문입니다.
  • 활동 onCreate/onDestroy: 활동이 생성된 상태일 때 브로드캐스트 수신기가 업데이트를 수신합니다. onSaveInstanceState(Bundle)이 아닌 onDestroy()에서 등록을 취소해야 합니다. onSaveInstanceState(Bundle)에서는 호출되지 않을 수 있기 때문입니다.
  • 맞춤 범위: 예를 들어 ViewModel 범위에 수신기를 등록하면 활동 재생성 후에도 수신기가 유지됩니다. 수신자가 활동 수명 주기 범위보다 오래 지속되어 활동을 유출할 수 있으므로 애플리케이션 컨텍스트를 사용하여 수신자를 등록해야 합니다.

스테이트풀(Stateful) 및 스테이트리스(Stateless) 컴포저블 만들기

Compose에는 스테이트풀(Stateful) 컴포저블과 스테이트리스(Stateless) 컴포저블이 있습니다. 컴포저블 내에서 broadcast receiver를 등록하거나 등록 취소하면 스테이트풀이 됩니다. 컴포저블은 동일한 매개변수가 전달될 때 동일한 콘텐츠를 렌더링하는 확정 함수가 아닙니다. 내부 상태는 등록된 broadcast receiver 호출에 따라 변경될 수 있습니다.

Compose에서는 컴포저블을 스테이트풀 버전과 스테이트리스 버전으로 분할하는 것이 좋습니다. 따라서 컴포저블에서 broadcast receiver 생성을 호이스팅하여 스테이트리스로 만드는 것이 좋습니다.

@Composable
fun MyStatefulScreen() {
    val myBroadcastReceiver = remember { MyBroadcastReceiver() }
    val context = LocalContext.current
    LifecycleStartEffect(true) {
        // ...
        ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
        onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
    }
    MyStatelessScreen()
}

@Composable
fun MyStatelessScreen() {
    // Implement your screen
}

manifest에 선언된 수신자

매니페스트에 broadcast receiver를 선언하면 브로드캐스트가 전송될 때 시스템에서 앱을 실행합니다. 앱이 아직 실행되고 있지 않으면 시스템에서 앱을 실행합니다.

manifest에서 broadcast receiver를 선언하려면 다음 단계를 따르세요.

  1. 앱의 매니페스트에서 <receiver> 요소를 지정합니다.

    <!-- If this receiver listens for broadcasts sent from the system or from
         other apps, even other apps that you own, set android:exported to "true". -->
    <receiver android:name=".MyBroadcastReceiver" android:exported="false">
        <intent-filter>
            <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
        </intent-filter>
    </receiver>
    

    인텐트 필터는 수신자가 구독할 브로드캐스트 작업을 지정합니다.

  2. BroadcastReceiver 서브클래스를 선언하고 onReceive(Context, Intent)를 구현합니다. 다음 예의 broadcast receiver는 브로드캐스트의 콘텐츠를 기록하고 표시합니다.

    Kotlin

    class MyBroadcastReceiver : BroadcastReceiver() {
    
        @Inject
        lateinit var dataRepository: DataRepository
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") {
                val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data"
                // Do something with the data, for example send it to a data repository:
                dataRepository.updateData(data)
            }
        }
    }
    

    자바

    public static class MyBroadcastReceiver extends BroadcastReceiver {
    
        @Inject
        DataRepository dataRepository;
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) {
                String data = intent.getStringExtra("com.example.snippets.DATA");
                // Do something with the data, for example send it to a data repository:
                if (data != null) { dataRepository.updateData(data); }
            }
        }
    }
    

앱이 설치될 때 시스템 패키지 관리자가 수신자를 등록합니다. 그러면 수신자가 앱으로 향하는 별도의 진입점이 됩니다. 이는 앱이 실행되고 있지 않으면 시스템이 앱을 시작하고 브로드캐스트를 전달할 수 있다는 의미입니다.

시스템은 수신하는 각 브로드캐스트를 처리하기 위해 새 BroadcastReceiver 구성요소 객체를 생성합니다. 이 객체는 onReceive(Context, Intent) 호출이 지속되는 동안만 유효합니다. 코드가 이 메서드에서 반환되면 시스템은 구성요소가 더 이상 활성 상태가 아닌 것으로 간주합니다.

프로세스 상태에 미치는 영향

BroadcastReceiver가 작동하는지 여부는 포함된 프로세스에 영향을 미치며, 이는 시스템 종료 가능성을 변경할 수 있습니다. 포그라운드 프로세스는 수신자의 onReceive() 메서드를 실행합니다. 메모리 부족이 심한 상황을 제외하고 시스템은 프로세스를 실행합니다.

시스템은 onReceive() 후에 BroadcastReceiver를 비활성화합니다. 수신자의 호스트 프로세스의 중요성은 앱 구성요소에 따라 다릅니다. 이 프로세스가 매니페스트 선언된 broadcast receiver만 호스팅하는 경우 시스템은 onReceive() 후에 이를 종료하여 더 중요한 다른 프로세스를 위한 리소스를 확보할 수 있습니다. 이는 사용자가 최근에 상호작용하지 않았거나 상호작용한 적이 없는 앱에서 흔히 발생합니다.

따라서 broadcast receiver는 장기 실행 백그라운드 스레드를 시작해서는 안 됩니다. 시스템은 onReceive() 이후 언제든지 프로세스를 중지하여 메모리를 회수하고 생성된 스레드를 종료할 수 있습니다. 프로세스를 활성 상태로 유지하려면 JobScheduler를 사용하여 수신기에서 JobService를 예약하여 시스템이 프로세스가 여전히 작동하고 있음을 알 수 있도록 합니다. 자세한 내용은 백그라운드 작업 개요를 참고하세요.

브로드캐스트 전송

Android는 앱에서 브로드캐스트를 전송하는 두 가지 방법을 제공합니다.

  • sendOrderedBroadcast(Intent, String) 메서드는 한 번에 하나의 수신자에 브로드캐스트를 전송합니다. 각 수신기는 차례로 실행되므로 결과를 다음 수신기로 전파할 수 있습니다. 또한 브로드캐스트가 다른 수신기에 도달하지 않도록 브로드캐스트를 완전히 중단할 수도 있습니다. 수신기가 실행되는 순서를 제어할 수 있습니다. 이렇게 하려면 일치하는 인텐트 필터의 android:priority 속성을 사용합니다. 우선순위가 동일한 수신자는 임의의 순서로 실행됩니다.
  • sendBroadcast(Intent) 메서드는 정의되지 않은 순서로 모든 수신기에 브로드캐스트를 전송합니다. 이를 일반 브로드캐스트라고 합니다. 일반 브로드캐스트는 상당히 효율적이지만 수신자가 다른 수신자의 결과를 읽거나 브로드캐스트로부터 수신한 데이터를 전파하거나 브로드캐스트를 중단할 수 없음을 의미합니다.

다음 코드 스니펫은 인텐트를 생성하고 sendBroadcast(Intent)를 호출함으로써 브로드캐스트를 전송하는 방법을 보여줍니다.

Kotlin

val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
    putExtra("com.example.snippets.DATA", newData)
    setPackage("com.example.snippets")
}
context.sendBroadcast(intent)

자바

Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);

브로드캐스트 메시지는 Intent 객체에서 래핑됩니다. 인텐트의 action 문자열은 앱의 Java 패키지 이름 문법을 제공하고 브로드캐스트 이벤트를 고유하게 식별해야 합니다. putExtra(String, Bundle)를 사용하여 인텐트에 추가 정보를 첨부할 수 있습니다. 또한 인텐트에서 setPackage(String)를 호출하여 동일한 조직의 앱 세트로 브로드캐스트를 제한할 수도 있습니다.

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

권한을 통해 특정 권한을 보유한 앱 세트로 브로드캐스트를 제한할 수 있습니다. 브로드캐스트의 발신자 또는 수신자에 제한사항을 적용할 수 있습니다.

권한으로 브로드캐스트 전송

sendBroadcast(Intent, String) 또는 sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)를 호출할 때 권한 매개변수를 지정할 수 있습니다. 매니페스트에 <uses-permission> 태그를 사용하여 권한을 요청한 수신자만 브로드캐스트를 수신할 수 있습니다. 권한이 위험한 경우 수신기가 브로드캐스트를 수신하기 전에 권한을 부여해야 합니다. 예를 들어 다음 코드는 권한이 있는 브로드캐스트를 전송합니다.

Kotlin

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)

자바

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);

브로드캐스트를 수신하려면 수신 앱에서 다음과 같이 권한을 요청해야 합니다.

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

BLUETOOTH_CONNECT와 같은 기존 시스템 권한을 지정하거나 <permission> 요소를 사용하여 맞춤 권한을 정의할 수 있습니다. 권한 및 보안에 관한 전반적인 내용은 시스템 권한을 참고하세요.

권한으로 브로드캐스트 수신

broadcast receiver를 등록할 때 권한 매개변수를 지정하면(registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) 또는 매니페스트의 <receiver> 태그 사용) 매니페스트의 <uses-permission> 태그로 권한을 요청한 브로드캐스트만 수신기에 인텐트를 전송할 수 있습니다. 권한이 위험한 경우 방송사에도 권한이 부여되어야 합니다.

예를 들어 수신 앱에 다음과 같이 매니페스트에 선언된 수신자가 있다고 가정합니다.

<!-- If this receiver listens for broadcasts sent from the system or from
     other apps, even other apps that you own, set android:exported to "true". -->
<receiver
    android:name=".MyBroadcastReceiverWithPermission"
    android:permission="android.permission.ACCESS_COARSE_LOCATION"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
    </intent-filter>
</receiver>

또는 다음과 같이 컨텍스트에 등록된 수신자가 수신 앱에 있습니다.

Kotlin

ContextCompat.registerReceiver(
    context, myBroadcastReceiver, filter,
    android.Manifest.permission.ACCESS_COARSE_LOCATION,
    null, // scheduler that defines thread, null means run on main thread
    receiverFlags
)

자바

ContextCompat.registerReceiver(
        context, myBroadcastReceiver, filter,
        android.Manifest.permission.ACCESS_COARSE_LOCATION,
        null, // scheduler that defines thread, null means run on main thread
        receiverFlags
);

그런 다음 발신 앱이 다음과 같이 권한을 요청해야 수신자에 브로드캐스트를 전송할 수 있습니다.

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

보안 고려사항

다음은 브로드캐스트 전송 및 수신에 관한 몇 가지 보안 고려사항입니다.

  • 여러 앱이 자체 매니페스트에서 동일한 브로드캐스트를 수신하도록 등록하면 시스템에서 많은 앱을 실행하게 되며 결국 기기 성능과 사용자 환경 모두에 상당한 영향을 줄 수 있습니다. 이를 방지하려면 매니페스트 선언보다 컨텍스트 등록을 사용하는 것이 좋습니다. Android 시스템 자체가 컨텍스트에 등록된 수신자의 사용을 적용하는 상황도 있습니다. 예를 들어 CONNECTIVITY_ACTION 브로드캐스트는 컨텍스트에 등록된 수신자에만 전달됩니다.

  • 암시적 인텐트를 사용하여 민감한 정보를 브로드캐스트하지 마세요. 브로드캐스트를 수신하도록 등록한 앱은 정보를 읽을 수 있습니다. 브로드캐스트를 수신할 수 있는 대상을 제어할 수 있는 방법은 다음과 같이 세 가지가 있습니다.

    • 브로드캐스트를 전송할 때 권한을 지정할 수 있습니다.
    • Android 4.0 (API 수준 14) 이상에서는 브로드캐스트를 전송할 때 setPackage(String)를 사용하여 패키지를 지정할 수 있습니다. 시스템은 패키지와 일치하는 앱 세트로 브로드캐스트를 제한합니다.
  • 수신자를 등록하면 임의의 앱이 잠재적 악성 브로드캐스트를 앱의 수신기에 전송할 수 있습니다. 앱이 수신하는 브로드캐스트를 제한하는 방법에는 여러 가지가 있습니다.

    • broadcast receiver를 등록할 때 권한을 지정할 수 있습니다.
    • 매니페스트에 선언된 수신자의 경우 매니페스트에서 android:exported 속성을 'false'로 설정할 수 있습니다. 그러면 수신자는 앱 외부 소스의 브로드캐스트를 수신하지 않습니다.
  • 브로드캐스트 작업의 네임스페이스는 전역입니다. 작업 이름 및 기타 문자열이 고유한 네임스페이스에 작성되었는지 확인합니다. 그러지 않으면 의도치 않게 다른 앱과 충돌할 수 있습니다.

  • 수신자의 onReceive(Context, Intent) 메서드는 기본 스레드에서 실행되므로 이 메서드의 실행 및 반환은 신속해야 합니다. 장기 실행 작업을 할 필요가 있다면 스레드 생성 또는 백그라운드 서비스 시작에 주의해야 합니다. onReceive() 반환 후 시스템이 프로세스 전체를 종료할 수 있기 때문입니다. 자세한 내용은 프로세스 상태에 미치는 영향을 참고하세요. 장기 실행 작업을 하려면 다음 방법을 사용하는 것이 좋습니다.

    • 수신자의 onReceive() 메서드에서 goAsync()를 호출하고 BroadcastReceiver.PendingResult를 백그라운드 스레드에 전달합니다. 이렇게 하면 onReceive()의 반환 후 브로드캐스트가 활성 상태로 유지됩니다. 그러나 이 방법을 사용하더라도 시스템은 브로드캐스트가 매우 빠르게 (10초 미만에) 완료될 것으로 예상합니다. 따라서 작업을 또 다른 스레드로 이동하여 기본 스레드에 문제가 발생하지 않도록 할 수 있습니다.
    • JobScheduler를 사용하여 작업을 예약합니다. 자세한 내용은 지능형 작업 예약을 참고하세요.
  • 특히 둘 이상의 수신자가 있다면 사용자 환경에 충돌이 발생하기 때문에 broadcast receiver에서 활동을 시작하지 않아야 합니다. 대신 알림을 표시하는 것이 좋습니다.