Skip to content

桌面微件 (Glance)

源:Jetpack Glance

以前开发 App Widget (桌面小组件) 非常痛苦,需要使用 RemoteViews 和 XML。Glance 是一套基于 Compose Runtime 的框架,让你用 Compose 的语法编写 Widget。

1. 依赖配置

kotlin
dependencies {
    implementation("androidx.glance:glance-appwidget:1.1.0")
    implementation("androidx.glance:glance-material3:1.1.0") // M3 风格
}

2. 定义 Widget

继承 GlanceAppWidget 并重写 provideGlance

kotlin
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.provideContent
import androidx.glance.text.Text

class MyWidget : GlanceAppWidget() {
    override suspend fun provideGlance(context: Context, id: GlanceId) {
        provideContent {
            // 这里使用的是 Glance 的 Composable,不是 Compose UI 的!
            // 比如 androidx.glance.text.Text,而不是 androidx.compose.material3.Text
            GlanceTheme {
                MyWidgetContent()
            }
        }
    }
}

@Composable
fun MyWidgetContent() {
    Column(
        modifier = GlanceModifier
            .fillMaxSize()
            .background(GlanceTheme.colors.background)
            .padding(16.dp)
    ) {
        Text(
            text = "Hello Glance",
            style = TextStyle(color = GlanceTheme.colors.onBackground)
        )
        Button(
            text = "Click Me",
            onClick = actionRunCallback<MyActionCallback>()
        )
    }
}

3. 注册 Receiver

Glance 需要一个 GlanceAppWidgetReceiver 来处理广播。

kotlin
class MyWidgetReceiver : GlanceAppWidgetReceiver() {
    override val glanceAppWidget: GlanceAppWidget = MyWidget()
}

AndroidManifest.xml 中注册:

xml
<receiver
    android:name=".MyWidgetReceiver"
    android:label="My Widget">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/my_widget_info" />
</receiver>

4. 状态管理

Glance 支持自带的状态存储(Preferences)。

kotlin
// 读取状态
val prefs = currentState<Preferences>()
val count = prefs[intPreferencesKey("count")] ?: 0

// 更新状态 (在 ActionCallback 中)
updateAppWidgetState(context, glanceId) { prefs ->
    val currentCount = prefs[intPreferencesKey("count")] ?: 0
    prefs[intPreferencesKey("count")] = currentCount + 1
}