A generic JSON sync bridge between a Capacitor iOS app and a native watchOS app using WatchConnectivity and App Groups.
npm install capacitor-watch-bridge> A modern, generic JSON bridge between a Capacitor iOS app and a native watchOS app
> using WatchConnectivity and App Groups β built with Capacitor 7 & Swift 5.9.
---
π GitHub: github.com/kisimediaDE/capacitor-watch-bridge
---
- π What you get
- π¦ Installation
* 1. Install the Capacitor plugin
* 2. Add WatchBridgeKit to your watchOS target (SPM)
- βοΈ Configuration
- π§ Usage
- π§© Example App
- API
* syncJson(...)
* isAvailable()
* Interfaces
+ SyncJsonOptions
+ IsAvailableResult
- π§° Requirements
- π§βπ» Author
- πͺ² Known Limitations
- π License
---
This package contains two Swift targets:
1. WatchBridgePlugin β the Capacitor iOS plugin (used in your iPhone app)
2. WatchBridgeKit β a tiny watchOS helper framework that:
- wraps WCSession on the watch
- reads the App Group ID from WatchBridgeAppGroupId in the watch Info.plist
- exposes @Published properties latestKey and latestJson for your UI
High-level features:
β
Sync arbitrary JSON from iOS β watchOS via updateApplicationContext()
β
Store the same data in a shared App Group for offline access
β
Gracefully degrades if no Watch is paired or the app isnβt installed
β
Swift Package Manager and CocoaPods support
β
Drop-in Capacitor 7 plugin β zero additional configuration on web
---
``bash`
npm install capacitor-watch-bridge
npx cap sync ios
Capacitor will add the iOS plugin (CapacitorWatchBridge) to your Podfile automatically.
In Xcode:
1. File β Add Packagesβ¦
2. Enter the repo URL:
`text`
https://github.com/kisimediaDE/capacitor-watch-bridge.git
3. Add the following products:
- "CapacitorWatchBridge" β iOS app target (if you also use SPM directly)
- "WatchBridgeKit" β WatchKit Extension target
The repo already ships a Package.swift with:
`swift`
products: [
.library(name: "CapacitorWatchBridge", targets: ["WatchBridgePlugin"]),
.library(name: "WatchBridgeKit", targets: ["WatchBridgeKit"]),
]
---
1. Configure your App Group (iOS + watchOS)
Create an App Group, e.g.:
`text`
group.de.kisimedia.watchbridge
Then enable this group under Signing & Capabilities β App Groups for:
- the iOS App target
- the WatchKit Extension target
2. Capacitor config (iOS app)
`typescript`
// capacitor.config.ts / capacitor.config.json
export default {
// ...
plugins: {
WatchBridge: {
appGroupId: 'group.de.kisimedia.watchbridge',
},
},
};
On iOS the plugin:
1. First tries plugins.WatchBridge.appGroupId from capacitor.config.
2. Falls back to the Info.plist key WatchBridgeAppGroupId (see below).
3. Info.plist key (watchOS and optional iOS fallback)
_WatchKit Extension Info.plist_
`xml`
This is what WatchBridgeKit uses to know which App Group to write into.
_Optional: iOS App Info.plist_
If you donβt want to configure the App Group in capacitor.config, you can also
set the same key in your iOS appβs Info.plist and skip the plugin config:
`xml`
---
1. From Capacitor (iOS / web)
`typescript
import { WatchBridge } from 'capacitor-watch-bridge';
await WatchBridge.syncJson({
key: 'debugText',
json: JSON.stringify({ text: 'Hello from Capacitor!' }),
});
const info = await WatchBridge.isAvailable();
console.log('Watch status:', info);
`
2. On watchOS with WatchBridgeKit
_SwiftUI example_
`swift
import SwiftUI
import WatchBridgeKit
@main
struct MyWatchApp: App {
@StateObject private var session = WatchBridgeSession.shared
var body: some Scene {
WindowGroup {
VStack(spacing: 8) {
Text("WatchBridge Debug")
.font(.headline)
Text("Key: \(session.latestKey)")
.font(.footnote)
Text("JSON:")
.font(.caption2)
ScrollView {
Text(session.latestJson)
.font(.caption2)
.multilineTextAlignment(.leading)
}
}
.padding()
}
}
}
`
WatchBridgeSession will:
- activate the WCSession once
- apply any previously known applicationContext on startup
- listen for new contexts via didReceiveApplicationContext
- optionally write the JSON into your App Group UserDefaults(suiteName:)
_Non-SwiftUI / manual access_
You can also use it without SwiftUI:
`swift
import WatchBridgeKit
let session = WatchBridgeSession.shared
// Access session.latestKey / session.latestJson
// or subscribe via Combine: session.$latestJson.sink { ... }
`
---
A minimal Capacitor 7 + Vite demo is included under example-app/.
It ships a full working setup:
- iOS app with the Capacitor plugin
- watchOS app using WatchBridgeKit
- both targets sharing the App Group
- a small HTML UI that shows connectivity state & sends JSON to the watch
| iPhone Demo | Watch Demo |
| ------------------------------------------------------------------ | ---------------------------------------------------------------------- |
|
|
|
To run it:
`bash`
cd example-app
npm install
npx cap sync ios
npx cap open ios
The example already uses:
- App Group: group.de.kisimedia.watchbridge
- WatchBridgeKit in the WatchKit Extension
- WatchBridgeSession as shown above
---
* syncJson(...)
* isAvailable()
* Interfaces
Public API of the WatchBridge plugin.
`typescript`
syncJson(options: SyncJsonOptions) => Promise
Stores a JSON string in the configured App Group and tries
to sync it to the watchOS app via WatchConnectivity.
If no watch is paired or available, the data is still written
to the App Group and the Promise resolves without error.
| Param | Type |
| ------------- | ----------------------------------------------------------- |
| options | SyncJsonOptions |
--------------------
`typescript`
isAvailable() => Promise
Returns information about WatchConnectivity availability:
- if it is supported
- if a watch is paired
- if the watchOS app is installed
Returns: Promise<IsAvailableResult>
--------------------
#### SyncJsonOptions
| Prop | Type | Description |
| ---------- | ------------------- | ---------------------------------------------------------------------------------------- |
| key | string | Key under which the data is stored in the shared App Group. Example: "items" or "tasks". |
| json | string | JSON string provided by the app. The plugin does not validate or parse this string. |
#### IsAvailableResult
| Prop | Type | Description |
| ------------------ | -------------------- | ------------------------------------------------------------------ |
| supported | boolean | True if WatchConnectivity (WCSession) is supported on this device. |
| paired | boolean | True if an Apple Watch is paired with the iPhone. |
| appInstalled` | boolean | True if the watchOS companion app is installed. |
---
- iOS 14+
- watchOS 10+ (for WatchBridgeKit as defined in Package.swift)
- Capacitor 7.0+
- Swift 5.9+
- Xcode 15+
---
Made with β€οΈ by Kisimedia
for open-source Capacitor developers everywhere.
---
- Android not implemented (stub only)
- Plugin does not validate JSON syntax
- No bi-directional sync yet (watch β iPhone planned for v2)
---
MIT Β© Kisimedia.de
See LICENSE for details.