Skip to content

Commit c30aed7

Browse files
committed
feat: add @capgo/capacitor-watch plugin for Apple Watch communication with comprehensive documentation
1 parent 5a7aa9d commit c30aed7

File tree

5 files changed

+706
-0
lines changed

5 files changed

+706
-0
lines changed

public/icons/plugins/watch.svg

Lines changed: 6 additions & 0 deletions
Loading

src/config/plugins.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import FolderIcon from 'astro-heroicons/mini/Folder.astro'
5454
import SunIcon from 'astro-heroicons/mini/Sun.astro'
5555
import StarIcon from 'astro-heroicons/mini/Star.astro'
5656
import FolderOpenIcon from 'astro-heroicons/mini/FolderOpen.astro'
57+
import ClockIcon from 'astro-heroicons/mini/Clock.astro'
5758

5859
export interface Action {
5960
icon?: any
@@ -837,4 +838,12 @@ export const actions = [
837838
title: 'File Picker',
838839
icon: FolderOpenIcon,
839840
},
841+
{
842+
name: '@capgo/capacitor-watch',
843+
author: 'github.com/Cap-go',
844+
description: 'Apple Watch communication with bidirectional messaging between iPhone and watchOS apps',
845+
href: 'https://github.com/Cap-go/capacitor-watch/',
846+
title: 'Watch',
847+
icon: ClockIcon,
848+
},
840849
]
Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
---
2+
title: Getting Started
3+
description: Learn how to install and configure the Capacitor Watch plugin for bidirectional communication between iPhone and Apple Watch.
4+
sidebar:
5+
order: 2
6+
---
7+
8+
import { Tabs, TabItem, Steps } from '@astrojs/starlight/components';
9+
import { PackageManagers } from 'starlight-package-managers'
10+
11+
<Steps>
12+
1. **Install the package**
13+
<PackageManagers pkg="@capgo/capacitor-watch" pkgManagers={['npm', 'pnpm', 'yarn', 'bun']} />
14+
15+
2. **Sync with native projects**
16+
<PackageManagers type="exec" pkg="cap" args="sync" pkgManagers={['npm', 'pnpm', 'yarn', 'bun']} />
17+
18+
3. **Configure the plugin**
19+
20+
**Basic Usage Example:**
21+
```typescript
22+
import { CapgoWatch } from '@capgo/capacitor-watch';
23+
24+
// Check watch connectivity status
25+
const info = await CapgoWatch.getInfo();
26+
console.log('Watch paired:', info.isPaired);
27+
console.log('Watch reachable:', info.isReachable);
28+
29+
// Listen for messages from watch
30+
await CapgoWatch.addListener('messageReceived', (event) => {
31+
console.log('Message from watch:', event.message);
32+
});
33+
```
34+
35+
**Send a Message to Watch:**
36+
```typescript
37+
// Check if watch is reachable first
38+
const info = await CapgoWatch.getInfo();
39+
if (info.isReachable) {
40+
await CapgoWatch.sendMessage({
41+
data: { action: 'refresh', timestamp: Date.now() }
42+
});
43+
}
44+
```
45+
46+
<Tabs>
47+
<TabItem label="iOS">
48+
**Required iOS Setup:**
49+
50+
1. Add the WatchConnectivity capability to your iOS app in Xcode
51+
2. Create a watchOS app target in your Xcode project
52+
3. Implement WatchConnectivity in your watchOS app (see Watch App Implementation below)
53+
54+
The plugin automatically activates the WCSession when the plugin loads.
55+
</TabItem>
56+
<TabItem label="Android">
57+
Apple Watch is only supported on iOS. On Android, all methods will reject with "Apple Watch is only supported on iOS" error. The `getInfo()` method returns `isSupported: false`.
58+
</TabItem>
59+
</Tabs>
60+
61+
4. **Handle messages that require a reply**
62+
```typescript
63+
// Listen for messages that need a response
64+
await CapgoWatch.addListener('messageReceivedWithReply', async (event) => {
65+
console.log('Request from watch:', event.message);
66+
67+
// Process the request
68+
const result = await processWatchRequest(event.message);
69+
70+
// Send reply back to watch
71+
await CapgoWatch.replyToMessage({
72+
callbackId: event.callbackId,
73+
data: { result }
74+
});
75+
});
76+
```
77+
78+
5. **Sync application state**
79+
```typescript
80+
// Update application context (latest value only)
81+
await CapgoWatch.updateApplicationContext({
82+
context: {
83+
theme: 'dark',
84+
userId: '123',
85+
lastSync: Date.now()
86+
}
87+
});
88+
89+
// Listen for context updates from watch
90+
await CapgoWatch.addListener('applicationContextReceived', (event) => {
91+
console.log('Context from watch:', event.context);
92+
});
93+
```
94+
95+
6. **Transfer user info reliably**
96+
```typescript
97+
// Queue data for reliable delivery (even when watch is offline)
98+
await CapgoWatch.transferUserInfo({
99+
userInfo: {
100+
recordId: '456',
101+
action: 'created',
102+
data: { name: 'Item 1' }
103+
}
104+
});
105+
106+
// Listen for user info transfers
107+
await CapgoWatch.addListener('userInfoReceived', (event) => {
108+
console.log('User info from watch:', event.userInfo);
109+
});
110+
```
111+
112+
7. **Monitor connectivity**
113+
```typescript
114+
// Track reachability changes
115+
await CapgoWatch.addListener('reachabilityChanged', (event) => {
116+
console.log('Watch reachable:', event.isReachable);
117+
if (event.isReachable) {
118+
// Watch is now available for interactive messaging
119+
}
120+
});
121+
122+
// Track session activation state
123+
await CapgoWatch.addListener('activationStateChanged', (event) => {
124+
// 0 = notActivated, 1 = inactive, 2 = activated
125+
console.log('Session state:', event.state);
126+
});
127+
```
128+
</Steps>
129+
130+
## Watch App Implementation
131+
132+
Your watchOS app needs to implement WatchConnectivity. Here's a SwiftUI example:
133+
134+
```swift
135+
import SwiftUI
136+
import WatchConnectivity
137+
138+
@main
139+
struct MyWatchApp: App {
140+
init() {
141+
WatchViewModel.shared.activate()
142+
}
143+
144+
var body: some Scene {
145+
WindowGroup {
146+
ContentView()
147+
}
148+
}
149+
}
150+
151+
class WatchViewModel: NSObject, ObservableObject, WCSessionDelegate {
152+
static let shared = WatchViewModel()
153+
154+
@Published var lastMessage: [String: Any] = [:]
155+
156+
func activate() {
157+
guard WCSession.isSupported() else { return }
158+
WCSession.default.delegate = self
159+
WCSession.default.activate()
160+
}
161+
162+
// Send message to iPhone
163+
func sendToPhone(_ data: [String: Any]) {
164+
guard WCSession.default.isReachable else {
165+
print("iPhone not reachable")
166+
return
167+
}
168+
WCSession.default.sendMessage(data, replyHandler: nil)
169+
}
170+
171+
// Send message with reply
172+
func sendToPhoneWithReply(_ data: [String: Any], completion: @escaping ([String: Any]) -> Void) {
173+
guard WCSession.default.isReachable else { return }
174+
WCSession.default.sendMessage(data, replyHandler: completion)
175+
}
176+
177+
// Receive message from iPhone
178+
func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
179+
DispatchQueue.main.async {
180+
self.lastMessage = message
181+
}
182+
}
183+
184+
// Receive application context
185+
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String: Any]) {
186+
DispatchQueue.main.async {
187+
self.lastMessage = applicationContext
188+
}
189+
}
190+
191+
// Required delegate methods
192+
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
193+
print("Watch session activated: \(activationState.rawValue)")
194+
}
195+
}
196+
```
197+
198+
## API Reference
199+
200+
### Methods
201+
202+
#### `sendMessage(options: SendMessageOptions)`
203+
Send an interactive message to the watch. Requires watch to be reachable.
204+
205+
**Parameters:**
206+
- `data`: Object - The data to send to the watch
207+
208+
#### `updateApplicationContext(options: UpdateContextOptions)`
209+
Update application context. Only latest value is kept.
210+
211+
**Parameters:**
212+
- `context`: Object - The context data to sync
213+
214+
#### `transferUserInfo(options: TransferUserInfoOptions)`
215+
Queue user info for reliable delivery.
216+
217+
**Parameters:**
218+
- `userInfo`: Object - The user info to transfer
219+
220+
#### `replyToMessage(options: ReplyMessageOptions)`
221+
Reply to a message that requested a response.
222+
223+
**Parameters:**
224+
- `callbackId`: string - The callback ID from messageReceivedWithReply event
225+
- `data`: Object - The reply data
226+
227+
#### `getInfo()`
228+
Get watch connectivity status.
229+
230+
**Returns:** `WatchInfo` object with:
231+
- `isSupported`: boolean - Whether WatchConnectivity is available
232+
- `isPaired`: boolean - Whether a watch is paired
233+
- `isWatchAppInstalled`: boolean - Whether watch app is installed
234+
- `isReachable`: boolean - Whether watch is reachable
235+
- `activationState`: number - Session state (0/1/2)
236+
237+
#### `getPluginVersion()`
238+
Get the native plugin version.
239+
240+
### Events
241+
242+
| Event | Description |
243+
|-------|-------------|
244+
| `messageReceived` | Simple message from watch |
245+
| `messageReceivedWithReply` | Message expecting a reply (includes callbackId) |
246+
| `applicationContextReceived` | Context update from watch |
247+
| `userInfoReceived` | User info transfer from watch |
248+
| `reachabilityChanged` | Watch connectivity changed |
249+
| `activationStateChanged` | Session activation state changed |
250+
251+
## Communication Patterns
252+
253+
### Immediate Messaging (`sendMessage`)
254+
- Requires watch to be reachable
255+
- Best for interactive, time-sensitive communication
256+
- Fails immediately if watch is not available
257+
258+
### Application Context (`updateApplicationContext`)
259+
- Latest value only - previous values are overwritten
260+
- Best for syncing current app state
261+
- Delivered when watch becomes available
262+
263+
### User Info Transfer (`transferUserInfo`)
264+
- Queued and delivered in order
265+
- Best for important data that must be delivered
266+
- Works even when watch is temporarily unreachable
267+
268+
## Platform Notes
269+
270+
### iOS
271+
- Requires iOS 15.0 or later
272+
- Uses WatchConnectivity framework
273+
- Session automatically activates on plugin load
274+
- Supports background delivery for context and user info
275+
276+
### Android
277+
- Not supported (Apple Watch is iOS-only)
278+
- All methods reject with appropriate error
279+
- `getInfo()` returns `isSupported: false`
280+
281+
### Web
282+
- Not supported
283+
- All methods reject with unavailable error
284+
- `getInfo()` returns `isSupported: false`
285+
286+
## Common Use Cases
287+
288+
1. **Data Sync**: Keep watch and phone data in sync
289+
2. **Remote Control**: Control phone features from watch
290+
3. **Notifications**: Send custom notifications to watch
291+
4. **Health Data**: Share fitness and health metrics
292+
5. **Media Control**: Control music playback from watch
293+
6. **Smart Home**: Control devices from your wrist
294+
295+
## Troubleshooting
296+
297+
**Watch not reachable:**
298+
- Ensure watch is within Bluetooth range
299+
- Check that both apps are running
300+
- Verify WCSession is activated on both sides
301+
302+
**Messages not received:**
303+
- Check that listeners are registered before sending
304+
- Verify the watch app implements WCSessionDelegate
305+
- Use `transferUserInfo` for guaranteed delivery
306+
307+
**Session not activating:**
308+
- Ensure WatchConnectivity capability is added in Xcode
309+
- Check that watch app has the companion bundle ID
310+
- Verify both apps target compatible OS versions
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
title: "@capgo/capacitor-watch"
3+
description: Capacitor plugin for bidirectional communication between iPhone and Apple Watch using WatchConnectivity framework.
4+
tableOfContents: false
5+
next: false
6+
prev: false
7+
sidebar:
8+
order: 1
9+
label: "Introduction"
10+
hero:
11+
tagline: Enable seamless two-way communication between your iPhone app and Apple Watch companion app.
12+
image:
13+
file: ~public/icons/plugins/watch.svg
14+
actions:
15+
- text: Get started
16+
link: /docs/plugins/watch/getting-started/
17+
icon: right-arrow
18+
variant: primary
19+
- text: Github
20+
link: https://github.com/Cap-go/capacitor-watch/
21+
icon: external
22+
variant: minimal
23+
---
24+
25+
import { Card, CardGrid } from '@astrojs/starlight/components';
26+
27+
<CardGrid stagger>
28+
<Card title="Bidirectional Messaging" icon="rocket">
29+
Send and receive messages between iPhone and Apple Watch in real-time
30+
</Card>
31+
<Card title="Background Transfers" icon="setting">
32+
Queue reliable data transfers that deliver even when the watch is offline
33+
</Card>
34+
<Card title="Application Context" icon="laptop">
35+
Sync app state with latest-value-only semantics for efficient updates
36+
</Card>
37+
<Card title="Comprehensive Documentation" icon="open-book">
38+
Check the [Documentation](/docs/plugins/watch/getting-started/) to master the plugin in just a few minutes.
39+
</Card>
40+
</CardGrid>

0 commit comments

Comments
 (0)