swiftship/internal/skills/data/always-watchos/watchos-patterns/SKILL.md
watchOS platform patterns: Digital Crown, Always On Display, battery constraints, WKApplicationDelegate lifecycle, wrist detection. Use when working on shared watchOS patterns related to watchos patterns.
npx skillsauth add abdullah4ai/apple-dev-docs watchos-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The Digital Crown is the primary input for value adjustment on Apple Watch.
// Basic rotation binding
@State private var crownValue: Double = 0
ScrollView {
content
}
.digitalCrownRotation($crownValue)
// Bounded rotation with haptics
@State private var volume: Double = 50
VolumeView(level: volume)
.digitalCrownRotation(
$volume,
from: 0,
through: 100,
by: 1,
sensitivity: .medium,
isContinuous: false,
isHapticFeedbackEnabled: true
)
.low — large physical rotation per unit (precise adjustment).medium — balanced (default for most use cases).high — small physical rotation per unit (fast scrolling)Only the focused view receives Crown events:
@FocusState private var crownFocused: Bool
VStack {
MetricView(value: crownValue)
}
.digitalCrownRotation($crownValue)
.focusable()
.focused($crownFocused)
.onAppear { crownFocused = true }
watchOS apps should support Always On Display when the wrist is lowered.
@Environment(\.isLuminanceReduced) var isLuminanceReduced
var body: some View {
VStack {
if isLuminanceReduced {
// Simplified, dim view — reduce updates and brightness
Text(Date.now, style: .time)
.font(AppTheme.Fonts.title)
} else {
// Full interactive view
DetailedContentView()
}
}
}
\.isLuminanceReduced to detect Always On stateTimelineView(.everyMinute) for clock-like updates in reduced modeisLuminanceReduced == trueTimelineView(.everyMinute) { context in
if isLuminanceReduced {
Text(context.date, style: .time)
} else {
LiveActivityView()
}
}
Apple Watch has very limited battery — every CPU/GPU cycle matters.
.animation only for state transitions)WKApplicationRefreshBackgroundTaskTimelineView over Timer for periodic updates.task for async work — it cancels automatically when the view disappearsfunc handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
for task in backgroundTasks {
switch task {
case let refreshTask as WKApplicationRefreshBackgroundTask:
// Update data
scheduleNextRefresh()
refreshTask.setTaskCompletedWithSnapshot(true)
default:
task.setTaskCompletedWithSnapshot(false)
}
}
}
import WatchKit
class AppDelegate: NSObject, WKApplicationDelegate {
func applicationDidFinishLaunching() {
// App launched
}
func applicationDidBecomeActive() {
// App is active and visible
}
func applicationWillResignActive() {
// App is about to go inactive
}
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
// Handle background tasks
}
}
@main
struct MyWatchApp: App {
@WKApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
@Environment(\.scenePhase) var scenePhase
.onChange(of: scenePhase) { _, phase in
switch phase {
case .active:
refreshData()
case .inactive:
saveState()
case .background:
scheduleBackgroundRefresh()
@unknown default:
break
}
}
For workouts or navigation that need to keep running:
import WatchKit
let session = WKExtendedRuntimeSession()
session.start()
// Session keeps app alive for the allowed duration
session.invalidate() // when done
// Watch is authenticated when on wrist and unlocked
// For sensitive features, confirm with LAContext
import LocalAuthentication
func requireAuth() async -> Bool {
let context = LAContext()
guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil) else {
return false
}
do {
return try await context.evaluatePolicy(
.deviceOwnerAuthentication,
localizedReason: "Access sensitive data"
)
} catch {
return false
}
}
isLuminanceReduced for Always On DisplayWKApplicationDelegate for lifecycle hooks and background taskstesting
Use for 3D games: racing, 3D sports, board games, marble maze, tower defense, bowling. SceneKit + SceneView architecture, 3D scene hierarchy, physics, game loop, primitives, materials, cameras, particles, audio.
documentation
Game UI patterns: SwiftUI HUD overlays on SpriteKit, menus (main/pause/game-over), virtual joystick/d-pad, score displays, health bars, tutorial onboarding.
tools
Download free game sprites/textures/3D models and generate procedural assets. Covers nw_download_asset tool, texture factories, sprite atlas organization, 3D model loading, and programmatic asset creation.
testing
Use for 2D games: arcade, puzzle, sports, ping pong, platformer, shooter, 2D racing. SpriteKit + SpriteView architecture, scene hierarchy, physics, game loop, audio, particles, game feel.