안드로이드 Broadcast Receiver

이영준·2023년 3월 16일
0

📌브로드캐스트 리시버

시스템이나 다른 앱에서 보내는 브로드 캐스트 메시지를 받아서 처리하는 것

  • 디자인 패턴 중 publish - subscribe 형태처럼 한쪽에서는 이벤트를 제공하기만 하고 한쪽에서는 이벤트를 받기만 함
  • 앱은 시스템이 부팅되거나, 기기가 충전을 시작했을 때 등 관련 Broadcast를 수신할 수 있음
  • 앱들끼리도 미리 사전에 정의한 Action을 주고 받을 수 있음

브로드캐스트 리시버는 등록 방식에 따라 정적, 동적으로 나뉜다. 동적으로 리시버를 등록하는 것은 4대 컴포넌트 중 브로드캐스트 리시버가 유일하다. (상황에 따라 리시브 할 때가 있고 안할 때가 있기 때문)

🔑 정적 리시버

정적 리시버로 등록하면 앱이 꺼져있는 중에도 브로드캐스트 리시버로 설정한 intent를 받는다

<receiver android:name=".LocaleChangeReceiver" android:exported="false">
            <intent-filter>
                <!-- 로케일 변경에 대한 시스템 broadcast 수신 -->
                <action android:name="android.intent.action.LOCALE_CHANGED" />
            </intent-filter>
        </receiver>

LocaleChangeReceiver라는 파일에서 언어 설정이 바뀔 때마다 브로드캐스트 리시버로부터 인텐트를 수신하도록 정적으로 manifest에 설정해 놓았다.

private const val TAG = "LocaleChangeRece_싸피"
class LocaleChangeReceiver : BroadcastReceiver() {
   override fun onReceive(context: Context, intent: Intent) {
       Log.d(TAG, "onReceive: receive 받기: ${intent.action}")

   }
}

브로드캐스트 리시버는 onReceive만을 override 한다. 인텐트를 받을 때마다(언어 설정이 바뀔 때마다) 로그가 출력된다.

https://developer.android.com/guide/components/broadcast-exceptions?hl=ko
현재는 정적으로 등록할 수 있는 개수가 위 링크 의 브로드캐스트로 한정되어 있다.

🔑 동적 리시버

Intentfilter에 원하는 브로드캐스트 인텐트를 담고
리시버를 object: 를 통해 anonymous class 로 만들었다. 그리고 만든 리시버에

registerReceiver(receiver, intentFilter2);코드로 시스템에 리시버를 등록했다.

class BroadcastActivity : AppCompatActivity() {

    lateinit var receiver:BroadcastReceiver
    lateinit var brBattery: BatteryReceiver

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_broadcast)
        setTitle("BroadcastActivity")

        /***** Screen On/Off *******/
        val intentFilter2 = IntentFilter(Intent.ACTION_SCREEN_OFF)
        intentFilter2.addAction(Intent.ACTION_SCREEN_ON)
        receiver = object: BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                val action = intent.action
                Log.d(TAG, "receive : $action")

                when (action) {
                    Intent.ACTION_SCREEN_ON -> {
                        // do something
                        Log.d(TAG,"ACTION_SCREEN_ON");
                    }
                    Intent.ACTION_SCREEN_OFF -> {
                        // do something
                        Log.d(TAG,"ACTION_SCREEN_OFF");
                    }
                }
            }
        }
        registerReceiver(receiver, intentFilter2);
        /***** Screen On/Off *******/


        /***** Power On/Off isInteractive로 화면 상태 알 수 있음. *******/
        val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
        if (pm.isInteractive) {
            // screen on
            Log.d(TAG,"POWER_SERVICE - Power ON");
        } else {
            // screen off
            Log.d(TAG,"POWER_SERVICE - Power OFF");
        }
        /***** Power On/Off *******/


        /***** low receiver. emulator에서 battery수치 15이하로 조정. *******/
        brBattery = BatteryReceiver()
        val filterBattery = IntentFilter(Intent.ACTION_BATTERY_LOW)
        registerReceiver(brBattery, filterBattery)


    }


    override fun onDestroy() {
        super.onDestroy()

        unregisterReceiver(receiver)
        unregisterReceiver(brBattery)
    }
}

🔑사용자 정의 Broadcast

<receiver android:name=".SSAFYNewsReceiver" android:enabled="true"  android:exported="false" >
            <intent-filter>
                <!-- 사용자 정의 broadcast 수신 -->
                <action android:name="example.MY" />
            </intent-filter>
        </receiver>

intent filter에 수신할 action을 작성하고

private const val TAG = "MainActivity_싸피"
class MainActivity : AppCompatActivity() {
    private lateinit var broadcastBtn: Button
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        broadcastBtn = findViewById(R.id.broadcast_btn)
        broadcastBtn.setOnClickListener {
            val intent = Intent(this, SSAFYNewsReceiver::class.java)
            intent.action = "example.MY"
            intent.putExtra("content", "오늘도 티끌을 모아봅니다.")

            sendBroadcast(intent)
            Log.d(TAG, "onCreate: 발송 완료")
        }
    }
}

action을 정하고 명시적으로 수신할 리시버를 지정해준다. 위에 액티비티에서 버튼을 누르면 브로드캐스트를 하도록 해주었다.

private const val TAG = "SSAFYNewsReceiver_싸피"
class SSAFYNewsReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "onReceive: receive 받기: ${intent.action}")
        Log.d(TAG, "onReceive: extra: ${intent.getStringExtra("content")}")
    }
}

리시버에서 받을 시 할 실행문을 적어주어 로그로 action과 데이터를 받도록 하였다.

🔑사용자 정의 Broadcast with Permission

특정 권한을 가진 앱만 브로드캐스트 받기

    <!-- 사용자 정의 permission 선언 -->
    <permission
        android:name="com.ssafy.android.news.funny.PRIVATE"
        android:protectionLevel="signature" /> <!-- permission 사용 선언 -->
    <uses-permission android:name="com.ssafy.android.news.funny.PRIVATE" />

사용자 정의 permission 생성 및 사용 선언

 <receiver
            android:name=".SSAFYNewsReceiver2"
            android:enabled="true"
            android:exported="false"
            android:permission="com.ssafy.android.news.funny.PRIVATE">
            <intent-filter>
                <!-- 사용자 정의 broadcast 수신 -->
                <action android:name="com.ssafy.android.news.funny" />
            </intent-filter>
</receiver>

수신받을 리시버와 액션 선언

private const val TAG = "SSAFYNewsReceiver2_싸피"
class SSAFYNewsReceiver2 : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "onReceive: receive 받기: ${intent.action}")
        Log.d(TAG, "onReceive: extra: ${intent.getStringExtra("content")}")
    }
}

리시버에서 브로드캐스트 수신시 실행할 문 작성

profile
컴퓨터와 교육 그사이 어딘가

0개의 댓글