macOS
The same WKWebView handler as iOS, hosted in AppKit.
macOS uses the same WKWebView and the same WKScriptMessageHandlerWithReply
as iOS — WebKit is shared across Apple platforms. The bridge implementation is
identical; only the hosting layer (AppKit instead of UIKit) and the platform tag
differ. Read the iOS page for the full handler; this page
only calls out the deltas.
Register the channel
import WebKit
let config = WKWebViewConfiguration()
config.userContentController.addScriptMessageHandler(
TodayWebViewBridge(),
contentWorld: .page,
name: "todayWebViewBridge"
)
let webView = WKWebView(frame: .zero, configuration: config)
// hosted by an NSViewController / NSWindow rather than a UIViewControllerThe TodayWebViewBridge handler — the track / headers / refreshToken /
establishSession dispatch, resolve-vs-reject rules, refreshToken coalescing,
and the WKHTTPCookieStore cookie mint — is byte-for-byte the iOS handler.
Share one type between the two targets.
Inject the platform tag
The only behavioural difference the web can observe is the platform value. Inject
'macos' at document start so the SDK does not have to fall back to user-agent
sniffing:
let tag = WKUserScript(
source: "window.__todayWebView = { platform: 'macos' };",
injectionTime: .atDocumentStart,
forMainFrameOnly: true
)
config.userContentController.addUserScript(tag)Without the tag the SDK still resolves macos from a non-touch Mac user-agent,
but the tag is the contract — do not rely on the heuristic. See
Environment detection.
Contract notes specific to macOS
- Shared handler. Do not fork the dispatch logic. The iOS and macOS targets
compile the same
WKScriptMessageHandlerWithReply; only injection and the tag differ. - Platform tag.
'macos'— the one signal that distinguishes this host from iOS, since both expose an identicalwebkit.messageHandlerschannel. client_plat. Enrichtrackevents withclient_plat: "macos", matching the cloud closed enum.- Main-frame + trusted surface.
headersandrefreshTokenare token-bearing — serve them to the main document frame only on an HTTPS trusted surface; a cross-origin sub-frame, or an untrusted / cleartext main-frame URL, MUST receiveundefined.refreshTokenshares theFeedWebHeaders.isTokenTrustedSurfacegate with theheadersbearer — the sharedwithCommonHandlers()wiring is identical to iOS. See Capabilities. establishSession. Mints theembed_bearercookie into the sharedWKHTTPCookieStoreexactly as on iOS — the bearer is never returned to JS. No macOS-specific delta.- Everything else (trust-domain
headers,refreshTokencoalescing, content world.page, navigation-injection limitation) is exactly as documented for iOS.