Android/Common

[Android] Notification MessageStyle에 이미지 표시하기

점냥 2025. 1. 1. 00:55
반응형

MessageStyle

MessageStyle Notification 예시 UI

 

이번 글에서는 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 함수가 있습니다.

 

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의 권한을 강제적으로 부여합니다.

 

 

결과


 

이번 글에서 사용한 전체 코드는 아래 링크에서 확인 가능합니다.

https://github.com/jaeryo2357/posting_android_sample_code/pull/8/files#diff-1495c31ebcf6ffefcc35daecd0eedc7a1e77971bede02808a97fad9b553e4697

 

MessageStyle 적용 by jaeryo2357 · Pull Request #8 · jaeryo2357/posting_android_sample_code

 

github.com

 

반응형