Documentation Index Fetch the complete documentation index at: https://mintlify.com/EvanBacon/expo-apple-targets/llms.txt
Use this file to discover all available pages before exploring further.
Expo Apple Targets supports both Apple Watch companion apps and watch face complications (widgets).
Apple Watch supports two target types:
Watch App Full watchOS app that runs alongside your iOS app
Watch Widget Watch face complications using WidgetKit
Watch App
A companion watchOS app that pairs with your iOS app.
Extension point
Property Value Type watchExtension Point None (standalone watchOS app) Product Type com.apple.product-type.applicationFrameworks All watchOS frameworks Embedded Swift Yes
Creating a watch app
Configure the watch app:
/** @type {import('@bacons/apple-targets/app.plugin').Config} */
module . exports = {
type: "watch" ,
deploymentTarget: "10.0" , // watchOS version
};
Watch app architecture
Watch apps use SwiftUI for the interface:
import SwiftUI
@main
struct MyWatchApp : App {
var body: some Scene {
WindowGroup {
ContentView ()
}
}
}
struct ContentView : View {
var body: some View {
VStack {
Text ( "Hello, Watch!" )
Button ( "Action" ) {
// Handle button tap
}
}
}
}
Communication with iOS app
Use WatchConnectivity to communicate between iOS and watchOS:
import WatchConnectivity
class WatchConnectivityManager : NSObject , WCSessionDelegate {
static let shared = WatchConnectivityManager ()
func setup () {
if WCSession. isSupported () {
let session = WCSession. default
session. delegate = self
session. activate ()
}
}
func sendMessage ( _ message : [ String : Any ]) {
WCSession. default . sendMessage (message, replyHandler : nil )
}
// Delegate methods
func session ( _ session : WCSession, activationDidCompleteWith activationState : WCSessionActivationState, error : Error ? ) {
// Handle activation
}
func session ( _ session : WCSession, didReceiveMessage message : [ String : Any ]) {
// Handle received message
}
}
From React Native, you’ll need to create a native module to use WatchConnectivity.
Watch face complications using WidgetKit.
Extension point
Property Value Type watch-widgetExtension Point com.apple.widgetkit-extension (watch)Frameworks WidgetKit, SwiftUIApp Groups Enabled by default
npx create-target watch-widget
Configure the complication:
/** @type {import('@bacons/apple-targets/app.plugin').Config} */
module . exports = {
type: "watch-widget" ,
colors: {
$accent: "#FF6B6B" ,
},
entitlements: {
"com.apple.security.application-groups" : [ "group.com.myapp.data" ],
},
};
import WidgetKit
import SwiftUI
struct MyWatchWidget : Widget {
let kind: String = "MyWatchWidget"
var body: some WidgetConfiguration {
StaticConfiguration ( kind : kind, provider : Provider ()) { entry in
MyWatchWidgetView ( entry : entry)
}
. configurationDisplayName ( "My Widget" )
. description ( "Shows app data" )
. supportedFamilies ([
. accessoryCircular ,
. accessoryRectangular ,
. accessoryInline
])
}
}
struct Provider : TimelineProvider {
func placeholder ( in context : Context) -> SimpleEntry {
SimpleEntry ( date : Date (), value : "0" )
}
func getSnapshot ( in context : Context, completion : @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry ( date : Date (), value : "42" )
completion (entry)
}
func getTimeline ( in context : Context, completion : @escaping (Timeline<Entry>) -> ()) {
// Read from App Groups
let defaults = UserDefaults ( suiteName : "group.com.myapp.data" )
let value = defaults ? . string ( forKey : "counter" ) ?? "0"
let entry = SimpleEntry ( date : Date (), value : value)
let timeline = Timeline ( entries : [entry], policy : . never )
completion (timeline)
}
}
struct SimpleEntry : TimelineEntry {
let date: Date
let value: String
}
struct MyWatchWidgetView : View {
var entry: Provider.Entry
var body: some View {
Text (entry. value )
. font (. system (. title , design : . rounded ))
}
}
Complication families
Watch widgets support different complication families:
Family Description .accessoryCircularCircular complication .accessoryRectangularRectangular complication .accessoryInlineInline text complication .accessoryCornerCorner complication
Sharing data with watch
Use App Groups to share data:
import { ExtensionStorage } from "@bacons/apple-targets" ;
const storage = new ExtensionStorage ( "group.com.myapp.data" );
storage . set ( "counter" , 42 );
ExtensionStorage . reloadWidget (); // Works for watch widgets too
Access from watch:
let defaults = UserDefaults ( suiteName : "group.com.myapp.data" )
let counter = defaults ? . integer ( forKey : "counter" ) ?? 0
Deployment target
Set the minimum watchOS version:
module . exports = {
type: "watch" ,
deploymentTarget: "10.0" , // watchOS 10.0+
};
Best practices
Optimize for small screens
Use large, readable text
Minimize the number of UI elements
Support Digital Crown scrolling
Test on different watch sizes
Show the most important info first
Use clear icons and symbols
Support all complication families
Update complications when data changes
Minimize background updates
Use efficient timeline updates
Avoid unnecessary network requests
Cache data locally
Learn more
Watch apps guide Detailed watch app guide
Sharing data Share data with watch
Widget targets iOS widget documentation
Apple documentation Official watchOS documentation