feat(android): support multiple simultaneous foreground services#6
Merged
feat(android): support multiple simultaneous foreground services#6
Conversation
Introduces a flexible multi-service architecture while preserving full
backward compatibility for existing single-service apps.
Android:
- Add `FlutterForegroundServiceBase` abstract class; `ForegroundService`
becomes a thin `serviceId="default"` subclass.
- Add `FlutterForegroundServiceRegistry` (singleton) with a static-init
default registration so `RebootReceiver`/`RestartReceiver` can resolve
services at cold boot, before any Flutter engine attaches.
- Add `ForegroundServiceRuntime` to manage per-id running state, task
references, and lifecycle listeners, replacing companion-object statics.
- Scope all `SharedPreferences` files by `serviceId` via
`ForegroundTaskStorageProvider`; default id uses the unchanged legacy
file names (zero migration for existing installs).
- Thread `serviceId` through `ForegroundServiceManager`, model companions,
`RestartReceiver`, `RebootReceiver`, `ForegroundServiceUtils`, and
`MethodCallHandlerImpl`.
- Send `onServiceIdSet` over the background channel immediately before
`onStart` so each Dart isolate knows its own service id.
Dart:
- Add `FlutterForegroundTaskController.of(id)` for explicit per-service
management (init/start/stop/update/restart, communication ports, storage).
- Expose `FlutterForegroundTask.currentServiceId` (set by native layer on
isolate start) and make `sendDataToMain` route automatically to the
correct controller, fixing silent data loss for non-default services.
- `FlutterForegroundTask` static API delegates to
`FlutterForegroundTaskController.of('default')` — no breaking changes.
- Add `serviceId` parameter to platform-interface and method-channel
implementations.
Docs:
- Add `documentation/multiple_services.md` covering subclassing, manifest
entries, `Application.onCreate` registration, Dart controller usage,
isolate model, and backward-compatibility table.
- Update `documentation/android_shared_preferences_usage.md` with the
serviceId-scoped diagram and corrected class references.
- Add "Multiple services (Android)" entry to README.
Add manifest validation before starting any foreground service. The library now checks PackageManager.getServiceInfo() to confirm a service class is declared in AndroidManifest.xml before attempting to start it. - Add FlutterForegroundServiceRegistry.isServiceDeclaredInManifest() - Gate ForegroundServiceManager.start() with a manifest check that throws IllegalStateException with a helpful message when the entry is missing - Gate RebootReceiver to skip registered services not in the manifest - Gate RestartReceiver to bail early for undeclared services - Update documentation to reflect that the default <service> entry is optional when only custom service subclasses are used
936cfd0 to
c4647ed
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
FlutterForegroundServiceBase(abstract),FlutterForegroundServiceRegistry, andForegroundServiceRuntimeon the Android side;FlutterForegroundTaskController.of(id)on the Dart side.ForegroundServicemanifest entry optional — the library validates the manifest at runtime and throws a clear error (or silently skips at boot) if a service class is not declared.Changes
Android (Kotlin)
FlutterForegroundServiceBase— new abstract base class containing all service logic;ForegroundServicebecomes a thinserviceId="default"subclass.FlutterForegroundServiceRegistry— singleton mappingserviceId→Serviceclass, with auto-registration of the default in a static initializer (available at cold boot). IncludesisServiceDeclaredInManifest()for runtime validation.ForegroundServiceRuntime— per-id running state, task references, and lifecycle listeners (replaces companion-object statics).ForegroundServiceManager— all methods acceptserviceId;start()validates the manifest before proceeding.RebootReceiver/RestartReceiver— iterate registered ids, skip services not declared in the manifest.serviceIdfor scoped SharedPreferences.ForegroundTask— sendsonServiceIdSetto the Dart isolate sosendDataToMainroutes correctly.MethodCallHandlerImpl— extractsserviceIdfrom method channel args.Dart
FlutterForegroundTaskController— instance-based API (init,start,stop,update,restart, communication ports, storage) scoped by service id.FlutterForegroundTask— static API now delegates toFlutterForegroundTaskController.of('default')for full backward compatibility.currentServiceId— set by the native layer on isolate start;sendDataToMainauto-routes to the correct port.serviceIdparameter threaded through all service methods.Documentation
documentation/multiple_services.md— full guide: Kotlin subclassing, manifest entries,Application.onCreateregistration, Dart controller usage, communication ports, backward-compatibility table, limitations.documentation/android_shared_preferences_usage.md— updated architecture diagram and class references.README.md— new "Multiple services (Android)" section linking to the guide.Backward compatibility
Existing single-service apps require zero changes. All public API signatures are preserved. SharedPreferences file names for the
"default"id are identical to the pre-refactor layout.Test plan
flutter test)flutter analyzeclean (only pre-existing deprecation infos)<service>subclass to the example, verify both services run simultaneously with independent notifications<service>entry from the manifest, verifystartServicethrowsIllegalStateExceptionwith a helpful messageautoRunOnBootworks for declared services and is skipped for undeclared onessendDataToMaindelivers data to the correct UI-side controller for non-default services