| name | flet-extension-workflow |
| description | Guided workflow for creating a Flet extension package (Service or UI Control) (Flet 0.85.x+). |
Flet Extension Workflow
You are guiding the user through creating a Flet extension package step by step. Follow these 6 phases in order.
Before starting, ask the user what Flutter package they want to wrap and whether it's a Service (no UI) or UI Control (visual widget).
Phase 1: Planning
- Identify the Flutter package — name on pub.dev, latest version
- Determine extension type:
- Service (
ft.Service) — for SDKs, background services, platform APIs
- UI Control (
ft.LayoutControl) — for widgets that render on screen
- Review the Flutter API — key classes, methods, events, callbacks
- Plan the Python API:
- Properties (sent to Flutter)
- Methods (invoke Flutter methods)
- Events (receive from Flutter)
- Sub-modules (if complex SDK with namespaces)
- Plan type mappings — Dart types → Python types
Summarize the plan before proceeding.
Phase 2: Scaffold
Use flet-pkg CLI to generate the project skeleton:
flet-pkg create my-extension --analyze
If scaffolding manually, create:
flet-my-extension/
├── pyproject.toml
└── src/
├── flet_my_extension/
│ ├── __init__.py
│ ├── my_control.py
│ └── types.py
└── flutter/flet_my_extension/
├── pubspec.yaml
└── lib/
├── flet_my_extension.dart
└── src/
├── extension.dart
└── my_service.dart
Ensure pyproject.toml includes:
[tool.setuptools.package-data]
"flutter.flet_my_extension" = ["**/*"]
Phase 3: Review Generated Code
Check and fix the generated code:
- Type mappings — verify Dart→Python type conversions are correct
- Method names —
camel_to_snake conversion from Dart
- Invoke keys —
_invoke_method("key") must match Dart switch cases
- Event names —
triggerEvent("name") → on_name: EventHandler
- @ft.control name — must match
control.type switch in Dart
- Enum values — string values that match Dart representations
- Platform validation — service-only or cross-platform?
Phase 4: Customize Implementation
Python side:
- Add any missing methods, properties, or events
- Implement sub-modules if the SDK has namespaces
- Add proper type annotations and docstrings
- Set up
__init__.py with __all__ exports
- Add
ErrorEvent and on_error handler
Dart side:
- Implement SDK initialization in
init()
- Wire up
_onInvokeMethod with all methods
- Set up SDK listeners →
control.triggerEvent()
- Add
_handleError with FlutterError.reportError
- Guard against duplicate listeners
- Add
dispose() cleanup
Phase 5: Test
- Create example app in
examples/:
import flet as ft
import flet_my_extension as fme
async def main(page: ft.Page):
service = fme.MyService(
on_event=lambda e: print(f"Event: {e.data}"),
on_error=lambda e: print(f"Error: {e.message}"),
)
page.services.append(service)
ft.run(main)
- Run example:
cd examples/flet_my_extension_example && flet run
- Unit tests: test Python classes, type conversions, enum values
- Integration test: verify invoke/trigger flow on target platforms
Phase 6: Publish
- Update metadata in
pyproject.toml (description, author, URLs)
- Create README.md with installation and usage examples
- Create CHANGELOG.md
- Build:
python -m build
- Publish to PyPI:
twine upload dist/*
- Note: Dart code is NOT published to pub.dev separately (
publish_to: none)
Reminders
@ft.control("Name") — PascalCase string must match Dart control.type
metadata={"skip": True} for all internal fields
- Always convert Dart args:
Map<String, dynamic>.from(args)
- Return bools as
.toString() in Dart
[tool.setuptools.package-data] is mandatory in pyproject.toml
- Service →
page.services.append() | UI → page.add()
- FletExtension →
createService() for services, createWidget() for UI