# mattermost_push_plugin An Android-first Flutter plugin for receiving Mattermost push notifications, displaying system notifications, handling tap events, processing inline replies, delivering ACKs, and securely storing device tokens, authentication tokens, and signing keys. --- ## Support Matrix | Platform | Support Status | Native Features Implemented | |---|---|---| | **Android** | **Full (Production Ready)** | Kotlin, Native FCM Service, Room DB, JJWT Verification, OkHttp ACK Client, Notification Builder, Inline Reply Receiver, Dismiss Receiver | | **iOS** | No-op Scaffold (Stub) | Future roadmap milestone | | **macOS** | No-op Scaffold (Stub) | Future roadmap milestone | --- ## Core Responsibilities This plugin isolates the Mattermost push notification domain logic from the host application. ```mermaid graph TD A[Mattermost Server] -->|Secure JWT Push| B(Plugin Native FCM Service) B -->|1. Signature Verification JJWT| C{Valid?} C -->|Yes| D[2. Store & Build Notification] C -->|No| E[Drop Push] D -->|3. OkHttp ACK API| A D -->|4. Display System Notification| F(Android Status Bar) F -->|Tap Notification| G[5. Method Channel Opened Event] F -->|Inline Reply| H[6. Broadcast Reply Receiver] H -->|Deliver via OkHttp| A G -->|Flutter Stream| I(Host App Navigation) ``` --- ## Public Dart API Reference Get the singleton instance via `MattermostPushPlugin.instance`. ### 1. Initialization Initialize the plugin channel subscriptions, listen to token refreshes, and request notification permissions: ```dart import 'package:mattermost_push_plugin/mattermost_push_plugin.dart'; await MattermostPushPlugin.instance.initialize(); ``` ### 2. Streams & Callbacks Set up listeners and navigation callbacks inside your app initialization flow: ```dart // 1. Listen to raw native notification events (Message, Clear, Session, etc.) MattermostPushPlugin.instance.onNotification.listen((data) { print("Raw push received: $data"); }); // 2. Listen to user interaction (notification tap) events MattermostPushPlugin.instance.onNotificationOpened.listen((event) { print("Notification clicked! Channel: ${event.channelId}, Root: ${event.rootId}"); }); // 3. Register navigation handlers (automatically triggered by onNotificationOpened) MattermostPushPlugin.instance.onNavigateToChannel = (String serverUrl, String channelId) { // Navigate the app to the specific channel }; MattermostPushPlugin.instance.onNavigateToThread = (String serverUrl, String rootId) { // Navigate the app to the specific CRT thread }; // 4. Triggered when the device token is registered/refreshed MattermostPushPlugin.instance.onDeviceTokenReady = (String deviceToken) { // e.g. "android_rn-v2:YOUR_FCM_TOKEN" // Send this token to the Mattermost server for token registration }; ``` ### 3. Credential & Signing Key Storing Securely write server-specific secrets to native persistent storage. These are required by the native service to decrypt and verify the authenticity of push messages. ```dart // Save authenticating token for HTTP ACK requests await MattermostPushPlugin.instance.setAuthToken( "https://mattermost.example.com", "YOUR_USER_AUTH_TOKEN", identifier: "user_session_id", // optional ); // Save public signing key for verification await MattermostPushPlugin.instance.setSigningKey( "https://mattermost.example.com", "YOUR_SERVER_PUBLIC_SIGNING_KEY", ); // Clear token on logout await MattermostPushPlugin.instance.clearAuthToken("https://mattermost.example.com"); // Fetch the formatted device token String? token = await MattermostPushPlugin.instance.getDeviceToken(); ``` --- ## Host App Integration & Responsibilities The host application (`apps/mobile`) acts as the consumer of the plugin and is responsible for: 1. **Firebase Configuration**: Include the `google-services.json` in `android/app/` and initialize Firebase in the Dart main block. 2. **Authentication Flow**: Call `setAuthToken` and `setSigningKey` on successful Mattermost login, and `clearAuthToken` on logout. 3. **App Navigation**: Implement `onNavigateToChannel` and `onNavigateToThread` callbacks to route users inside the Flutter UI. 4. **FCM Token Registration**: Send the formatted token received in `onDeviceTokenReady` to the Mattermost server. ### Firebase Messaging Manifest Collision Guard This plugin implements a custom Android FCM service (`MattermostFirebaseMessagingService`) that consumes incoming FCM payloads. To prevent manifest merge collisions with the standard Flutter `firebase_messaging` library, the plugin's `AndroidManifest.xml` disables the generic Flutter Firebase service via `tools:node="remove"`. Ensure that the host app does not redeclare duplicate FCM services unless explicitly configured to do so. --- ## Verification & Manual Smoke Testing Checklist Since full end-to-end FCM flows cannot be automated in headless test runners, verify functionality manually using the following checklist: - [ ] **FCM Payload Receipt**: Verify that sending an FCM notification payload targeting the host application successfully wakes up `MattermostFirebaseMessagingService`. - [ ] **Signature Verification**: Ensure that a valid push payload signed by the Mattermost server's private key compiles and passes the native JJWT verification using the stored signing key. - [ ] **Notification Display**: Verify the system notification builds with the correct title, message, avatar (if supplied), and CRT threading hierarchy. - [ ] **ACK Delivery**: Verify the plugin sends a HTTP `POST` receipt delivery ACK back to the Mattermost server and logs a `200 OK` or `201 Created` response. - [ ] **Notification Tap & Route**: Tap the system notification and verify the host app launches/resumes, triggers the `onNotificationOpened` stream, and executes the designated navigation callback. - [ ] **Inline Reply Action**: Click "Reply" directly on the system notification. Type a reply, press send, and verify the native broadcast receiver intercepts the text, writes it to the local Room database, and sends it via HTTP to the Mattermost API. - [ ] **Notification Dismiss (Clear)**: Swipe away or dismiss a notification and verify the `NotificationDismissService` is triggered, clearing the corresponding notification records natively. - [ ] **Token Storage & Generation**: Ensure the generated token has the correct `android_rn-v2:` prefix and is saved securely in the device's native database/shared preferences.