glance_widget 1.0.1 copy "glance_widget: ^1.0.1" to clipboard
glance_widget: ^1.0.1 copied to clipboard

Create instant-updating home screen widgets for Android (Jetpack Glance) and iOS (WidgetKit). Supports Simple, Progress, List, Image, Chart, Calendar, and Gauge widget templates.

glance_widget #

pub package License: MIT

Create instant-updating home screen widgets for Android and iOS. Built with Jetpack Glance (Android) and WidgetKit (iOS).

List, Image and Chart widgets Gauge, Image and Progress widgets Progress and Bitcoin widgets

Why glance_widget? #

Unlike other packages (e.g., home_widget) that only provide a data bridge and require you to write all widget UI in native Swift/Kotlin, glance_widget is a complete solution — zero native code required.

glance_widget home_widget
Widget UI 7 ready-to-use templates Write native code yourself
Type Safety sealed class + generic controllers — compile-time errors String keys — runtime errors
Real-time Updates DebouncedWidgetController — 100ms coalescing, auto-flush on app background Not available — build it yourself
Background Updates Built-in GlanceBackground (WorkManager + Timeline) Requires external flutter_workmanager
iOS Push Built-in iOS 26+ APNs support Not available
Platform Safety GlanceConfig.strictMode — graceful on Web/desktop Crashes on unsupported platforms
Native Code Zero Required for every widget

Features #

  • Instant Updates - Widgets update in < 1 second on both platforms
  • Cross-Platform - Same API for Android and iOS
  • 7 Widget Templates - Simple, Progress, List, Image, Chart, Calendar, and Gauge
  • Theme Support - Light/Dark themes with full customization
  • Deep Links - All widgets support custom deep link URIs
  • Interactive Actions - Tap, checkbox toggle, item tap handling
  • Background Updates - Android widgets update even when app is closed (WorkManager)
  • Timeline Refresh - iOS widgets refresh periodically via WidgetKit timeline policy
  • iOS 26+ Push Updates - Server-triggered widget updates via APNs
  • Lock Screen Widgets - Android widgets on home screen and lock screen
  • Real-time Data - Debounced controller for high-frequency updates (crypto, stocks)
  • Widget Configuration - Handle widget setup flow when users add widgets

Platform Comparison #

Feature Android (Jetpack Glance) iOS (WidgetKit)
Update Speed < 1 second < 1 second (app foreground)
Background Updates WorkManager (15 min+) Timeline-based (.after policy)
Server Push N/A iOS 26+ (APNs)
Lock Screen Supported (keyguard) N/A
Interactive Actions ActionCallback URL-based actions
Min Version Android 8.0 (API 26) iOS 16.0

Widget Templates #

Template Description Use Cases
SimpleWidget Title + Value + Subtitle Crypto prices, weather, stats
ProgressWidget Circular/Linear progress Downloads, goals, battery
ListWidget Scrollable item list with checkboxes To-do, shopping, activities
ImageWidget Photo with title and subtitle Photo of the day, album art
ChartWidget Line, bar, or sparkline chart Revenue trends, analytics
CalendarWidget Date header with event list Daily schedule, meetings
GaugeWidget Radial or dashboard metrics CPU usage, performance scores

Installation #

Add to your pubspec.yaml:

dependencies:
  glance_widget: ^1.0.0

Requirements #

Platform Minimum Version
Flutter 3.27+
Dart 3.6+
Android API 26 (Android 8.0)
iOS 16.0

Android Setup #

1. Configure Manifest #

Add widget receivers to android/app/src/main/AndroidManifest.xml:

<application>
    <!-- Simple Widget -->
    <receiver
        android:name="com.example.glance_widget_android.templates.SimpleWidgetReceiver"
        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/simple_widget_info" />
    </receiver>

    <!-- Progress Widget -->
    <receiver
        android:name="com.example.glance_widget_android.templates.ProgressWidgetReceiver"
        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/progress_widget_info" />
    </receiver>

    <!-- List Widget -->
    <receiver
        android:name="com.example.glance_widget_android.templates.ListWidgetReceiver"
        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/list_widget_info" />
    </receiver>

    <!-- Image Widget -->
    <receiver
        android:name="com.example.glance_widget_android.templates.ImageWidgetReceiver"
        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/image_widget_info" />
    </receiver>

    <!-- Chart Widget -->
    <receiver
        android:name="com.example.glance_widget_android.templates.ChartWidgetReceiver"
        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/chart_widget_info" />
    </receiver>

    <!-- Calendar Widget -->
    <receiver
        android:name="com.example.glance_widget_android.templates.CalendarWidgetReceiver"
        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/calendar_widget_info" />
    </receiver>

    <!-- Gauge Widget -->
    <receiver
        android:name="com.example.glance_widget_android.templates.GaugeWidgetReceiver"
        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/gauge_widget_info" />
    </receiver>
</application>

2. Create Widget Info XML #

Create android/app/src/main/res/xml/simple_widget_info.xml (repeat for each template):

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="180dp"
    android:minHeight="110dp"
    android:targetCellWidth="3"
    android:targetCellHeight="2"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen|keyguard"
    android:updatePeriodMillis="0" />

3. Set SDK Versions #

In android/app/build.gradle.kts:

android {
    compileSdk = 36
    defaultConfig {
        minSdk = 26
    }
}

iOS Setup #

1. Create Widget Extension #

In Xcode:

  1. Open ios/Runner.xcworkspace
  2. File → New → Target → Widget Extension
  3. Name: GlanceWidgets
  4. Click Finish

2. Configure App Groups #

Both targets need the same App Group:

  1. Select Runner target → Signing & Capabilities → + App Groups
  2. Add: group.com.yourcompany.yourapp
  3. Select GlanceWidgets target → repeat with same App Group ID

3. Add Widget Files #

Copy files from glance_widget_ios/example/ios/GlanceWidgets/ to your extension:

  • GlanceWidgets.swift
  • SharedModels.swift (update appGroupId!)
  • SimpleWidget.swift
  • ProgressWidget.swift
  • ListWidget.swift
  • ImageWidget.swift
  • ChartWidget.swift
  • CalendarWidget.swift
  • GaugeWidget.swift

4. Configure URL Scheme #

Add to ios/Runner/Info.plist:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>glancewidget</string>
        </array>
    </dict>
</array>

See iOS Widget Setup Guide for detailed instructions.


Usage #

Simple Widget #

import 'package:glance_widget/glance_widget.dart';

await GlanceWidget.simple(
  id: 'crypto_btc',
  title: 'Bitcoin',
  value: '\$94,532.00',
  subtitle: '+2.34%',
  subtitleColor: Colors.green,
  deepLinkUri: 'myapp://crypto/btc',
);

Type-Safe Controllers (v1.0) #

For advanced use cases, use generic type-safe controllers:

import 'package:glance_widget/glance_widget.dart';

// Convenience controller — compile-time type safety
final controller = SimpleWidgetController(widgetId: 'crypto_btc');

await controller.update(SimpleWidgetData(
  title: 'Bitcoin',
  value: '\$94,532.00',
  subtitle: '+2.34%',
  subtitleColor: Colors.green,
));

// Listen for widget interactions
controller.onAction.listen((action) {
  print('Widget tapped: ${action.type}');
});

// Don't forget to dispose
controller.dispose();

Available controllers:

  • SimpleWidgetController
  • ProgressWidgetController
  • ListWidgetController
  • ImageWidgetController
  • ChartWidgetController
  • CalendarWidgetController
  • GaugeWidgetController

Or use the generic form directly:

final ctrl = GlanceWidgetController<ChartWidgetData>(widgetId: 'chart1');
await ctrl.update(ChartWidgetData(
  title: 'Revenue',
  dataPoints: [12, 19, 15, 25, 22, 30, 28],
));
ctrl.dispose();

Progress Widget #

await GlanceWidget.progress(
  id: 'daily_goal',
  title: 'Steps Today',
  progress: 0.75,
  subtitle: '7,500 / 10,000',
  progressType: ProgressType.circular,
  progressColor: Colors.green,
);

List Widget #

await GlanceWidget.list(
  id: 'todo_list',
  title: 'Today\'s Tasks',
  items: [
    GlanceListItem(text: 'Buy groceries', checked: true),
    GlanceListItem(text: 'Call mom', checked: false),
  ],
  showCheckboxes: true,
);

Image Widget #

await GlanceWidget.image(
  id: 'photo',
  title: 'Photo of the Day',
  imageBase64: base64EncodedImage,
  subtitle: 'Beautiful sunset',
  fit: ImageFit.cover,
);

Chart Widget #

await GlanceWidget.chart(
  id: 'revenue',
  title: 'Revenue',
  dataPoints: [12, 19, 15, 25, 22, 30, 28],
  chartType: ChartType.line,
  color: Colors.blue,
  subtitle: 'Last 7 days',
);

Calendar Widget #

await GlanceWidget.calendar(
  id: 'events',
  title: 'Today\'s Events',
  date: DateTime.now(),
  events: [
    CalendarEvent(time: '09:00', title: 'Standup', color: Colors.green),
    CalendarEvent(time: '14:00', title: 'Review', color: Colors.blue),
  ],
);

Gauge Widget #

await GlanceWidget.gauge(
  id: 'monitor',
  title: 'System Monitor',
  metrics: [
    GaugeMetric(label: 'CPU', value: 45, maxValue: 100, color: Colors.green, unit: '%'),
    GaugeMetric(label: 'Memory', value: 72, maxValue: 100, color: Colors.orange, unit: '%'),
  ],
  gaugeType: GaugeType.radial,
);

Theme Configuration #

await GlanceWidget.setTheme(GlanceTheme.dark());

// Or custom theme
await GlanceWidget.setTheme(GlanceTheme(
  backgroundColor: Color(0xFF1A1A2E),
  textColor: Colors.white,
  secondaryTextColor: Color(0xFFB0B0B0),
  accentColor: Colors.orange,
  borderRadius: 16.0,
  isDark: true,
));

Handle Widget Actions #

GlanceWidget.onAction.listen((action) {
  switch (action.type) {
    case GlanceActionType.tap:
      print('Widget ${action.widgetId} tapped');
      break;
    case GlanceActionType.checkboxToggle:
      print('Item ${action.itemIndex} toggled to ${action.value}');
      break;
    case GlanceActionType.itemTap:
      print('Item ${action.itemIndex} tapped');
      break;
    case GlanceActionType.configure:
      // Show configuration UI, then:
      GlanceWidget.completeWidgetConfiguration(action.widgetId);
      break;
    default:
      break;
  }
});

All widget types support deepLinkUri parameter:

await GlanceWidget.simple(
  id: 'btc',
  title: 'Bitcoin',
  value: '\$94,532',
  deepLinkUri: 'myapp://crypto/btc',  // Opens when widget is tapped
);

Background Updates (Android) #

await GlanceBackground.configureUpdate(
  widgetId: 'crypto_btc',
  template: GlanceTemplate.simple,
  apiUrl: 'https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd',
  intervalMinutes: 15,
  title: 'Bitcoin',
  valuePath: r'$.bitcoin.usd',
  valuePrefix: r'$',
);

// Cancel
await GlanceBackground.cancelUpdate('crypto_btc');

// Check status
final status = await GlanceBackground.getUpdateStatus('crypto_btc');

Timeline Refresh (iOS) #

await GlanceBackground.configureTimelineRefresh(
  widgetId: 'weather',
  intervalMinutes: 30,
);

await GlanceBackground.cancelTimelineRefresh('weather');

DebouncedWidgetController (Real-time Data) #

For high-frequency updates like crypto prices or live scores:

final controller = DebouncedWidgetController<SimpleWidgetData>(
  widgetId: 'crypto_btc',
  theme: GlanceTheme.dark(),
  debounceInterval: Duration(milliseconds: 100),
  maxWaitTime: Duration(milliseconds: 500),
  stalenessThreshold: Duration(seconds: 15),
);

priceStream.listen((price) {
  controller.scheduleUpdate(SimpleWidgetData(
    title: 'Bitcoin',
    value: '\$${price.toStringAsFixed(2)}',
  ));
});

// Flushes pending updates automatically when app goes to background
controller.dispose();

iOS 26+ Server Push Updates #

if (await GlanceWidget.isWidgetPushSupported()) {
  final token = await GlanceWidget.getWidgetPushToken();
  if (token != null) {
    await api.registerWidgetPushToken(token);
  }
}

Platform Safety #

glance_widget runs gracefully on unsupported platforms (Web, macOS, Windows, Linux):

// Default: methods return false/empty and log a warning
await GlanceWidget.simple(id: 'test', title: 'T', value: 'V'); // no-op on Web

// Opt-in to strict mode (recommended in debug):
GlanceConfig.strictMode = kDebugMode; // throws UnsupportedError on Web/desktop

Architecture #

Package Description
glance_widget Main package with cross-platform API
glance_widget_platform_interface Platform-independent interface
glance_widget_android Android implementation (Jetpack Glance)
glance_widget_ios iOS implementation (WidgetKit)

Example #

Check the example directory for a complete demo app showing all 7 widget types.

cd example
flutter run

Contributing #

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

License #

MIT License - see LICENSE for details.

4
likes
150
points
209
downloads

Documentation

Documentation
API reference

Publisher

verified publisherabdullahtas.dev

Weekly Downloads

Create instant-updating home screen widgets for Android (Jetpack Glance) and iOS (WidgetKit). Supports Simple, Progress, List, Image, Chart, Calendar, and Gauge widget templates.

Repository (GitHub)
View/report issues

Topics

#widget #android #ios #glance #widgetkit

License

MIT (license)

Dependencies

flutter, glance_widget_android, glance_widget_ios, glance_widget_platform_interface, logging

More

Packages that depend on glance_widget

Packages that implement glance_widget