watchOS App Development for Apple Watch
A client ordered a workout tracker for Apple Watch with data sync to iPhone. The first version lost up to 5% of records because WCSession.sendMessage worked only when the app was active, and WKExtendedRuntimeSession wasn't configured. We redesigned the architecture: used HKWorkoutSession for unlimited background and transferUserInfo for guaranteed delivery. Data loss dropped to 0.01%. The app now handles up to 1000 workouts per day without failures.
A watchOS app is a separate target with its own lifecycle, limited resources (512 MB RAM on Series 4, 1 GB on Series 9), and specific patterns. We use SwiftUI, Combine, and async/await for a reactive architecture. Average development time is 2–4 weeks for a comprehensive solution. When setting up code signing for watchOS, separate provisioning profiles are required — a common mistake for beginners. We strongly recommend testing complications on real devices, as the simulator doesn't reflect actual performance and power constraints.
Each project starts with a deep analysis of use cases: will the Watch work standalone or as a companion app? This determines the sync mechanism. Among our projects are fitness, meditation, and smart home apps, each with a unique architecture. We specialize in watchOS for over 5 years and have shipped 20+ apps to the App Store. Order a turnkey watchOS app development — from idea to App Store publication.
How to Ensure Data Delivery During Sync?
WCSession is the communication channel between apps on iPhone and Watch. Not between devices, but between apps. Three data transfer mechanisms:
| Mechanism |
When it works |
Speed |
Delivery guarantee |
Typical use |
| sendMessage |
Both apps active |
Instant |
No (if Watch goes to sleep) |
Commands, data requests in foreground |
| updateApplicationContext |
Any state (incl. background) |
On next wake |
Yes, overwrites |
Current state (workout, settings) |
| transferUserInfo |
Any state |
In order, with delay |
Yes, queued |
Event logs, transactions |
WatchConnectivity via sendMessage is 10x faster than updateApplicationContext, but requires the app to be active. For background delivery — only updateApplicationContext or transferUserInfo.
WCSession.default.sendMessage(["action": "fetchData"], replyHandler: { reply in
// Response from iPhone
}, errorHandler: { error in
// Handle error (Watch unavailable)
})
try WCSession.default.updateApplicationContext(["lastSync": Date().timeIntervalSince1970])
If the app is active on both devices — use sendMessage for immediate response. For state sync in background (e.g., current workout metrics) — updateApplicationContext. For event queues — transferUserInfo. Checking WCSession.default.isReachable is asynchronous: always handle errorHandler.
Why Do Complications Drain the Battery?
A common mistake is updating the timeline too often or fetching network data. Optimal solution: update timeline once per hour, use HealthKit for local data. To save power, follow Apple's recommendations on update frequency limits.
Complications are elements on the watch face. ClockKit (deprecated) → now WidgetKit, similar to iOS. ComplicationConfiguration via WidgetConfiguration — the same API as iOS widgets. Families: .circularSmall, .modularSmall, .modularLarge, .utilitarianSmall, .utilitarianLarge, .graphicCorner, .graphicBezel, .graphicCircular, .graphicRectangular, .graphicExtraLarge. Timeline in Complication works like iOS WidgetKit: TimelineProvider, pre-filled TimelineEntry. The watch knows what to show for the next few hours — saving battery. CLKComplicationDataSource.getPrivacyBehavior — what to show on the locked watch face. hideOnLockScreen — hide data, show empty complication.
Background Modes on watchOS
WKExtendedRuntimeSession — up to 60 minutes of background work for specific scenarios:
-
workout — unlimited time with active WorkoutSession
-
selfCare — meditation, breathing exercises (up to 10 minutes after screen off)
-
alarm — alarm (requires user permission)
-
sleepTracking — sleep tracking (overnight)
For workout tracking: HKWorkoutSession + HKLiveWorkoutBuilder — official API. Without HKWorkoutSession, the system aggressively kills background processes. Network requests in background via URLSession with background configuration are not supported — data only via iPhone (WatchConnectivity) or on next foreground launch.
Technical detail: setting up WKExtendedRuntimeSession
To start, you must call start() and specify the type. Important: the session requires explicit invalidate() after completion, otherwise it will run until timeout. Example:
let session = WKExtendedRuntimeSession()
session.start(with: .workout)
// ...
session.invalidate()
UX Considerations
The screen is small: Series 4+ — 44mm (368×448pt retina). Minimum touch target — 44pt. List rows without complex hierarchy — preferred navigation. Digital Crown — scroll content, zoom in MapKit, input values via Stepper or custom Picker styles. onLongPressGesture — works, but requires 0.8 seconds by default — often accidental triggers. Haptic feedback via WKInterfaceDevice.current().play(.click) — an important UX element where visual feedback is limited.
What's Included in watchOS App Development
- Architecture design: shared code with iOS, dedicated watchOS target.
- WatchConnectivity setup: choose the right mechanism for your scenario.
- Complication implementation: support for 5+ families, timeline configuration.
- Integration with HealthKit / CoreMotion / other sensors.
- Testing on real devices (Series 4, Series 9, Ultra).
- App Store preparation: provisioning profiles, code signing, icons.
- Documentation on sync and background tasks.
- 1-month warranty support after publication.
Timeline and Cost
Full-featured watchOS app with WatchConnectivity and complications — 1–2 weeks. Simple companion app (no own logic) — 3–5 days. Cost is calculated after requirements analysis. Order a free consultation — we'll assess your project. Contact us for details.
We have been in mobile development for over 5 years and have shipped more than 20 apps to the App Store. Our solutions work reliably — we guarantee compliance with App Store Review Guidelines and performance recommendations.
Get a free engineer consultation — contact us for a detailed project assessment.
Development of Widgets, App Clips, and Live Activities: Entry Points Outside the App
We understand that users see your app not only when they open it. A widget on the home screen, a live score in Dynamic Island, a mini experience without installation — these are separate entry points that we implement within platform constraints. Over 5 years, we have developed more than 50 extensions for mobile apps, from simple informational widgets to App Clips with payment scenarios, saving clients up to 30% of time on repeat visits.
What entry points should you consider for your app?
WidgetKit Widget Development: Why You Can't Just "Add a Widget"
WidgetKit works via a Timeline Provider — the widget doesn't stay in memory continuously; it requests data snapshots in advance. The most common mistake: developers try to show real-time data via URLSession directly from getTimeline(). Apple doesn't prohibit this, but with aggressive updates, the system starts throttling requests, and the widget gets stuck on outdated data.
The correct approach: the main app updates data via WidgetCenter.shared.reloadTimelines(ofKind:) — after receiving a push notification or when the user returns to the foreground. The widget reads data from a shared App Group container using UserDefaults(suiteName:) or file storage. No direct network requests in the provider in production.
In the latest iOS versions, AppIntent-based interactive widgets have emerged — buttons and toggles directly on the widget without opening the app. This is implemented via Button(intent:) in the SwiftUI widget layout. Only works for simple actions; complex logic should transition to the app via widgetURL.
How Live Activities Change User Experience?
Live Activities are a mechanism for displaying live data on the Lock Screen and Dynamic Island (iPhone 14 Pro+). They are launched via ActivityKit, updated via push notifications of type liveactivity with a payload up to 4KB.
Architecturally, it's a separate SwiftUI target with two views: compact (Dynamic Island) and expanded (Lock Screen). Data is passed via ActivityAttributes — a strictly typed structure. The dynamic part is ContentState, while the static part (unchanged during the activity) is directly in ActivityAttributes.
A typical issue: Live Activity doesn't update on the device even though push is sent. The reason is that the app doesn't have permission for background push or apns-push-type is set incorrectly. In production, you need apns-push-type: liveactivity and a token from activity.pushToken. According to Apple documentation, without a correct push token, the Activity won't receive updates.
When to Use App Clips vs Instant Apps?
App Clips (iOS) and Instant Apps (Android) solve a similar problem — provide functionality without installing the full app. But the implementation is fundamentally different.
App Clip is a separate target in Xcode, max 15MB, launched via NFC tag, QR code, Safari Smart App Banner, or a link in Messages. Data access is limited: no Keychain sharing with the main app without explicit setup, no access to HealthKit, no push notifications (only ephemeral). The App Clip Card is configured in App Store Connect, and metadata errors are a common reason for rejection.
Android Instant Apps are built on a modular architecture: the app is divided into feature modules, each of which can be downloaded separately via Play Feature Delivery. An Instant App is a feature module with <dist:module dist:instant="true">. The limitation is no more than 15MB total for instant delivery.
Comparison shows that App Clips win in payment scenarios due to Apple Pay integration — conversion is 20% higher compared to Instant Apps in similar cases. Instant Apps are better suited for game demos and services requiring quick access via Google Search.
| Parameter |
App Clips |
Instant Apps |
| Max size |
15 MB |
15 MB |
| Launch triggers |
NFC, QR, URL, Safari |
URL, Google Search, Play Store |
| Shared Keychain |
Via App Group |
Via SharedPreferences/Keystore |
| Recommended scenario |
Payment, boarding, demo |
Game demo, one-time services |
What Does Our Work Include?
-
Audit of current architecture: determine which entry points your app needs — widget, Live Activity, App Clip, Instant App.
-
Prototyping: visual model of the extension following platform guidelines (Apple HIG, Material Design).
-
Development: implementation in Swift (iOS) or Kotlin (Android) using WidgetKit, ActivityKit, App Clip API, Play Feature Delivery.
-
Integration: setting up App Group, Keychain sharing, push certificates, provisioning profiles.
-
Testing: on real devices (iPhone, iPad, Android) and simulators. For Live Activities, test via
xcrun simctl push.
-
Publication: preparing metadata for App Store Connect (App Clip Card) and Google Play Console (Instant App configuration).
-
Documentation and training: architecture description, widget update instructions, push notification troubleshooting.
How Does Our Development Process Work?
-
Analytics: which app features are truly needed outside the app, and which mechanism fits. Widget for forecast — WidgetKit. Real-time delivery tracking — Live Activity. Payment at checkout — App Clip.
-
Design: choosing stack, data update schemes (Timeline, push), UI layouts for compact and expanded views.
-
Implementation: writing code in Swift/Kotlin, configuring App Group, push certificates, test schemes.
-
Testing: each extension is tested in isolation. WidgetKit rendering is verified via Xcode Widget Gallery, Live Activities via simulator with forced push.
-
Deployment: publishing to stores, monitoring metrics (update frequency, App Clip launch count).
Estimated Timeframes
| Extension Type |
Timeframe (business days) |
| Simple informational widget |
5 to 10 |
| Interactive widget (AppIntent) |
10 to 15 |
| Live Activity with push |
10 to 20 |
| App Clip with payment |
20 to 30 |
| Instant App (Android) |
15 to 25 |
Cost is calculated individually after audit. An estimate is provided within 2 business days.
What Are Typical Mistakes in Extension Development?
-
Too frequent widget updates — leads to throttling and empty state. We recommend an interval of at least 15 minutes (see Apple Human Interface Guidelines in WidgetKit documentation).
-
Ignoring shared container — the widget doesn't see data because it uses its own
UserDefaults instead of App Group.
-
Lack of fallback for Live Activities — if push isn't delivered, the user sees outdated data. A periodic polling mechanism via
Activity.update with pushType: nil is needed.
-
Incorrect App Clip Card metadata — a common reason for rejection in App Store Review. For example, incorrect URL or missing icon.
Contact us to assess which extension fits your app. Order an audit of current entry points — we'll find non-obvious scenarios for widgets and App Clips. Get an engineer consultation on architecture today.