RORK LABJP
PLAY — Google Play's target API level 36 requirement took effect yesterday, August 31. From today, new apps and updates must target Android 16VISIBILITY — Apps still on API 35 stay listed but disappear for users on newer Android versions. No error is raised; new installs simply fade, which makes the change easy to missEXTENSION — If you missed the deadline, an extension through November 1, 2026 can be requested in Play Console — best filed alongside a concrete migration planAPPLE — On the Apple side, the event lands September 9 and iOS 27 is reported to ship September 14. Testing generated apps on iOS 27 hardware before release week is time well spentEXPO — Expo released expo-paste-input on August 28, a native module that brings image, GIF, and sticker paste to React Native TextInputEAS — EAS Observe reached general availability on August 20, putting crash and performance monitoring on the same EAS platform as builds and updatesPLAY — Google Play's target API level 36 requirement took effect yesterday, August 31. From today, new apps and updates must target Android 16VISIBILITY — Apps still on API 35 stay listed but disappear for users on newer Android versions. No error is raised; new installs simply fade, which makes the change easy to missEXTENSION — If you missed the deadline, an extension through November 1, 2026 can be requested in Play Console — best filed alongside a concrete migration planAPPLE — On the Apple side, the event lands September 9 and iOS 27 is reported to ship September 14. Testing generated apps on iOS 27 hardware before release week is time well spentEXPO — Expo released expo-paste-input on August 28, a native module that brings image, GIF, and sticker paste to React Native TextInputEAS — EAS Observe reached general availability on August 20, putting crash and performance monitoring on the same EAS platform as builds and updates
Articles/Dev Tools
Dev Tools/2026-03-26Intermediate

Building Apple Watch Apps with Rork Max — A Complete watchOS Companion App Guide

Learn how to build Apple Watch (watchOS) companion apps using Rork Max. This guide covers SwiftUI-based WatchKit development, iPhone communication, HealthKit integration, and complication implementation.

Rork Max232Apple Watch3watchOS2SwiftUI64WatchKitHealthKit5companion app

Setup and context

Apple Watch is the world's most popular smartwatch, and it's used daily for health tracking, fitness monitoring, notifications, and more. However, traditional watchOS development has historically been challenging — setting up Xcode, configuring WatchKit Extensions, and designing iPhone-Watch communication required significant expertise.

With Rork Max, you can leverage AI to build SwiftUI-based Apple Watch companion apps efficiently. This guide walks you through everything from watchOS project setup to iPhone data synchronization, HealthKit integration, and complication (watch face widget) implementation.

Who this guide is for:

  • Developers who've learned the basics of Rork app development
  • Anyone looking to extend their iPhone app to Apple Watch
  • Indie developers seeking differentiation through wearable support

For a foundational understanding of Rork Max, check out the Rork Max Native Swift Complete Guide.

Understanding watchOS App Architecture

Apple Watch apps are built around two primary architectures.

Independent Apps: These run entirely on Apple Watch without requiring an iPhone. Supported since watchOS 6, users can download them directly from the App Store on their watch.

Companion Apps: These work alongside an iPhone app, enabling bidirectional data sync and remote control features. Most commercial apps use this approach for richer functionality.

Rork Max supports both architectures, but this guide focuses on the most practical setup: an iPhone app with a Watch companion app.

watchOS Project Directory Structure

When you add a watchOS target in Rork Max, the following structure is automatically generated:

MyApp/
├── MyApp/                    # iPhone app
│   ├── ContentView.swift
│   └── MyAppApp.swift
├── MyAppWatch/               # Watch app
│   ├── MyAppWatchApp.swift   # Watch app entry point
│   ├── ContentView.swift     # Watch main screen
│   ├── ComplicationController.swift
│   └── Assets.xcassets
└── Shared/                   # Code shared between iPhone and Watch
    ├── Models/
    └── Services/

Understanding this structure helps you write more precise prompts for Rork Max, resulting in higher quality generated code.

Creating a watchOS Project in Rork Max

Step 1: Initialize the Project

Create a new project in Rork Max and specify that you want a watchOS target included.

// Example Rork Max prompt:
// "Create a project with an iPhone app and Apple Watch companion app.
//  The Watch app should display a task list with completion toggles."
 
// Generated Watch app entry point
import SwiftUI
 
@main
struct MyAppWatchApp: App {
    var body: some Scene {
        WindowGroup {
            TaskListView()
        }
    }
}

Step 2: Build the Watch UI with SwiftUI

watchOS interfaces are built with SwiftUI. Since screen real estate is limited, prioritizing information is crucial.

// TaskListView.swift — Watch task list screen
import SwiftUI
 
struct TaskListView: View {
    @StateObject private var viewModel = TaskViewModel()
 
    var body: some View {
        NavigationStack {
            List {
                ForEach(viewModel.tasks) { task in
                    TaskRow(task: task) {
                        viewModel.toggleComplete(task)
                    }
                }
            }
            .navigationTitle("Tasks")
        }
        .onAppear {
            viewModel.fetchTasks()
        }
    }
}
 
struct TaskRow: View {
    let task: TaskItem
    let onToggle: () -> Void
 
    var body: some View {
        Button(action: onToggle) {
            HStack {
                Image(systemName: task.isCompleted
                    ? "checkmark.circle.fill"
                    : "circle")
                    .foregroundColor(task.isCompleted ? .green : .gray)
                Text(task.title)
                    .strikethrough(task.isCompleted)
                    .lineLimit(2)
            }
        }
    }
}
 
// Expected output:
// A task list displayed on Apple Watch where tapping
// toggles the completion state of each task

Key design considerations for Watch UI: keep tap targets large enough for comfortable interaction, and limit the amount of information displayed on each screen.

Implementing iPhone–Apple Watch Data Sync

The defining feature of a companion app is bidirectional data synchronization with the iPhone. Apple provides the WCSession (Watch Connectivity) framework for real-time messaging and background data transfers.

Real-Time Communication with WCSession

// Shared/Services/WatchConnectivityManager.swift
import WatchConnectivity
 
class WatchConnectivityManager: NSObject, ObservableObject, WCSessionDelegate {
    static let shared = WatchConnectivityManager()
    @Published var receivedTasks: [TaskItem] = []
 
    private override init() {
        super.init()
        if WCSession.isSupported() {
            let session = WCSession.default
            session.delegate = self
            session.activate()
        }
    }
 
    // Send tasks from iPhone to Watch
    func sendTasks(_ tasks: [TaskItem]) {
        guard WCSession.default.isReachable else { return }
 
        let data = tasks.map { [
            "id": $0.id.uuidString,
            "title": $0.title,
            "isCompleted": $0.isCompleted
        ] as [String: Any] }
 
        WCSession.default.sendMessage(
            ["tasks": data],
            replyHandler: nil
        ) { error in
            print("Send error: \(error.localizedDescription)")
        }
    }
 
    // Receive handler
    func session(
        _ session: WCSession,
        didReceiveMessage message: [String: Any]
    ) {
        if let tasksData = message["tasks"] as? [[String: Any]] {
            DispatchQueue.main.async {
                self.receivedTasks = tasksData.compactMap {
                    TaskItem(from: $0)
                }
            }
        }
    }
 
    // Required delegate methods
    func session(
        _ session: WCSession,
        activationDidCompleteWith state: WCSessionActivationState,
        error: Error?
    ) {}
 
    #if os(iOS)
    func sessionDidBecomeInactive(_ session: WCSession) {}
    func sessionDidDeactivate(_ session: WCSession) {
        WCSession.default.activate()
    }
    #endif
}
 
// Expected output:
// Tasks added or updated on iPhone sync to Watch in real time
// Tasks completed on Watch sync back to iPhone

Persistent Sync with Application Context

While sendMessage works great for real-time communication, messages won't be delivered if the Watch app is inactive. updateApplicationContext persists the latest data so the Watch can retrieve the current state whenever it wakes up.

// Background-compatible data sync
func syncTasksInBackground(_ tasks: [TaskItem]) {
    let context: [String: Any] = [
        "tasks": tasks.map { $0.toDictionary() },
        "lastUpdated": Date().timeIntervalSince1970
    ]
 
    do {
        try WCSession.default.updateApplicationContext(context)
    } catch {
        print("Context update error: \(error.localizedDescription)")
    }
}
 
// Receiving on the Watch side
func session(
    _ session: WCSession,
    didReceiveApplicationContext context: [String: Any]
) {
    if let tasksData = context["tasks"] as? [[String: Any]] {
        DispatchQueue.main.async {
            self.receivedTasks = tasksData.compactMap {
                TaskItem(from: $0)
            }
        }
    }
}

Integrating HealthKit Data into Your Watch App

One of Apple Watch's greatest strengths is real-time access to health data. By integrating HealthKit, you can build apps that leverage heart rate, step count, workout data, and more.

// Shared/Services/HealthKitManager.swift
import HealthKit
 
class HealthKitManager: ObservableObject {
    private let healthStore = HKHealthStore()
    @Published var todaySteps: Int = 0
    @Published var currentHeartRate: Double = 0
 
    // Request HealthKit authorization
    func requestAuthorization() async throws {
        let typesToRead: Set<HKObjectType> = [
            HKQuantityType(.stepCount),
            HKQuantityType(.heartRate),
            HKQuantityType(.activeEnergyBurned)
        ]
 
        try await healthStore.requestAuthorization(
            toShare: [],
            read: typesToRead
        )
    }
 
    // Fetch today's step count
    func fetchTodaySteps() async {
        let stepsType = HKQuantityType(.stepCount)
        let startOfDay = Calendar.current.startOfDay(for: Date())
        let predicate = HKQuery.predicateForSamples(
            withStart: startOfDay,
            end: Date(),
            options: .strictStartDate
        )
 
        let descriptor = HKStatisticsQueryDescriptor(
            predicate: .init(
                quantityType: stepsType,
                predicate: predicate
            ),
            options: .cumulativeSum
        )
 
        do {
            let result = try await descriptor.result(for: healthStore)
            let steps = result?.sumQuantity()?
                .doubleValue(for: .count()) ?? 0
            await MainActor.run {
                self.todaySteps = Int(steps)
            }
        } catch {
            print("Step count fetch error: \(error.localizedDescription)")
        }
    }
}
 
// Expected output:
// The Watch app displays "Today's Steps: 8,432" on screen

Apps using HealthKit require a clear privacy policy during App Store review. For detailed review preparation, the App Store Review Complete Checklist for Rork Apps is an invaluable resource.

Building Complications (Watch Face Widgets)

Complications place small widgets directly on the watch face, letting users see key information at a glance without opening the app. This significantly boosts user engagement and daily active usage.

// ComplicationProvider.swift
import WidgetKit
import SwiftUI
 
struct TaskComplicationEntry: TimelineEntry {
    let date: Date
    let remainingTasks: Int
    let nextTask: String?
}
 
struct TaskComplicationProvider: TimelineProvider {
    func placeholder(in context: Context) -> TaskComplicationEntry {
        TaskComplicationEntry(
            date: Date(),
            remainingTasks: 3,
            nextTask: "Sample task"
        )
    }
 
    func getSnapshot(
        in context: Context,
        completion: @escaping (TaskComplicationEntry) -> Void
    ) {
        let entry = TaskComplicationEntry(
            date: Date(),
            remainingTasks: 5,
            nextTask: "Submit proposal"
        )
        completion(entry)
    }
 
    func getTimeline(
        in context: Context,
        completion: @escaping (Timeline<TaskComplicationEntry>) -> Void
    ) {
        // Fetch actual task data and build timeline
        let tasks = TaskStorage.shared.incompleteTasks
        let entry = TaskComplicationEntry(
            date: Date(),
            remainingTasks: tasks.count,
            nextTask: tasks.first?.title
        )
 
        let nextUpdate = Calendar.current.date(
            byAdding: .minute, value: 30, to: Date()
        )!
        let timeline = Timeline(
            entries: [entry],
            policy: .after(nextUpdate)
        )
        completion(timeline)
    }
}
 
// Complication display view
struct TaskComplicationView: View {
    let entry: TaskComplicationEntry
 
    var body: some View {
        VStack(alignment: .leading) {
            Text("\(entry.remainingTasks)")
                .font(.title2)
                .fontWeight(.bold)
            Text("Tasks left")
                .font(.caption2)
                .foregroundColor(.secondary)
        }
        .containerBackground(.fill.tertiary, for: .widget)
    }
}
 
// Expected output:
// A complication on the watch face showing "5 Tasks left"

Summary

Here's a recap of the key points for building Apple Watch companion apps with Rork Max:

  • watchOS app structure: Design around three layers — iPhone app, Watch target, and Shared code
  • SwiftUI-based Watch UI: Keep interfaces simple and optimized for the small screen
  • WCSession data sync: Use sendMessage for real-time updates and updateApplicationContext for persistent state
  • HealthKit integration: Leverage step counts, heart rate, and workout data to add genuine value
  • Complications: Embed your app into the watch face for maximum daily engagement

Adding Apple Watch support is a powerful differentiator on the App Store. While many indie developers haven't yet ventured into watchOS, now is the perfect time to use Rork Max's AI code generation to move quickly and capture this opportunity.

For step-by-step instructions on publishing your Watch app, see Rork Max 2-Click App Store Publishing Guide.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Dev Tools2026-06-18
Building Apple Watch Complications with WidgetKit in a Rork Max App
A concrete walkthrough for adding watchOS complications and Smart Stack support to a SwiftUI app generated by Rork Max, covering target setup, cross-process data sharing, and timeline design.
Dev Tools2026-03-20
Build a Complete Fitness Tracker with Rork Max — HealthKit, Apple Watch, and Widget Integration
A comprehensive tutorial on building a fitness tracker app with Rork Max that integrates HealthKit, Apple Watch, and Home Screen widgets. From architecture design to App Store submission.
Dev Tools2026-07-18
The Generated Screen That Quietly Jams at AX5 and in German — Putting Layout Resilience Checks on Rork Max SwiftUI
A record of running every Rork Max generated SwiftUI screen through pseudolocalization and the largest text size to find exactly where it jams. Covers when to reach for ViewThatFits, ScaledMetric and layoutPriority, plus the snapshot checks that catch regressions every time you regenerate.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →