How to Create an Android Widget | Build It With Glance

An Android app widget needs metadata XML, a Glance UI class, and a registered receiver before it can appear in the home-screen widget picker.

A small home-screen card can surface app data without making the user open the full app, and how to create an Android widget now starts cleanly with Jetpack Glance. For a new Kotlin project, Glance is the modern Android option because it lets you define widget content with Compose-style APIs while Android still renders the result through the app-widget system.

The build has four moving parts: add the Glance dependency, describe the widget in XML, create the Kotlin UI, and register its receiver in AndroidManifest.xml. The example below creates a simple 2-by-1 greeting widget and then shows how to get it into the launcher picker.

What Does An Android Widget Need?

An Android app widget built with Jetpack Glance needs a host app, an AppWidgetProviderInfo XML file, a GlanceAppWidget class, and a GlanceAppWidgetReceiver. Android reads the XML and manifest registration before the launcher can offer the widget to the user.

Glance uses Compose-style Kotlin, but Glance components are not the same as ordinary Jetpack Compose UI components. A normal androidx.compose.material3.Text cannot simply be dropped into widget code; use the matching Glance component instead. If an existing app is a legacy Views or Java project with no Compose setup, Android still supports the classic AppWidgetProvider and RemoteViews approach.

Creating An Android App Widget With Glance

Jetpack Glance turns a Kotlin widget definition into the RemoteViews data Android launchers understand. Android Developers currently lists Glance 1.1.1 as the stable release, so this walkthrough uses that version rather than a release candidate or alpha build.

dependencies {
    implementation("androidx.glance:glance-appwidget:1.1.1")
}

android {
    buildFeatures {
        compose = true
    }
}

Create res/xml/greeting_widget_info.xml and define the widget’s starting size, resize behavior, category, and loading layout. Supplying both cell-based sizing and dp-based sizing gives Android 12 and newer launchers a cell target while older launchers still have minimum dimensions to use.

Setting updatePeriodMillis to 0 disables scheduled system refreshes, which is fine for this first static widget. When the widget later shows changing app data, request a Glance update after the data changes or schedule longer background work with WorkManager.

Project Piece What It Controls What To Check
build.gradle.kts Glance library access glance-appwidget is included
Compose build feature Glance compiler support compose = true
greeting_widget_info.xml Size and picker metadata Resource is under res/xml
initialLayout Pre-composition loading view Points to Glance’s loading layout
targetCellWidth / targetCellHeight Default cells on Android 12+ Both values match the intended footprint
minWidth / minHeight Fallback size on older launchers Both are present
GlanceAppWidget Widget content provideGlance() calls provideContent
GlanceAppWidgetReceiver Widget broadcasts Receiver points to the widget class

Build The Widget UI In Kotlin

The widget UI lives in a GlanceAppWidget subclass, and its receiver tells Android which Glance widget to compose. Keep the first version small so registration problems are easy to separate from data-loading or interaction bugs.

class GreetingWidget : GlanceAppWidget() {
    override suspend fun provideGlance(
        context: Context,
        id: GlanceId
    ) {
        provideContent {
            Text("Hello from Glance")
        }
    }
}

class GreetingWidgetReceiver : GlanceAppWidgetReceiver() {
    override val glanceAppWidget: GlanceAppWidget = GreetingWidget()
}

Register that receiver inside the element of AndroidManifest.xml. The receiver must accept android.appwidget.action.APPWIDGET_UPDATE, and its metadata resource must point to the XML file created above.

Android Developers documents the same receiver, metadata, sizing, and GlanceAppWidget structure in its Glance app-widget instructions. One detail matters when you expand this sample: Android’s Glance docs give receiver callbacks a 10-second background limit, so longer database or network work belongs in WorkManager before the widget is updated.

How Do You Test The Widget On A Phone?

A finished Android widget should appear in the launcher’s widget picker under the installed app’s name. Install the current debug build first, then add the widget from the home screen rather than trying to launch the receiver directly.

  1. Run the app on an emulator or Android phone so the package is installed.
  2. Return to the home screen and touch and hold an empty area.
  3. Tap Widgets, then find your app in the widget list.
  4. Open the app’s widget group, touch and hold the greeting widget, and drag it to an empty area.
  5. Release it on the home screen. The text Hello from Glance should appear inside the widget.

If the app appears in the launcher but no widget is listed, inspect the manifest receiver name and the android:resource path first. Those two references decide whether Android can discover the provider metadata.

Fix The Failures That Stop A Widget Appearing

A widget that does not appear in the picker usually has a registration, metadata, build, or rendering problem. Check discovery failures before changing the Kotlin UI, because a launcher cannot render a widget it never registered.

Symptom Likely Cause First Fix
No widget under the app name Receiver missing or class name wrong Match android:name to the receiver class
Provider fails to load Metadata resource path is wrong Point android:resource to @xml/greeting_widget_info
Build cannot resolve Glance classes Dependency or Compose support missing Add glance-appwidget and enable Compose
Widget shows only a loading surface provideGlance() fails before content renders Check Logcat for the first composition exception
Widget starts at an odd size Sizing metadata does not match the intended footprint Set both cell targets and dp minimums
Widget never refreshes updatePeriodMillis is 0 and no update is requested Call a Glance update after app data changes
Background refresh is unreliable Long work is running in a receiver Move long work to WorkManager, then update the widget

Periodic timing also has limits. Android Developers states that the app-widget system does not honor updatePeriodMillis values below 30 minutes, and current Glance guidance favors infrequent background refreshes to reduce battery work. For data that changes when the user edits the app, an immediate Glance update after the write is usually a better fit than polling.

From Empty Project To Working Widget

A working first widget comes down to six checks, and each one can be verified before adding live data or tap actions. Finish this sequence with the static greeting visible on the home screen, then build on a known-good provider.

  1. Add stable androidx.glance:glance-appwidget:1.1.1 and make sure Compose support is enabled.
  2. Create the AppWidgetProviderInfo XML under res/xml with both cell and dp sizing.
  3. Use @layout/glance_default_loading_layout as the initial loading layout.
  4. Create a GlanceAppWidget that renders one small piece of content.
  5. Create a GlanceAppWidgetReceiver and register it with the update intent plus metadata in AndroidManifest.xml.
  6. Install the app, open Widgets from the home screen, place the widget, and confirm the greeting renders.

Once that version works, add state, actions, responsive sizing, previews, or scheduled refreshes one feature at a time. That keeps the next failure tied to the last change instead of hiding it inside several new moving parts.

References & Sources

  • Android Developers.“Create an app widget with Glance.”Documents Glance widget metadata, receivers, sizing attributes, and Kotlin UI structure.
  • Jetpack Glance.“Jetpack Glance.”Official Android overview for building app widgets with Kotlin APIs.
  • WorkManager.“WorkManager.”Official API reference for persistent background work used when widget refresh work should not run in a receiver.

Please use a real email you check. If it's fake or mistyped, your message won't reach us and we can't reply — wrong addresses are rejected automatically.