MessageStyle
이번 글에서는 Android Notification Style 중 MessageStyle의 이미지 표시하는 방법에 대해서 알아보려고 합니다. MessageStyle은 Android에서 제공하는 알림 스타일 중 채팅처럼 대화형 데이터를 표시하는 목적으로 사용하는 스타일입니다.
최근 회사에서 앱의 알림 스타일을 MessageStyle로 변경하는 작업을 진행했는데요.이미지를 표시하는 부분에서 어려움을 느껴서 이번 글에서 정리해보려고 합니다.
기본 사용법
val person = Person.Builder() --- (1)
.setName("자비스")
.setIcon(IconCompat.createWithBitmap(bitmap))
...
.build()
val style = NotificationCompat.MessagingStyle(person) --- (2)
.addMessage(
NotificationCompat.MessagingStyle.Message("안녕하세요", Date().time, person)
)
val builder = NotificationCompat.Builder(this, channelId) --- (3)
...
.setStyle(style)
.setCategory(Notification.CATEGORY_MESSAGE)
...
우선 MessageStyle의 사용법을 아주 간단히 알아보면
(1) - Person 객체 생성
Person 클래스는 생성자로 직접 객체를 생성할 수 없고 Builder 객체로 생성 가능합니다. 프로필 이미지, 사용자 이름 등 정보를 저장하는 Immutable 객체입니다.
(2) - MessageStyle 객체 생성
MessageStyle 객체는 메시지 응답을 보내는 유저의 이름으로 사용될 문자열, 또는 (1)에서 만든 Person 객체를 통해 생성 가능합니다. addMessage 함수로 알림에 표시할 메시지 정보를 저장합니다.
(3) - 적용
Notification Builder 객체에서 (2)에서 만든 Style을 적용합니다
MessageStyle 이미지 표시
(2) 코드 부분에서 메시지를 추가하는 addMessage 함수를 확인할 수 있었습니다.
addMessage 함수는 Message 객체 인자로 받고 있는데요. 이 Message 객체에 이미지를 추가하는 setData 함수가 있습니다.
친절한 주석으로 설명되어 있지만 정리해 보자면 이미지의 mimeType, 이미지의 uri 2개의 인자가 필요합니다.
이미지의 mimeType은 image/png
등이 해당되며 타입을 굳이 명시하지 않고 image/
로도 충분합니다.
중요한 부분은 2번째 인자인 이미지의 uri입니다. 단순 바이너리로는 넘길 수 없고, 저장소에 저장하고 해당 파일의 위치를 의미하는 Uri를 넘겨야 합니다. System UI에서 접근이 가능한 Uri를 넘겨야 하는 것이 매우 중요합니다.
이미지를 Uri 가져오기
private fun getFileUri(file: File): Uri {
return FileProvider.getUriForFile(this, "$packageName.fileprovider", file)
}
위 함수는 이미지가 저장되어 있는 파일의 uri를 FileProvider를 이용해 가져오는 코드입니다.
그런데 Fileprovider는 그냥 사용할 수 없고 몇 가지 설정이 필요합니다.
- AndroidManifest.xml
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
- values/xml/filepaths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path path="/" name="cache" />
</paths>
setData로 이미지 데이터 적용하기
val style = NotificationCompat.MessagingStyle(person)
.addMessage(
NotificationCompat.MessagingStyle.Message("image", Date().time, person)
.also {
if (uri != null) {
it.setData("image/", uri)
}
}
)
주의할 점은 Message의 생성자에서 text 인자를 null로 설정하면 안 됩니다.
grantUriPermission로 퍼미션 직접 부여하기
Fileprovider 자체로도 타 앱에 이미지 파일 접근 권한을 부여하지만, 일부 기기에서는 이미지가 표시 안 되는 케이스가 발생할 수 있습니다. 필자도 이 이슈로 오랜 시간 삽질했습니다.. ㅜㅜ
val uri = file?.let { getFileUri(it) }
uri?.grantReadPermissionToSystem()
private fun Uri.grantReadPermissionToSystem() {
applicationContext.grantUriPermission("com.android.systemui", this,
Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
grantUriPermission 함수는 다른 패키지에게 권한을 부여하는 함수입니다. 이를 알림을 관리하는 것으로 추측되는 com.android.systemui
패키지에 이미지 uri의 권한을 강제적으로 부여합니다.
이번 글에서 사용한 전체 코드는 아래 링크에서 확인 가능합니다.
'Android > Common' 카테고리의 다른 글
[Android] touchDelegate로 뷰 계층 제약 없이 터치 영역 확장하기 (1) | 2023.11.30 |
---|---|
[Android] InAppUpdate 기능 알아보기 (1) | 2023.11.09 |
[Android] 앱 성능 개선 - 앱 시작 시간 (1) | 2023.10.10 |
[Android] minSdk, compileSdk, targetSdk (0) | 2023.09.25 |
[Android] Radius 올바르게 적용하기 (0) | 2023.05.24 |