Skip to content

feat: flet-notifications extension - #6999

Open
ndonkoHenri wants to merge 133 commits into
flet-1.1.0from
feat/flet-notifications
Open

ndonkoHenri wants to merge 133 commits into
flet-1.1.0from
feat/flet-notifications

Conversation

@ndonkoHenri

@ndonkoHenri ndonkoHenri commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #6948

Builds on @Nwokike's work in #6977.

Adds flet-notifications, a service for local notifications on Android, iOS, macOS, Windows, Linux and Web, built on flutter_local_notifications.

The notifications are local: the app posts them itself, now or scheduled ahead, and the OS delivers scheduled ones even while the app isn't running. Push notifications (FCM/APNs) are out of scope.

The extension

import flet as ft
import flet_notifications as ftn


def main(page: ft.Page):
    def handle_tap(e: ftn.NotificationEvent):
        page.add(ft.Text(f"Opened {e.payload}"))

    def handle_action(e: ftn.NotificationActionEvent):
        page.add(ft.Text(f"{e.action_id} on {e.payload}"))

    notifications = ftn.Notifications(on_tap=handle_tap, on_action=handle_action)

    async def notify(e: ft.Event[ft.Button]):
        await notifications.request_permissions()
        await notifications.show(
            id=1,
            title="Ada",
            body="Lunch at noon?",
            payload="chat:ada",
            actions=[ftn.NotificationAction(id="archive", title="Archive")],
        )

    page.add(ft.SafeArea(content=ft.Button("Notify", on_click=notify)))


ft.run(main)
  • Showing: show(), schedule() (time-zone aware through ZoneInfo datetimes, with daily/weekly matching), periodically_show(), cancelling one or all, and listing pending and shown notifications.
  • Responses: on_tap and on_action (with reply text) are also called for the notification that launched the app, and for selections made while the app wasn't running: Android, iOS and macOS queue them natively and hand them over once the service starts, and Windows starts a flet build app to deliver them (see the limitations for Linux and other Windows apps).
  • Platform options: each platform has its own class, AndroidOptions (styles, progress, groups, channels, full-screen), DarwinOptions, WindowsOptions, LinuxOptions and WebOptions, all passed together in NotificationOptions.
  • Android extras: permission requests (notifications, exact alarms, full-screen, Do Not Disturb access), notification channels and channel groups, and a foreground service.
  • Errors: failures raise NotificationException subclasses (unsupported platform, invalid argument, permission denied, …).
  • Windows: each app gets its own notification identity, derived from the executable, so toasts from different Flet apps don't mix and a click reaches the copy of the app that posted it. A flet build app also registers itself as the COM server Windows starts for a click made after the app exited, so cold taps, actions and replies reach on_tap/on_action. The plugin only registers its activator inside the running process.
Platform Show Schedule Repeat Actions Reply input List shown
Android ✅ ✅ ✅ ✅ ✅ ✅
iOS / macOS ✅ ✅ ✅ ✅ ✅ ✅
Windows ✅ ✅ one-off ❌ ✅ ✅ MSIX only
Linux ✅ ❌ ❌ ✅ while running ❌ ❌
Web ✅ ❌ ❌ browser-dependent ❌ ✅

Docs: website/docs/services/notifications/, with ten focused examples (basic, permissions, actions, scheduling, exact alarms, progress, active notifications, Android styles, channels, foreground service).

Changes outside the extension

The extension needed some general flet build and flet pack features. They aren't notification-specific, so reviewing them on their own may be easier:

flet build

  • Extension build settings: an extension can ship a flet-extension.toml declaring the Android compile options and Gradle dependencies its Flutter package needs. These are applied to every app that installs the extension, with the app's own pyproject.toml winning (documented in website/docs/extend/user-extensions.md). flet create --template extension scaffolds a commented one. Manifest entries come from the Flutter plugin's own AndroidManifest.xml through the manifest merger, as for any plugin. flet-notifications ships this one:

    # flet-extension.toml
    [android]
    gradle_dependencies = 'coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")'
    
    [android.compile_options]
    isCoreLibraryDesugaringEnabled = "true"
  • New Android settings: compile_options, gradle_dependencies, manifest receiver and service entries, and res_dir for app-provided resources (a notification icon or sound), which are kept in release builds:

    [tool.flet.android]
    res_dir = "android_res"
    gradle_dependencies = 'implementation("com.google.code.gson:gson:2.12.0")'
    
    [tool.flet.android.compile_options]
    sourceCompatibility = "JavaVersion.VERSION_1_8"
    
    [tool.flet.android.receiver."com.example.BootReceiver"]
    exported = false
    
    [[tool.flet.android.receiver."com.example.BootReceiver".intent_filter]]
    actions = ["android.intent.action.BOOT_COMPLETED"]
    
    [tool.flet.android.service."com.example.SyncService"]
    exported = false
    foregroundServiceType = "dataSync"
  • iOS entitlements: [tool.flet.ios.entitlement], or --ios-entitlements on the command line:

    [tool.flet.ios.entitlement]
    aps-environment = "production"
    "com.apple.security.application-groups" = ["group.dev.example.myapp"]
  • Template context: settings now reach the template unrendered as cookiecutter._options / cookiecutter._pyproject, so numbers keep their types and {{ in a value no longer breaks the build. This breaks custom --template authors (see below).

  • Startup fix: built apps no longer show a blank page when the OS suspends them while Python starts, as iOS does when launching an app in the background for a notification action.

  • Windows -Embedding: built apps ignore the -Embedding argument COM adds when Windows starts them for a notification; it was taken as a dev-mode page URL, leaving a blank window.

  • Default bundle ID: flet build now resolves the default bundle ID (<org>.<project slug>, org com.flet) itself instead of leaving it to the template. With no bundle_id set, the build used to name a Linux app's icons None.png, and skip SERIOUS_PYTHON_BUNDLE_ID, leaving the iOS frameworks built from the app's packages under shared identifiers (bug:ITMS-91065 Missing signature for _ssl.framework and _hashlib.framework in iOS IPA built with Flet 0.86.2 #6724). The template no longer derives it, so the two can't drift.

  • flutter doctor fix: a build that fails before the Flutter SDK is found no longer crashes with a TypeError instead of reporting the error.

flet pack

  • Warns about each extension the app imports that the prebuilt client doesn't include.
  • Quiet by default: -v shows progress and PyInstaller's INFO log, -vv its DEBUG log.
  • Writes the app icon to data/app_icon.ico, which Windows notifications use.
  • Passes the packed app's Windows identity to the client.
  • Leaves Windows taskbar code out of non-Windows apps.

Core and client

  • Validation rules accept T | None annotations (only Optional[T] worked before).
  • FilePicker dialogs no longer fail with a timeout after an hour open. The fixed timeouts on permission requests and file dialogs are gone.
  • The client registers flet_notifications. The plugin registrants and the iOS AppDelegate are updated.

Docs

  • New Android publishing sections for the settings above, iOS entitlements, extension build settings, and FLET_DESKTOP_FLAVOR.
  • Unrelated, picked up on the way: a "quick preview from your terminal" section on the docs home page.

Breaking change

Custom flet build templates must read cookiecutter._options and cookiecutter._pyproject instead of cookiecutter.options and cookiecutter.pyproject. Nothing else here has shipped before.

Known limitations

  • Full-screen notifications on a locked device: Android wakes the screen and starts the app, but the app stays behind the lock screen. Showing it over the lock screen needs showWhenLocked/turnScreenOn on MainActivity, which would need an opt-in flet build setting. Documented on AndroidOptions.full_screen_intent.
  • Linux: taps and actions reach the app only while it's running. Starting a closed app from a notification needs D-Bus activation, which Flet's Linux builds don't set up.
  • Windows, flet run and flet pack: taps and actions reach the app only while it's running; clicking a notification after the app has closed doesn't start it. Windows can only start a flet build app, which runs its own Python; the Flet client of flet run and flet pack needs Python to start it with the app.
  • Windows: listing and cancelling shown notifications works only for MSIX-packaged apps (an OS restriction).

Testing

  • Android: 16 emulator, every example, including cold launches from a tap and from an action, exact alarms, channels and the foreground service.
  • iOS: simulator, every example, including a background action with the app killed.
  • Windows: 11 VM, actions with reply, progress, scheduling, the active list, identity (toasts routed to the right copy of the app), and a body click, an action and a reply made after the app exited, each starting the app and reaching its handler.
  • Linux: Ubuntu 24.04 arm64 VM, show, tap and action buttons.
  • Web: Brave, permission, body click and actions.
  • macOS: built and run, and the permission prompt appears.
  • Automated: 75 Dart VM tests and 7 browser tests in the extension; Python tests for the extension, flet build (Android, iOS, template, extension settings) and flet pack.

Nwokike and others added 30 commits October 15, 2026 21:16
`LocalNotifications` service wrapping flutter_local_notifications for Android,
iOS, macOS, Windows, Linux and Web: show, schedule (zoned, daily, weekly,
periodic), cancel, permissions and probes, Android channels and foreground
service, rich styles (big text/picture/inbox/messaging), inline-reply actions
and typed on_tap/on_action/on_dismissed handlers.

The plugin needs scheduled-notification receivers and core-library-desugaring
Gradle flags that [tool.flet.android.*] cannot declare, so the package ships an
idempotent `flet-notifications-patch` console script for the built project.
@sourcery-ai

sourcery-ai Bot commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Sorry @ndonkoHenri, your pull request is larger than the review limit of 150,000 diff characters

@ndonkoHenri ndonkoHenri changed the title Add flet-notifications extension feat: flet-notifications extension Oct 25, 2026
@ndonkoHenri ndonkoHenri linked an issue Oct 25, 2026 that may be closed by this pull request
@ndonkoHenri ndonkoHenri mentioned this pull request Oct 25, 2026
9 tasks done
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Deploying flet-website-v2 with  Cloudflare Pages  Cloudflare Pages

Latest commit: dddc118
Status: ✅  Deploy successful!
Preview URL: https://dec45332.flet-website-v2.pages.dev
Branch Preview URL: https://feat-flet-notifications.flet-website-v2.pages.dev

View logs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New extension: flet-notifications for local notifications

2 participants