No description
Find a file
2026-05-25 14:33:55 +09:00
.claude sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
agent-ops sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
agent-task sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
android initial commit: mattermost-push-plugin 2026-05-25 13:45:37 +09:00
example sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
ios initial commit: mattermost-push-plugin 2026-05-25 13:45:37 +09:00
lib initial commit: mattermost-push-plugin 2026-05-25 13:45:37 +09:00
macos initial commit: mattermost-push-plugin 2026-05-25 13:45:37 +09:00
test initial commit: mattermost-push-plugin 2026-05-25 13:45:37 +09:00
.aiexclude sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
.clineignore sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
.clinerules sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
.cursorignore sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
.cursorrules sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
.geminiignore sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
.gitignore sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
.metadata initial commit: mattermost-push-plugin 2026-05-25 13:45:37 +09:00
AGENTS.md sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
analysis_options.yaml initial commit: mattermost-push-plugin 2026-05-25 13:45:37 +09:00
CHANGELOG.md initial commit: mattermost-push-plugin 2026-05-25 13:45:37 +09:00
CLAUDE.md sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
GEMINI.md sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
LICENSE initial commit: mattermost-push-plugin 2026-05-25 13:45:37 +09:00
opencode.json sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00
pubspec.yaml initial commit: mattermost-push-plugin 2026-05-25 13:45:37 +09:00
README.md sync agent-ops, add documentation files and updates 2026-05-25 14:33:55 +09:00

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.

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:

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:

// 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.

// 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.


Test Harness Strategy

This repository keeps the plugin and its independent consumer test app together:

mattermost-push-plugin/
  lib/                    # Public Dart API and Flutter-facing behavior
  android/                # Android native plugin implementation
  test/                   # Dart unit tests for the plugin contract
  example/                # Thin Flutter app used as the integration test harness
    test/                 # Widget tests for the harness app
    integration_test/     # Device/emulator integration tests

The example/ app is the official place to validate plugin integration without coupling this package to any consuming product app. Consumer apps should only test their own wiring, such as calling initialization, storing credentials, and connecting navigation callbacks.

Recommended verification layers:

  1. flutter test from the repository root for Dart API behavior, event parsing, callback routing, and token formatting.
  2. flutter test from example/ for the test harness app.
  3. Android unit tests from example/android for native payload, storage, signing, and ACK behavior.
  4. flutter test integration_test from example/ on a device or emulator for plugin registration, method/event channels, notification-open routing, and manifest integration.
  5. Manual smoke tests for true Firebase FCM delivery and real Mattermost server ACK flows, because those depend on external infrastructure.

Recommended local commands:

flutter analyze
flutter test
(cd example && flutter analyze && flutter test)
(cd example/android && ./gradlew testDebugUnitTest)

Android Gradle tests require a configured Android SDK via ANDROID_HOME or example/android/local.properties.


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.