본문 바로가기
안드로이드 공부 노트

[Android] 안드로이드 위젯 알아보기 2편 - Glance, Compose, Kotlin (Android Compose Glance Appwidget)

by 지게요 2024. 5. 2.
728x90
반응형

지난 1편에서 위젯에 대한 개념을 알아봤다면 이제 2편에서는 위젯을 만드는 법에 대해서 알아볼 것이다.

 

들어가기 전 본 포스팅은 Xml 개발이 아닌 Compose로 개발을 진행할 것임으로 Xml으로 개발을 원한다면 공식문서를 보길 바란다.

 

우선 위젯을 Kotlin과 Compose를 사용하여 빌드하려면 Jetpack Glance라는 것을 이용해야 한다.

차근차근 알아보자!

# Glance란?

공식문서에서는 아래와 같이 말하고 있다.

Jetpack Glance는 Jetpack Compose 런타임을 기반으로 빌드된 프레임워크로, Kotlin API를 사용하여 앱 위젯을 개발하고 설계할 수 있습니다.
Glance는 적은 코드로 홈 화면의 반응형 위젯을 빠르게 빌드하는 데 도움이 되는 컴포저블 세트를 제공합니다.

 

정리하자면 Glance는 적은 코드로 반응형 위젯을 빠르게 빌드하는 데 도움이 되는 컴포저블 세트라고 생각할 수 있다.

## 유의 사항 (2024. 04. 29 기준)

 

Glance는 안정화 버전이긴 하지만 개인적으로는 아직 부족한 기능이나 속성들이 많은 거 같다고 느꼈다(컴포저블 함수를 커스텀 못하는 문제..)

그래서 이 점을 참고하길 바란다.

물론 간단한 위젯을 만들기에는 현재 나온 버전으로도 충분히 가능!


이 부분을 못 읽어서 가장 많이 삽질을 했다.

저 말을 정리하하면 Glance로 개발 시 android.glance 패키지에 들어있는 컴포저블 함수만 사용해야 한다는 것이다!

 

Box 컴포저블로 예를 들면 기존 사용하는 패키지를 아래 사진과 같이 android.glance 패키지로 사용해야 한다.

                                                                                                      <기존>

 

                                                                                                      <변경>

 

이 과정에서 android.glance 패키지에 없는 컴포저블 함수도 많고 원래 알고 있던 컴포저블의 속성들도 약간씩 다르기 때문에 잘 살펴보면서 하길 추천한다!

⭐️ 대표적으로는 그냥 Modifier가 아닌 GlanceModifier를 사용해야 한다.


# Glance를 사용하여 간단 위젯 구현하기

## 의존성 추가 

- 앱 수준의 build.gradle 추가 (최신 버전은 여기 확인)

dependencies {
   // For AppWidgets support
   implementation( "androidx.glance:glance-appwidget:1.0.0" )

   // For interop APIs with Material 2
   implementation( "androidx.glance:glance-material:1.0.0" )

   // For interop APIs with Material 3
   implementation( "androidx.glance:glance-material3:1.0.0" )
}

 

- Compose 컴파일러를 Glance에 사용할 수 있도록 활성화

android {
   buildFeatures {
      compose true
   }

   composeOptions {
      kotlinCompilerExtensionVersion = "1.5.11"
   }

   kotlinOptions {
      jvmTarget = "1.8"
   }
}

1.  AppWidgetProviderInfo XML 선언

Compose만 사용할 줄 알았는데 갑자기 XML?이라는 생각이 들것이다.

 

위젯을 구성하려면 AppWidgetProviderInfo XML은 필수적으로 만들어야 한다.

 

바로 만들기 전에 AppWidgetProviderInfo XML에 대해 알아보자!

1-1 AppWidgetProviderInfo XML 란?

- 위젯 생성을 위해서는 필수적으로 만들어야 한다.

- 위젯의 필수 특성(크기,  미리 보기 이미지, 설명,  업데이트 간격)등 정의를 한 xml이다.

- 단일 <appwidget-provider> 요소를 사용하여 XML 리소스 파일에 AppWidgetProviderInfo 객체를 정의하고 프로젝트의 res/xml/ 폴더에 저장한다.

 

예를 들면 아래 코드와 같이 작성한다.

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:targetCellWidth="1"
    android:targetCellHeight="1"
    android:maxResizeWidth="250dp"
    android:maxResizeHeight="120dp"
    android:minResizeWidth="40dp"
    android:minResizeHeight="40dp"
    android:updatePeriodMillis="86400000"
    android:description="@string/example_appwidget_description"
    android:previewImage="@drawable/example_appwidget_preview"
    android:previewLayout="@drawable/example_appwidget_preview"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen">
</appwidget-provider>



아니면 Glance에서 제공하는 기본 정의 로드 레이아웃을 아래와 같이 사용해도 된다!

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/glance_default_loading_layout">
</appwidget-provider>

 

각 속성에 대해 알고 싶으면 더 보기를 클릭하면 된다.

더보기

이제 각 주요 속성들을 알아보자

🔵 targetCellWidth 및 targetCellHeight (Android 12), minWidth 및 minHeight

android:minWidth="40dp"
android:minHeight="40dp"
android:targetCellWidth="1"
android:targetCellHeight="1"

 

targetCellWidth, targetCellHeight은 Android 12부터 사용 가능하고, 그리드 셀 측면에서 위젯의 기본크기를 지정할 수 있다.

Android 11 이하에서는 무시된다. 또한 홈화면이 그리드 기반 레이아웃을 지원하지 않으면 무시된다.

ex) targetCellWidth: 3, targetCellHeight: 3 이면 3*3 크기의 위젯 설정

 

minWidth, minHeight은 위젯의 기본 크기를 dp 단위로 지정한다.

 

따라서 Android 11 이하에서도 위젯의 크기 설정하는 것이 호환하도록 안드로이드 공식문서에서는 둘 다 지정하는 것을 권장한다.

또한 Android 12 이상 둘 다 지정했을 경우에는 targetCell의 우선순위가 더 높다!

🔵 minResizeWidth 및 minResizeHeight

android:minResizeWidth="40dp"
android:minResizeHeight="40dp"

 

 위젯의 절대 최소 크기를 지정한다.

 만약 minResizeWidth가 minWidth보다 크면 무시된다.

 마찬가지로 minResizeHeight도 동일하다.

🔵 maxResizeWidth 및 maxResizeHeight

android:maxResizeWidth="250dp"
android:maxResizeHeight="120dp"

 

위젯의 권장 최대 크기를 지정한다.

만약 maxResizeWidth가 maxWidth보다 작으면 무시된다.

마찬가지로 maxResizeHeight도 동일하다.

🔵 resizeMode

 android:resizeMode="horizontal|vertical"

 

위젯 크기를 조절할 수 있는 규칙 지정

속성 값에는 horizontal, vertical , none 이 세 가지를 사용할 수 있다.

horizontal → 가로만 조절 가능

vertical → 세로만 조절 가능

none → 조절 불가

horizontal | vertical → 가로 세로 조절 가능

🔵 updatePeriodMillis - Xml 개발 전용 Glance는 작동 안 함

 android:updatePeriodMillis="86400000"

 

위젯 프레임워크가 onUpdate 콜백 메서드를 호출하여 AppWidgetProvider에 업데이트를 요청하는 빈도를 정의한다.

30분 미만의 값을 지원하지 않는다.

Glance에서는 작동을 안 하기 때문에 WorkManager 사용을 권장한다.

🔵 description - Android 12 이상 사용 가능

android:description="@string/example_appwidget_description"

 

아래 사진처럼 위젯에 표시할 위젯 선택 도구의 설정을 지정 Android 12에서 도입

🔵 previewLayout (Android 12) 및 previewImage (Android 11 이하)

android:previewImage="@drawable/example_appwidget_preview"
android:previewLayout="@drawable/example_appwidget_preview"

 

둘 다 앱 위젯 선택 도구의 미리 보기를 설정해 주는 속성이다.

previewLayout는 Android 12부터 사용 가능하고, previewImage는 Android 11 이하에서 사용 가능하다.

이 속성도 모든 버전의 호환성을 위해 두 개다 지정해 주는 걸 권장한다!

                                    <Android 11 이하>                                                          <Android 12 이상>

 

🔵  widgetCategory

 android:widgetCategory="home_screen"

 

 위젯을 홈 화면, 잠금 화면 또는 둘 다에 표시할 수 있는지 여부를 선언한다.

 홈 화면 → home_screen

 잠금 화면 → keyguard

 하지만 어떤 이유인지는 모르겠지만 Android 5.0 이상에서는 홈 화면(home_screen)만 유효하다!

 

 이외에도 더 알고 싶으면 공식문서를 참고 바란다.

 

2. GlanceAppWidgetReceiver를 구현하는 클래스 생성

class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {
    override val glanceAppWidget: GlanceAppWidget = TODO("Create GlanceAppWidget")
}

GlanceAppWidgetReceiver의 함수인 glanceAppWidget를 오버라이드를 받고 리턴은 우선 비워놓는다.

 

3. 매니페스트에서 AppWidget 선언

<receiver android:name=".MyAppWidgetReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/my_app_widget_info" />
</receiver>

 

여기서 방금 전 2단계에서 생성했던 xml과 class를 등록해 준다.

4. GlanceAppWidget를 구현하는 클래스 생성

class MyAppWidget : GlanceAppWidget() {

    // provideGlance override를 해준다.
    override suspend fun provideGlance (context: Context, id: GlanceId) {

        // provideGlance는 기본 스레드에서 실행된다.
        // 비용이 많이 드는 작업 실행 시 withContext 사용

        provideContent {
            // 앱 위젯 UI를 작성한다.
            Text("Hello World")
        }
    }
}

 

추상 클래스의 GlanceAppWidget안에 보면 추상 함수인  provideGlance이 있다.

그래서 오버라이드를 필수적으로 해줘야 하며 provideContent 스코프 내에 앱 위젯 UI를 작성해 주면 된다.

 

5. GlanceAppWidgetReceiver의 glanceAppWidget에서 인스턴스 화

class MyAppWidgetReceiver : GlanceAppWidgetReceiver() {

    // MyAppWidgetReceiver에게 사용할 GlanceAppWidget을 알려준다.
    override val glanceAppWidget: GlanceAppWidget = MyAppWidget()
}

 

2번째 GlanceAppWidgetReceiver 구현하는 클래스로 가서 4번째에서 만들어준 GlanceAppWidget 구현한 클래스를 넣어준다.

 

6. 버튼이 2개 있는 예제 UI 코드 입력

import androidx.glance.Button
import androidx.glance.layout.Column
import androidx.glance.layout.Row
import androidx.glance.text.Text

class MyAppWidget : GlanceAppWidget() {

    override suspend fun provideGlance(context: Context, id: GlanceId) {
    
        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        Column(
            modifier = GlanceModifier.fillMaxSize()
                .background(GlanceTheme.colors.background),
            verticalAlignment = Alignment.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                text = "어디로 이동할까요?",
                modifier = GlanceModifier.padding(12.dp)

            )
            Button(
                text = "Home",
                onClick = actionStartActivity<MainActivity>()
            )
        }
    }
}

 

❗️ 여기서 중요한 점이 1편에서도 설명을 했는데 꼭 androidx.glance 패키지에 있는 컴포저블 함수를 사용해야 한다!

절대로 androidx.compose.foundation 패키지와 머터리얼 패키지를 혼용해서 사용하면 안 된다!!

완성 화면

이렇게 버튼을 누르면 메인액티비로 이동하는 간단한 위젯을 만들어봤다.

 

다음 3편에서는 조금 더 다양한 상호작용 방법에 대해 알아보자!

 

https://jige.tistory.com/87

 

[Android] 안드로이드 위젯 알아보기 3편 - Glance, Compose, Kotlin (Android Compose Glance Appwidget) 상호작용

지난 2편에서는 간단한 앱 위젯을 만들어봤다면 이번 3편에서는 액티비티 실행, 서비스 실행 등 앱 위젯 상호작용에 대해서 알아보자!# 상호작용 종류- 활동 실행 (Activity)- 서비스 실행- 브로드

jige.tistory.com

 

반응형