Knock Flutter client library
A client-side Flutter library to interact with user-facing Knock features, such as feeds.
Note: This is a lower-level library intended for building your own notification UIs on top of Knock’s APIs (feeds, preferences, channels, messages).
Installation
flutter pub add knock_flutter
or add it to your pubspec.yaml:
dependencies:
knock_flutter: ^1.1.0
Requires Dart SDK >=3.8.0 and Flutter >=3.32.0.
Upgrading from 1.0.x to 1.1.0
1.1.0 is a stabilization release. Three behavior changes may need attention (details in CHANGELOG.md):
KnockMessageDeliveryStatus.bouncedandKnockMessageEngagementStatus.linkClickedwere added; exhaustiveswitchstatements over these enums need the new cases.FeedClients for the same feed channel share one realtime subscription (see Realtime feeds).knock.authenticate()with a different user disposes the previous user's feeds (see Lifecycle and cleanup).
Migrating from 0.1.x to 1.0.0
Version 1.0.0 is a major release with breaking changes. Read CHANGELOG.md for the full list. Highlights:
| Before (0.1.x) | After (1.0.0) |
|---|---|
ApiClient |
KnockApiClient (knock.client()) |
ApiResponse |
KnockApiResponse |
ApiClientStatus |
KnockApiClientStatus |
ApiError (extends Error) |
KnockApiException (implements Exception) |
knock.getFcmToken() / knock.getApnsToken() |
Obtain tokens yourself (e.g. firebase_messaging); see Push notifications |
- Catch semantics: Prefer
on KnockApiException catchorcatch (e)ande is KnockApiException. Code that only caughtErrorsubtypeApiErrorwill not catchExceptionsubtypeKnockApiException. - Flutter / Dart SDK: Requires Dart SDK
>=3.8.0and Flutter>=3.32.0.
Documentation
See the documentation for usage examples.
Lifecycle and cleanup
- Call
knock.dispose()when you are finished with theKnockinstance (your app teardown or logout flows). - For each
FeedClientcreated viaknock.feed(...), callfeedClient.dispose()when that feed is torn down (e.g. navigating away). This unsubscribes from the Phoenix socket and cleans listeners. Optionally cancel any subscriptions onfeedClient.feed;dispose()clears the rest deterministically. Afterdispose(),feedClient.feedis an empty stream. knock.dispose()andknock.logout()also dispose everyFeedClientcreated from that instance.- Calling
knock.authenticate(...)with a different user disposes the current API client, its socket and its feeds; create new feeds for the new user. Calling it again for the same user only updates the user token (for example after a token refresh); the new token is used for subsequent requests and when the socket reconnects.
Realtime feeds
Several FeedClients for the same feed channel (for example a badge counter and a feed list) share one realtime channel. The channel is joined with the options of the first client that subscribes; every client still fetches its own items with its own options when a realtime update arrives.
Feed loading state (NetworkStatus.initial)
Feed.initialState() now uses NetworkStatus.initial before any HTTP fetch runs. Prefer checking feed.requestInFlight (or treating loading/fetchMore/error explicitly) rather than relying on NetworkStatus.ready alone—the feed is empty while initial.
Push notifications
The SDK does not fetch FCM/APNS tokens (the old Android/iOS plugin was removed). In your app:
- Complete platform setup using Firebase for Flutter (or another push provider compatible with Knock’s channel APIs).
- Add
firebase_coreandfirebase_messagingas usual. - Retrieve tokens—for example
FirebaseMessaging.instance.getToken()on Android /getAPNSToken()on Apple platforms when available. - Register with Knock via:
await knock.user().registerTokenForChannel(channelId, token);
Optionally override the inferred locale passed to Knock:
await knock.user().registerTokenForChannel(
channelId,
token,
languageTag: 'en-US',
);
For a fuller flow, including Firebase initialization guarded when no project is configured locally, see the example/ app and Running the example app.
Package Development
Code generation
Code generation is limited to supporting JSON serialization/deserialization of API messages. If you need to adjust the generated code, run from the repo root:
dart run build_runner build
Generated files are checked into version control because they ship with the published package. CI fails if they are out of date. The code generators are pinned to exact versions in pubspec.yaml; bump them deliberately and regenerate.
Development uses the Flutter version pinned in .github/workflows/quality.yml. CI also checks the library against the minimum supported Flutter version from pubspec.yaml.
Release (internal)
Manually update CHANGELOG.md.
Update version: in pubspec.yaml.
Create a PR.
After your PR is merged, run /release status knock-flutter in Slack to start the release process.
Running the example app
Requirements for this repository’s example app mirror a normal Flutter app:
cd example
flutter pub get
To exercise push-token buttons in example/lib/main.dart, configure Firebase (e.g. add google-services.json, GoogleService-Info.plist, and firebase_options.dart from your Firebase project). Without them, Firebase.initializeApp() falls back gracefully and push-token actions show a helper message rather than crashing. See example/README.md for concrete steps.
Otherwise, follow Flutter’s test drive: select a device, then run/Debug (e.g. F5).
You can monitor build progress in the Debug Console until the app appears on device or simulator.
Libraries
- knock_flutter
- Knock Flutter SDK