- Add macos notification smoke evidence template and test guide - Add Fixtures for open_channel and open_thread json - Update roadmaps for messaging runtime phase and macos notification milestone - Update flutter-test and messaging_flutter READMEs
143 lines
6.9 KiB
Markdown
143 lines
6.9 KiB
Markdown
# macOS Notification Test Guide
|
|
|
|
Last verified: 2026-06-02
|
|
|
|
This guide fixes the preflight contract for macOS notification work before
|
|
Apple signing, a macOS test device, or real OS notification UI evidence is
|
|
available.
|
|
|
|
Do not commit real Apple, APNs, Firebase, service-account, device-token, auth
|
|
token, private endpoint, Team ID, signing identity, provisioning, notarization,
|
|
or private host values into tracked docs. Use placeholders in examples and keep
|
|
credential files in approved local or secret-store locations.
|
|
|
|
## Current Repository State
|
|
|
|
- The macOS plugin is still a scaffold. `packages/messaging_flutter/macos/Classes/NexoMessagingPlugin.swift`
|
|
currently registers only the legacy `nexo_messaging` method channel and
|
|
implements `getPlatformVersion`.
|
|
- Dart expects native notification and action channels:
|
|
`com.tokilabs.nexo.messaging/notifications` and
|
|
`com.tokilabs.nexo.messaging/notification_actions`.
|
|
- The minimum macOS bridge is therefore not implemented yet. Until it exists,
|
|
local routing can only be tested through Dart unit tests or a future debug
|
|
injection bridge.
|
|
- `apps/flutter-test/macos` is a host scaffold. It carries sandbox
|
|
entitlements, but no notification entitlement, signing team, provisioning
|
|
profile, hardened runtime, or notarization value is tracked in this repo.
|
|
- Local routing fixtures live under `apps/flutter-test/macos/Fixtures/*.json`.
|
|
|
|
The first useful macOS smoke target is:
|
|
|
|
1. Register the expected EventChannel and MethodChannel in the macOS plugin.
|
|
2. Implement a debug-only local injection path compatible with
|
|
`debugSendNativeEvent`.
|
|
3. Map notification `userInfo` fields into the Dart
|
|
`NotificationOpenedEvent` contract.
|
|
4. Build and run the test host with local placeholder signing.
|
|
5. Collect permission, display, click/open routing, lifecycle, and known ACK,
|
|
dismiss, and inline reply gap evidence.
|
|
|
|
## Minimum Bridge Contract
|
|
|
|
The Dart SDK expects the macOS native side to preserve these channel names:
|
|
|
|
| Channel | Name | Direction | Minimum macOS behavior |
|
|
|---|---|---|---|
|
|
| EventChannel | `com.tokilabs.nexo.messaging/notifications` | native to Dart | Emit codec-safe maps for notification, open, token, clear, session, and future action-failure events. |
|
|
| MethodChannel | `com.tokilabs.nexo.messaging/notification_actions` | Dart to native | Accept SDK action methods used by Dart without crashing the host app. |
|
|
| Legacy MethodChannel | `nexo_messaging` | Dart/test compatibility | Keep `getPlatformVersion` until the generated example compatibility path is intentionally removed. |
|
|
|
|
Minimum methods for the action channel:
|
|
|
|
| Method | Minimum preflight result | Production expectation |
|
|
|---|---|---|
|
|
| `debugSendNativeEvent` | Validate the argument is a map and emit it on the EventChannel. | Debug/test-only injection path. |
|
|
| `saveDeviceToken` | Accept and store or no-op a formatted token string without logging secrets. | Store the macOS server-registration token once the platform token source is chosen. |
|
|
| `getDeviceToken` | Return the last stored formatted token or null. | Return the current formatted macOS server-registration token. |
|
|
| `setAuthToken` | Validate required string arguments and no-op. | Persist token for ACK/reply work only after storage rules are designed. |
|
|
| `clearAuthToken` | Validate `serverUrl` and no-op. | Clear persisted token for the server. |
|
|
| `setSigningKey` | Validate required string arguments and no-op without persistence. | Persist the signing key only after secure storage rules are designed. |
|
|
|
|
Fallback boundaries:
|
|
|
|
- Missing bridge methods should return `FlutterMethodNotImplemented`, not a
|
|
successful placeholder.
|
|
- Token, auth, signing-key, ACK, dismiss, and inline reply persistence are not
|
|
implied by this preflight milestone.
|
|
- Real notification permission prompts and visible notification display belong
|
|
to `macOS 알림 테스트` unless a small debug bridge task explicitly implements
|
|
them first.
|
|
|
|
## Host Placeholder Criteria
|
|
|
|
Tracked macOS host files must stay generic:
|
|
|
|
- Keep real signing Team ID, identity, provisioning profile, notarization
|
|
profile, Apple ID, and private host values out of tracked files.
|
|
- Keep `apps/flutter-test/macos/Runner/DebugProfile.entitlements` and
|
|
`Release.entitlements` as placeholder entitlements until a smoke run requires
|
|
a specific capability.
|
|
- Add notification capability through Xcode or local build settings for a smoke
|
|
run, then record sanitized evidence instead of committing private signing
|
|
state.
|
|
- Do not add real credential files under `apps/flutter-test/macos`.
|
|
|
|
Expected local placeholder checks:
|
|
|
|
```sh
|
|
codesign -d --entitlements :- build/macos/Build/Products/Debug/flutter_test.app
|
|
```
|
|
|
|
Look for sandbox values and any locally added notification-related capability.
|
|
Record private identifiers as placeholders in evidence.
|
|
|
|
## Payload Mapping
|
|
|
|
macOS notification `userInfo` maps into Dart using the same stable keys as the
|
|
Android and iOS contracts:
|
|
|
|
| `userInfo` key | Dart event field | Notes |
|
|
|---|---|---|
|
|
| `type` | `type` | Use `message` for visible message notifications and `opened` for direct open events. |
|
|
| `server_url` | `server_url` | Required before host navigation callbacks can run. |
|
|
| `server_id` | `server_id` | Diagnostic and future server URL fallback input. |
|
|
| `channel_id` | `channel_id` | Drives `onNavigateToChannel` when thread routing is not selected. |
|
|
| `root_id` | `root_id` | Drives `onNavigateToThread` when CRT is enabled. |
|
|
| `is_crt_enabled` | `is_crt_enabled` | Accept boolean `true`, string `"true"`, or string `"1"`. |
|
|
| `ack_id` | `ack_id` | Preserve for future ACK evidence; do not invent ACK behavior. |
|
|
| `post_id` | `post_id` | Preserve for notification identity and future ACK/display evidence. |
|
|
| `userInteraction` | `userInteraction` | Set to `true` when a click/open path caused the event. |
|
|
|
|
Routing expectation:
|
|
|
|
- Channel fixture: `server_url` and `channel_id` are present, `root_id` is empty
|
|
and `is_crt_enabled` is false, so Dart calls `onNavigateToChannel`.
|
|
- Thread fixture: `server_url` and `root_id` are present and
|
|
`is_crt_enabled` is true, so Dart calls `onNavigateToThread`.
|
|
|
|
## Local Fixtures
|
|
|
|
Use the fixture files as sanitized payloads for a future debug injection method
|
|
or for manual `userInfo` construction during smoke testing:
|
|
|
|
- `apps/flutter-test/macos/Fixtures/open_channel.json`
|
|
- `apps/flutter-test/macos/Fixtures/open_thread.json`
|
|
|
|
The fixtures intentionally use `https://example.invalid` and smoke IDs. Replace
|
|
private runtime values only in local run notes or sanitized evidence.
|
|
|
|
## Evidence
|
|
|
|
Use [`macos-notification-smoke-evidence-template.md`](macos-notification-smoke-evidence-template.md)
|
|
for macOS runs. Preflight evidence should explicitly separate:
|
|
|
|
- permission state
|
|
- visible display state
|
|
- click/open routing result
|
|
- app lifecycle state
|
|
- ACK, dismiss, and inline reply implementation gaps
|
|
|
|
Until the bridge and real OS smoke exist, a valid preflight result may be
|
|
"not implemented yet" with a concrete follow-up plan, rather than a failed
|
|
runtime claim.
|