---
title: Update Widget
description: How to Update a native Widget from Flutter
nextTitle: iOS Setup
next: /setup/android
---

# Update Widget

In order to initiate a reload of the HomeScreenWidget you need to call
```dart
HomeWidget.updateWidget(
    name: 'HomeWidgetExampleProvider',
    androidName: 'HomeWidgetExampleProvider',
    iOSName: 'HomeWidgetExample',
    qualifiedAndroidName: 'com.example.app.HomeWidgetExampleProvider',
);
```

<Info>
<b>Not</b> all the arguments are required. Depending on your setup you might need to call different arguments of the function.
For iOS either `name` or `iOSName` must match the `kind` that is defined for the Widget
For Android either `name` or `androidName` must the class Name of your Widget <b>Receiver</b>. Alternatively you can point to the receivers full class using `qualifiedAndroidName`
</Info>


#### Android Glance

To ensure your Android Glance Widget is getting updated you need to add the following snippet to your Android Glance Widget. Please also make sure you read the full documentation on [Android Glance](/setup/android) to ensure you have the correct setup.

```kotlin
override val stateDefinition: GlanceStateDefinition<*>?
  get() = HomeWidgetGlanceStateDefinition()
```

## Scheduled Updates

Besides an immediate refresh, `HomeWidget.scheduleWidgetUpdates` schedules refreshes for specific points in time — useful if your widget's content should change on a timer without polling from a background task. It is a standalone API: it works with hand-written native widgets too, not only widgets generated by [home_widget_generator](/generator) (which uses it internally for [Time-based Content](/generator/timed-data)).

```dart
await HomeWidget.scheduleWidgetUpdates(
  [
    DateTime.now().add(const Duration(hours: 6)),
    DateTime.now().add(const Duration(hours: 12)),
  ],
  androidName: 'HomeWidgetExampleProvider',
);

await HomeWidget.cancelScheduledWidgetUpdates(
  androidName: 'HomeWidgetExampleProvider',
);
```

`name` / `androidName` / `qualifiedAndroidName` resolve the target widget the same way as `updateWidget` above. Scheduling replaces any previously scheduled updates for that widget. Passing an empty list is equivalent to `cancelScheduledWidgetUpdates`, and update times already in the past are ignored.

<Info>
<b>iOS</b> handles this natively: WidgetKit swaps timeline entries on its own, so `scheduleWidgetUpdates` is a no-op on iOS — `updateWidget`'s `reloadTimelines` call is enough there.
<b>Android</b> has no OS-level timeline API for widgets, so the plugin arms a single `AlarmManager` alarm per widget for the next update time; when it fires, it broadcasts a normal widget update and arms the alarm for the following time. Alarms don't survive a reboot or an app update, so a receiver in your app re-arms every pending schedule — see [Android setup](#android-setup-for-scheduled-updates) below. Once the last instance of a widget is removed from the home screen, its remaining scheduled updates are dropped automatically.
</Info>

### Timezones and DST

The passed `DateTime`s are **absolute instants**, not wall-clock times: only their epoch milliseconds reach the platform, so a local `DateTime` and its `toUtc()` equivalent schedule the exact same update. Nothing re-interprets an existing schedule when the clock rules change, so a recurring wall-clock schedule such as "every day at 06:00 local time" does not survive a DST switch or a timezone change on its own — recompute the times and call `scheduleWidgetUpdates` again if that drift matters.

### Exact vs. inexact updates

On Android 12 (API 31) and above, exact alarms require the app to declare either `android.permission.SCHEDULE_EXACT_ALARM` (pre-granted on Android 12–13; on Android 14+ the user has to enable it in system settings, and can revoke it again) or `android.permission.USE_EXACT_ALARM` (always granted, but only allowed for apps whose core function needs exact alarms — Google Play reviews this). The plugin declares neither, so the choice is yours.

`canScheduleExactWidgetUpdates` tells you which of the two applies:

```dart
final exact = await HomeWidget.canScheduleExactWidgetUpdates();
```

It returns `true` on iOS (WidgetKit renders timeline entries at their exact date) and on Android below 12; from Android 12 on it reflects `AlarmManager.canScheduleExactAlarms()`. When it is `false`, `scheduleWidgetUpdates` does not throw — it silently falls back to inexact alarms, which the system may delay.

#### If updates arrive too late

Widget content trailing its schedule by a few minutes on Android — while iOS switches on the second — is the inexact fallback at work, not a scheduling bug. Without an exact-alarm permission, Android deliberately holds each alarm in a delivery window so it can batch your update with other wakeups and save battery. How late an update arrives grows with the gap between updates; expect delays of a few minutes at typical schedules, occasionally more. Interacting with the device does not reliably speed delivery up, and in rare cases a delivery can slip so far that the next scheduled update overtakes it, skipping an entry outright.

If that is not precise enough for your content, opt in to exact updates:

1. **Declare the permission** in your app's `AndroidManifest.xml` — without this line the permission cannot be granted at all, and the system settings toggle for it does not even appear:

   ```xml
   <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
   ```

2. **On Android 14 and above, have the user enable it.** The permission lives under *Settings → Apps → Special app access → Alarms & reminders*. Send them there from your app with [`permission_handler`](https://pub.dev/packages/permission_handler)'s `Permission.scheduleExactAlarm`, ideally at the moment they turn on the feature that needs it. On Android 12–13 declaring the permission is enough — it is granted automatically.

3. **That's all.** The plugin notices the grant on its own and re-arms every pending schedule with exact alarms; the next `scheduleWidgetUpdates` call uses them too.

Before opting in, weigh the downsides — they are the reason Android gates this behind a permission:

- **Battery.** An exact alarm wakes the device on its own instead of piggybacking on another wakeup. A handful of updates per day is negligible; a widget updating every few minutes around the clock is not. Space updates as far apart as your content allows.
- **A settings hurdle on Android 14+.** Users have to flip a system toggle, and can revoke it later — so treat exactness as an enhancement, not something your widget breaks without.
- **`USE_EXACT_ALARM` is not a shortcut.** It skips the user-facing toggle, but Google Play restricts it to apps whose core purpose is alarms or calendars; using it for a widget risks rejection.

If the user revokes `SCHEDULE_EXACT_ALARM` after having granted it, the system force-stops the app and deletes all of its exact alarms outright — there is no broadcast for a revocation to react to. Re-arming happens automatically: the system sends `ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED` to `HomeWidgetScheduledUpdateReceiver` when the permission is *granted* again, which re-arms every pending schedule (falling back to inexact if the permission ends up not held after all). A reboot re-arms them too, independently of permission state. Until one of those happens, scheduled updates are simply paused.

### Android setup for scheduled updates

Scheduled updates are delivered to `es.antonborri.home_widget.HomeWidgetScheduledUpdateReceiver`. The plugin ships that receiver but does not register it, so that apps which never schedule an update do not inherit the boot permission. Apps that use scheduling have to add it to `android/app/src/main/AndroidManifest.xml`:

```xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application>
    <receiver
        android:name="es.antonborri.home_widget.HomeWidgetScheduledUpdateReceiver"
        android:exported="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
            <action android:name="android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED" />
        </intent-filter>
    </receiver>
</application>
```

<Info>
If you use [home_widget_cli](/generator) and your widget schema uses [`HWTimedData`](/generator/timed-data), this snippet is added to your app manifest automatically during generation — there is nothing to do by hand. Schemas without timed fields leave the manifest untouched.
</Info>

Without the manifest entry, the alarm is armed but never delivered, and the widget is silently never updated. To make that visible, `scheduleWidgetUpdates` logs a warning under the `HomeWidgetScheduler` tag whenever it schedules while the receiver is not registered. The receiver is not exported; `BOOT_COMPLETED`, `MY_PACKAGE_REPLACED` and `ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED` are protected system broadcasts and are delivered regardless.

