- 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
6.9 KiB
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.swiftcurrently registers only the legacynexo_messagingmethod channel and implementsgetPlatformVersion. - Dart expects native notification and action channels:
com.tokilabs.nexo.messaging/notificationsandcom.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/macosis 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:
- Register the expected EventChannel and MethodChannel in the macOS plugin.
- Implement a debug-only local injection path compatible with
debugSendNativeEvent. - Map notification
userInfofields into the DartNotificationOpenedEventcontract. - Build and run the test host with local placeholder signing.
- 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.entitlementsandRelease.entitlementsas 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:
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_urlandchannel_idare present,root_idis empty andis_crt_enabledis false, so Dart callsonNavigateToChannel. - Thread fixture:
server_urlandroot_idare present andis_crt_enabledis true, so Dart callsonNavigateToThread.
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.jsonapps/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
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.