Broadcast Intent
와이파이를 접속하거나, 전화를 수신하거나, sw를 설치되기도 하는 이벤트들이 반으한다.
이러한 시스템이 전송하는 브로드캐스트 인텐트를 시스템 브로드캐스트 인텐트라고 한다.
또 다른 형태로 커스텀 브로드캐스트 인텐트가 있다. 이것 또한 시스템 브로드캐스트 인텐트와 유사하다.
인텐트와 유사하게 작동되며, 차이점은 브로드캐스트 수신자로 등록한 다수의 컴포넌트가 동시에 받을 수 있다는 점이다.
즉 다른 앱의 상황이나 정보 공유가 인텐트는 한개씩 가능한 반면 브로드캐스트 인텐트는 동시에 여러 앱이 가능하다는 것이다.
브로드캐스트 인텐트 사용법
1. 브로드캐스트 인텐트를 생성하고 전송한다.
context.sendBoradcast(Intent(MSG))
...
companion object { const val MSG = "패키지명.SHOW_알림" }
2. 인텐트를 생성했으면 이제 수신자를 생성하고 등록까지 해준다.
수신자의 종류는 두 가지이다.
- 독립 실행형 Standalone : Manifest에 선언되며, 앱이 종료되도 활성화 된다.
- 동적 실행형 Dynamic : 액티비티나 프래그먼트 같은 가시적인 앱 컴포넌트 생명주기와 연관되는 수신자이다.
수신자는 시스템에 등록해줘야 한다.
android.content.BroadcastReceiver 을 사용해준다.
class 수신자 이름 : BroadcastReceiver() {
override fun onReceive(context: Context, intent : Intent) {
Log.d("수신자", "수신됨 ${intent.action}" )
}
}
제대로 등록이 되어야 onReceive() 를 사용할 수 있다.
이제 매니페스트에 수신자 등록도 진행한다.
<application ...>
<activity android: name = ".앱메인화면이름">
...
</activity>
<receiver android:name = ".수신자 이름" >
</receiver>
</application>
이렇게 한뒤 한가지 더 추가해줘야 할 것이 있다.
intent filter도 추가해줘야 한다. 해당 브로드캐스트 인텐트에 MSG 라고 설정한 부분이다.
이렇게 해줘야 정확히 필터링이 된다.
<application ...>
<activity android: name = ".앱메인화면이름">
...
</activity>
<receiver android:name = ".수신자 이름" >
<intent-filter>
<action android:name = "패키지 명.SHOW_알림" />
</intent-filter>
</receiver>
</application>
3. 브로드캐스트 인텐트를 나의 앱에만 작동되게 제한한다.
기본적으로 여러 어떠한 컴포넌트도 리스닝을 할 수 있기 때문에, 원치 않는 작업이 수행될 수도 있다.
이러한 문제를 막기위해서는 권한을 설정해주면 된다.
- 커스텀 권한을 만들어준다.
<permission android:name = "패키지명.PRIVATE" android:protectionLevel = "signature" />
- 커스텀 한 권한을 사용한다고 추가해준다.
protectionLevel의 종류는 총 4 종류이다.<use-permission android: name = "패키지명.PRIVATE" />
1. normal : INTERNET같은 일반 수준의 권한 레벨이다. 안전한 범위내의 권한이다.
2. dangerous : 위험할 수 있는 범위의 권한이다. 이제는 사용자에게 직접 승인을 받아야 한다.
3. signature : 인증 키로 다른앱이 서명되어있다면 사용가능하게 해준다.
4. signatureOrSystem : 주로 하드웨어 제조사에서 사용하기 위한 보호 수준이다. - 수신자에 권한 설정을 적용해준다.
Exported = false 이므로 해당 permission을 가진 수신자만 신호와 요청을 받게 된다.<receiver android:name = ".수신자명" android:permission = "패키지명.PRIVATE" android:exported = "false"> .... </receiver>
다른 앱에서는 해당 수신자를 사용할 수 없게 만드는 것이다.(즉, 다른 앱에서 내 앱의 데이터를 가져가는게 의심되면,
exported = false를 해주고 따로 권한 설정으로 한정적이게 풀어주면 된다.) - 마지막으로 이 권한을 반영하여 인텐트를 전송해주는 부분을 수정한다.
context.sendBoradcast(Intent(MSG), PERM_PRIVATE) companion object { const val MSG = "패키지명.SHOW_알림" const val PERM_PRIVATE = "패키지명.PRIVATE" }
이렇게 함으로써 이제 이 앱에서만 해당 수신자를 시작시킬 수 있게 된다.
브로드캐스트 인텐트와 수신자를 알아봤다.
그리고 이러한 인텐트가 내 앱에서만 활성화되게 권한 설정을 하는 것도 알아봤다.
이제는 내 앱이 실행되는 동안 이러한 반응을 컨트롤 하기 위한 방법을 알아본다.
동적 브로드캐스트 수신자를 사용한다.
Dynamic
동적 수신자는 위의 말그대로 fragment나 Activity 의 생명주기에 맞춰 가동되도록 해준다.
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.widget.Toast
import androidx.fragment.app.Fragment
abstract class VisibleFragment :Fragment() {
// 리시버 생서하기
private val onShowNotification = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Toast.makeText(requireContext(), "브로드캐스트를 얻어냈다: ${intent.action}", Toast.LENGTH_LONG).show()
}
}
override fun onStart() {
super.onStart()
val filter = IntentFilter(PollWorker.ACTION_SHOW_NOTIFICATION)
// 리시버 등록하기
// fragment에서는 requireActivity().getApplicationContext() 를 기억해야 한다.
requireActivity().registerReceiver(
onShowNotification,
filter,
PollWorker.PERM_PRIVATE,
null
)
}
override fun onStop() {
super.onStop()
// 등록생성한 리시버 지우기
requireActivity().unregisterReceiver(onShowNotification)
}
}
매니페스트에서의 intent filter 부분을 위의 코드에서는 fragment상에서 표현을 한 것이다.
또한 위의 추상클래스를 생성함으로써 이 추상 클래스를 적용하고자 하는 fragment에 서브 클래스로 넣어주면 된다.
class PhotoGalleryFragment : 수신자등록된 추상클래스() {...}
registerRecevier
unregeisterReceiver
을 사용하여 수신자를 등록했다 해제해주는 코드가 반드시 들어가야 한다.
그리고 onStart, onStop 에 적용하여 사용하였지만, onCreate, onDestroy()에 적용해도 되지만, 화면 변화에 맞춰 사용하기 귀찮으니 웬만하면 onStart, onStop에서 사용한다.
순차 브로드캐스트 인텐트로 데이터 주고 받기
순차 브로드캐스트 인텐트?
위의 브로드 캐스트 인텐트 들은 모두 전송자가 보낸 인텐트를 순서 없이 수신자가 받아들였다.
위의 예시는 하나의 수신자만 있는 경우이지만, 수신자가 여러 곳이라면 순서가 없이, 누가 끝났는지, 진행중인지 모르는 상태에 인텐트를 보내고 있는 것이다.
이렇게 되면 컨트롤의 문제가 생기기 때문에,
순차로 순서를 정해주어 수신자가 인텐트를 수신받게 할 수 있다. 이것이 바로 순차 브로드캐스트 인텐트 이다.
이렇게 하면 뭐가 좋나?
위의 일방향 브로드캐스트 인텐트의 단점이 그대로 컨트롤이 된다는게 장점이다.
한마디로, 양방향으로 소통이 원할해진다는 것이다.
abstract class VisibleFragment :Fragment() {
// 리시버 생서하기
private val onShowNotification = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Toast.makeText(requireContext(), "브로드캐스트를 얻어냈다: ${intent.action}", Toast.LENGTH_LONG).show()
Log.i(TAG, "알림을 취소하였습니다.")
resultCode = Activity.RESULT_CANCELED
}
}
// 순차 브로드캐스트 인텐트를 생성해서 데이터를 넣어 보내기
showBackgroundNotification(0, notification)
...
// 순차 브로드캐스트 인텐트 전송하기
private fun showBackgroundNotification(requestCode: Int, notification: Notification) {
val intent = Intent(ACTION_SHOW_NOTIFICATION).apply {
putExtra(REQUEST_CODE, requestCode)
putExtra(NOTIFICATION, notification)
}
context.sendOrderedBroadcast(intent, PERM_PRIVATE) //sendBroadast()와 동일하게 작동하지만, 수신자의 순서에 맞춰 전달한다.
}
companion object {
// 상수로 공통 객체로 사용한다고 등록해준것이다.
const val ACTION_SHOW_NOTIFICATION = "com.greenhelix.photogallery.SHOW_NOTIFICATION"
const val PERM_PRIVATE = "com.greenhelix.photogallery.PRIVATE"
const val REQUEST_CODE = "REQUEST_CODE"
const val NOTIFICATION = "NOTIFICATION"
}
'Programming > Android' 카테고리의 다른 글
SHA-1, SHA-256 ? (0) | 2021.09.13 |
---|---|
Message (0) | 2021.08.24 |
Retrofit (0) | 2021.08.18 |