A Swift SDK for third-party macOS apps to display live activities, lock screen widgets, and notch experiences in Atoll via JSON-RPC over WebSocket.
Unlike AtollExtensionKit (which uses XPC and requires matching bundle IDs, making it not ideal for App Store), AtollRPC allows any application to communicate with Atoll, while being App Store safe.
- macOS 13.0+
- Swift 6.0+
- Atoll with RPC server enabled (v1.0.0+)
dependencies: [
.package(url: "https://github.com/Ebullioscopic/AtollRPC.git", from: "1.0.0")
]import AtollRPC
let client = AtollRPCClient.shared
// Connect to Atoll
try await client.connect()
// Request authorization
let authorized = try await client.requestAuthorization()
if authorized {
// Present a live activity
let activity = AtollLiveActivityDescriptor(
id: "my-timer",
title: "Timer",
subtitle: "25:00",
leadingIcon: .symbol(name: "timer"),
accentColor: .blue,
centerTextStyle: .inheritUser,
sneakPeekConfig: .standard(duration: 3.0),
sneakPeekTitle: "Timer",
sneakPeekSubtitle: "25 min"
)
try await client.presentLiveActivity(activity)
}| Method | Description |
|---|---|
connect() |
Connect to Atoll RPC server (auto-reconnects) |
disconnect() |
Disconnect from Atoll |
isConnected |
Check connection status |
| Method | Description |
|---|---|
requestAuthorization() |
Request user authorization |
checkAuthorization() |
Check current authorization status |
onAuthorizationChange(_:) |
Register callback for authorization changes |
onAtollLifecycleChange(emitCurrentState:_:) |
Register callback for Atoll active/idle lifecycle changes |
| Method | Description |
|---|---|
presentLiveActivity(_:) |
Show a live activity in the notch |
updateLiveActivity(_:) |
Update an existing live activity |
dismissLiveActivity(activityID:) |
Remove a live activity |
onActivityDismiss(activityID:callback:) |
Register dismissal callback |
| Method | Description |
|---|---|
presentLockScreenWidget(_:) |
Show a lock screen widget |
updateLockScreenWidget(_:) |
Update an existing widget |
dismissLockScreenWidget(widgetID:) |
Remove a widget |
onWidgetDismiss(widgetID:callback:) |
Register dismissal callback |
| Method | Description |
|---|---|
presentNotchExperience(_:) |
Show rich notch content |
updateNotchExperience(_:) |
Update an existing experience |
dismissNotchExperience(experienceID:) |
Remove an experience |
onNotchExperienceDismiss(experienceID:callback:) |
Register dismissal callback |
AtollRPC communicates with Atoll over JSON-RPC 2.0 on a WebSocket connection (ws://localhost:9020). The connection auto-reconnects with exponential backoff.
┌──────────────┐ JSON-RPC/WS ┌─────────────┐
│ Your App │◄───────────────►│ Atoll │
│ (AtollRPC) │ localhost:9020 │ (RPC Server)│
└──────────────┘ └─────────────┘
AtollRPC normalizes descriptor payloads before sending JSON-RPC requests to match Atoll's Codable decoding expectations.
AtollLiveActivityPriorityis serialized as string values:low,normal,high,critical.- Color channels (
red,green,blue,alpha) are serialized as numeric values. - Size dictionaries (
{ "width": ..., "height": ... }) are normalized for host compatibility. - Missing top-level descriptor metadata is normalized to
{}.
These guarantees are applied automatically by the SDK.
do {
try await client.presentLiveActivity(descriptor)
} catch let error as AtollRPCError {
switch error {
case .atollNotReachable:
print("Atoll is not running")
case .notAuthorized:
print("Please authorize in Atoll Settings")
case .invalidDescriptor(let reason):
print("Invalid descriptor: \(reason)")
default:
print(error.localizedDescription)
}
}## Lifecycle Notifications
Atoll publishes distributed lifecycle notifications when it launches and quits.
AtollRPC surfaces this through a callback API:
```swift
client.onAtollLifecycleChange { state in
switch state {
case .active:
// Atoll started and is ready
break
case .idle:
// Atoll quit; move your app to idle mode
break
}
}
```
MIT License — see LICENSE for details.
