[Android] Jetpack Compose로 Android Widget은 어떻게 개발할까?

최근에 서버 개발자분이 안드로이드 위젯에 관한 질문을 주셔서 알아보다가

JetPack Compose에서는 어떻게 위젯을 만드는지에 대한 궁금증이 생겼습니다. 

어떤 라이브러리를 사용하고 어떻게 개발하는지 알아보려고 합니다!


 

 

1. Glance 라이브러리 추가

 implementation "androidx.glance:glance-appwidget:1.0.0-alpha05"

우선, 앱 위젯을 사용하기 위한 라이브러리를 추가해 줍니다. (아직 Jetpack용 Glance는 알파 버전만 출시된 상황입니다.)

Glance는 선언형 Kotlin API를 제공하므로, 훨씬 적은 코드로 보기에도 좋고 반응이 빠른 앱 위젯을 빌드할 수 있다고 합니다. 

해당 라이브러리를 사용해보니 compileSdk가 33인 곳에서 실행이 됩니다!

 

 

위 사진을 통해 Glance의 작동방식을 간단하게 살펴보도록 하겠습니다. 

Glance는 Jetpack Compose 런타임을 사용하여 Composable을 실제 RemoteView로 변환하여 앱 위젯을 표시할 수 있습니다.

GlanceAppWidget과 GlanceAppWidgetReceiver 사용하여 앱 위젯을 선언할 수 있습니다. 

 

 

2. Glacne로 AppWidget 구축해 보기

class GreetingsWidget(private val name: String): GlanceAppWidget() {
    @Composable
    override fun Content() {
        Text(text = "Hello $name")
    }
}
class GreetingsWidgetReceiver : GlanceAppWidgetReceiver() {
    override val glanceAppWidget = GreetingsWidget("Glance")
}

우선 AppWidget을 선언해야 합니다. GlanceAppWidget과 GlanceAppWidgetReceiver를 사용하여 선언하고 Receiver는 AndroidManifest에서 수신기로 연결되어야 합니다. 본질적으로 GlanceAppWidgetReceiver에서 개발자 대신 대부분의 작업을 처리하고 개발자는 AppWidget이 무엇인지 정보만 제공하면 되는 형태입니다. 

 

Content()에서 UI를 정의하고 Glance가 필요할 때마다 메서드를 호출해 알아서 위젯 UI를 표시합니다. 

(즉 , Content에 정의한 콘텐츠가 원격 뷰로 변환되어 표시됩니다.)

 

 

또한, Glance는 클릭 가능한 수정자를 통해 사용자 상호작용을 처리하기 쉽다고 합니다. 

Button(
	text = "Home",
    modifier = Modifier.clickable(launchActivity<NavigationActivity>(..))
)

위 코드처럼 Modifier.clickable을 통해 사용자가 컴포저블을 클릭할 때마다 해당 작업을 콜백 할 수 있습니다.

예를 들어 액티비티를 시작하를 시작하는 방법을 처리하는 작업이 있을 때, launchActivity를 호출하여 액티비티 대상 클래스를 전달하면 됩니다. 그럼 사용자가 컴포저블을 클릭할 때마다 Glance는 해당 액티비티를 호출하여 실행합니다.

 

 

3. Glance의 SizeMode

Glance는 여러 가지 SizeMode를 지원합니다. Single | Exact | Reponsive 세 가지를 지원하고 SizeMode.Single이 Default입니다.

override val sizeMode: SizeMode = SizeMode.Single //default size

SizeMode.Single

먼저, SizeMode.Single은 Content() 메서드를 한 번만 호출하되 위젯 메타 데이터에서 정의한 지원되는 최소 크기를 적용합니다. 위젯의 이용 가능한 크기가 변해서 사용자가 위젯 크기를 조정해도 콘텐츠는 새로 고쳐지지 않습니다.

 

SizeMode.Exact 

SizeMode.Exact는 크기가 바뀔 때마다 콘텐츠를 변경하고자 하는 경우 사용합니다. 해당 모드는 사용자가 위젯의 크기를 조정할 때마다 위젯 UI를 다시 만들어 콘텐츠 함수를 다시 호출하고 그 시점에 이용 가능한 최대 크기를 지원합니다.

if(size.width > 110.dp) {
	Button(text = "...")
}

즉, 위 코드처럼 크기에 따라 버튼을 추가하는 등 UI를 변경할 수 있습니다.

 

SizeMode.Responsive 

 

SizeMode.Responsive는 해당 앱이 지원하는 사이즈를 직접 정의할 수 있습니다. 위젯 모양에 맞추어 크기를 매핑할 수 있고 SizeMode.Exact처럼 사이즈에 따라 UI를 변경할 수 있습니다. 

    companion object {
        private val SMALL_SQUARE = DpSize(100.dp, 100.dp)
        private val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp)
        private val BIG_SQUARE = DpSize(250.dp, 250.dp)
    }

SizeMode.Responsive는 개발자가 지정한 사이즈로만 표시가 가능하고 각각의 호출에 맞는 크기를 매핑하여 메모리에 저장하기 때문에 크기가 변경될 때 UI를 전부 다시 만들지 않아도 됩니다.   Exact는 사이즈가 변경될 때마다 Content() 함수를 매번 호출하지만, Responsive는 한 번만 호출합니다. 

 



 

마무리

이번에는 Compose로 Widget 만드는 방법에 대해 간단하게 알아보았습니다! 아직 알파 버전이지만 간단하게 프로젝트를 만들어 직접 구현해 보면 재밌을 것 같다는 생각이 듭니다😮

 

https://developers-kr.googleblog.com/2022/02/announcing-jetpack-glance-alpha-for-app.html