diff --git a/README.md b/README.md
index 70162de..7a029a3 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,14 @@
# react-native-wear-connectivity
-Allows you to connect React Native Mobile apps with WearOS.
+Allows you to connect React Native Mobile apps with WearOS and Apple Watch.
| Sending Voice Message (enable audio) | Sending Text |
| ----------- | ----------- |
| | |
-**Note**: Refer to [react-native-watch-connectivity][2] for Apple Watch development.
+Apple Watch support is provided through [react-native-watch-connectivity][2].
+See the [Apple Watch Setup](docs/applewatch-setup.md) guide for details on Xcode
+configuration, entitlements, and pairing instructions.
[1]: https://wearos.google.com
[2]: https://github.com/mtford90/react-native-watch-connectivity
@@ -14,6 +16,7 @@ Allows you to connect React Native Mobile apps with WearOS.
# Table of Contents
- [Installation](#installation)
+- [Apple Watch Setup](#apple-watch-setup)
- [React Native API Documentation](#react-native-api-documentation)
- [Jetpack Compose API Documentation](#jetpack-compose-api-documentation)
- [How to run the example](#how-to-run-the-example)
@@ -69,6 +72,11 @@ Add the following entry to your `android/app/src/main/AndroidManifest.xml` (full
```
+## Apple Watch Setup
+
+See [docs/applewatch-setup.md](docs/applewatch-setup.md) for instructions on
+setting up Xcode, required entitlements, and pairing a watch app.
+
## React Native API Documentation
The example of implementation available in the [CounterScreen](example/src/CounterScreen/index.android.tsx).
diff --git a/docs/applewatch-setup.md b/docs/applewatch-setup.md
new file mode 100644
index 0000000..c9a9604
--- /dev/null
+++ b/docs/applewatch-setup.md
@@ -0,0 +1,24 @@
+# Apple Watch Setup
+
+This library integrates with [`react-native-watch-connectivity`](https://github.com/mtford90/react-native-watch-connectivity)
+to enable communication between an iOS app and its paired Apple Watch.
+
+## Xcode configuration
+
+1. Open the iOS project in Xcode.
+2. Select **File > New > Target…** and add a **Watch App for iOS App**.
+3. In **Signing & Capabilities** for both the iOS app and the WatchKit extension:
+ - Add **App Groups** and use the same identifier (e.g. `group.com.example.watch`).
+ - Enable **Background Modes** and tick **Uses Bluetooth LE accessories**.
+
+## Entitlements
+
+Both the iOS application and the WatchKit extension must include the chosen
+`com.apple.security.application-groups` entry in their entitlements files so
+that the two apps can communicate.
+
+## Pairing with a watch
+
+1. Pair an Apple Watch with the iPhone or simulator using the **Watch** app.
+2. In Xcode choose a run destination that includes both the phone and watch.
+3. Build and run; Xcode installs the watch app and establishes the pairing.
diff --git a/package.json b/package.json
index 86167e0..8bc1be1 100644
--- a/package.json
+++ b/package.json
@@ -53,6 +53,9 @@
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
+ "dependencies": {
+ "react-native-watch-connectivity": "*"
+ },
"devDependencies": {
"@commitlint/config-conventional": "^17.0.2",
"@react-native/eslint-config": "^0.72.2",
diff --git a/src/applewatch/AppleWatchConnector.ts b/src/applewatch/AppleWatchConnector.ts
new file mode 100644
index 0000000..284bea1
--- /dev/null
+++ b/src/applewatch/AppleWatchConnector.ts
@@ -0,0 +1,47 @@
+import Watch, { watchEvents } from 'react-native-watch-connectivity';
+import type {
+ Payload,
+ ReplyCallback,
+ ErrorCallback,
+} from '../NativeWearConnectivity';
+
+/**
+ * Connector responsible for activating the WatchConnectivity session and
+ * forwarding messages between the iOS app and the paired Apple Watch.
+ */
+class AppleWatchConnector {
+ private activated = false;
+
+ /**
+ * Ensures that the underlying WCSession is activated before any
+ * communication attempts.
+ */
+ activateSession() {
+ if (this.activated) {
+ return;
+ }
+ try {
+ Watch.activateSession();
+ this.activated = true;
+ } catch (err) {
+ console.warn('Failed to activate Apple Watch session', err);
+ }
+ }
+
+ /**
+ * Sends a message to the paired Apple Watch device.
+ */
+ sendMessage(
+ message: Payload,
+ cb?: ReplyCallback,
+ errCb?: ErrorCallback
+ ) {
+ this.activateSession();
+ Watch.sendMessage(message, cb, errCb);
+ }
+}
+
+const appleWatchConnector = new AppleWatchConnector();
+
+export { appleWatchConnector, watchEvents as appleWatchEvents };
+export default appleWatchConnector;
diff --git a/src/applewatch/react-native-watch-connectivity.d.ts b/src/applewatch/react-native-watch-connectivity.d.ts
new file mode 100644
index 0000000..10b3209
--- /dev/null
+++ b/src/applewatch/react-native-watch-connectivity.d.ts
@@ -0,0 +1,26 @@
+declare module 'react-native-watch-connectivity' {
+ import { EmitterSubscription } from 'react-native';
+
+ export interface WatchConnectivity {
+ activateSession(): void;
+ sendMessage(
+ message: any,
+ reply?: (data: any) => void,
+ error?: (err: any) => void
+ ): void;
+ }
+
+ export const watchEvents: {
+ addListener: (
+ event: string,
+ listener: (...args: any[]) => void
+ ) => EmitterSubscription;
+ on: (
+ event: string,
+ listener: (...args: any[]) => void
+ ) => EmitterSubscription;
+ };
+
+ const Watch: WatchConnectivity;
+ export default Watch;
+}
diff --git a/src/messages.ts b/src/messages.ts
index 5f763de..bcd5e70 100644
--- a/src/messages.ts
+++ b/src/messages.ts
@@ -1,7 +1,7 @@
import { Platform } from 'react-native';
import type { SendMessage, Payload } from './NativeWearConnectivity';
import { WearConnectivity } from './index';
-import { LIBRARY_NAME, IOS_NOT_SUPPORTED_WARNING } from './constants';
+import { appleWatchConnector } from './applewatch/AppleWatchConnector';
const UNHANDLED_CALLBACK =
'The sendMessage function was called without a callback function. ';
@@ -17,7 +17,7 @@ const defaultErrCb = (err: string) => {
console.warn(UNHANDLED_CALLBACK + UNHANDLED_CALLBACK_ERROR, err);
};
-const sendMessage: SendMessage = (message, cb, errCb) => {
+const sendMessageAndroid: SendMessage = (message, cb, errCb) => {
const json: Payload = { ...message, event: 'message' };
const callbackWithDefault = cb ?? defaultReplyCb;
const errCbWithDefault = errCb ?? defaultErrCb;
@@ -28,12 +28,20 @@ const sendMessage: SendMessage = (message, cb, errCb) => {
);
};
-const sendMessageMock: SendMessage = () =>
- console.warn(LIBRARY_NAME + 'message' + IOS_NOT_SUPPORTED_WARNING);
+const sendMessageIOS: SendMessage = (message, cb, errCb) => {
+ const json: Payload = { ...message, event: 'message' };
+ const callbackWithDefault = cb ?? defaultReplyCb;
+ const errCbWithDefault = errCb ?? defaultErrCb;
+ return appleWatchConnector.sendMessage(
+ json,
+ callbackWithDefault,
+ errCbWithDefault
+ );
+};
-let sendMessageExport: SendMessage = sendMessageMock;
-if (Platform.OS !== 'ios') {
- sendMessageExport = sendMessage;
+let sendMessageExport: SendMessage = sendMessageAndroid;
+if (Platform.OS === 'ios') {
+ sendMessageExport = sendMessageIOS;
}
export { sendMessageExport as sendMessage };
diff --git a/src/subscriptions.ts b/src/subscriptions.ts
index 1a2aae0..e142d7f 100644
--- a/src/subscriptions.ts
+++ b/src/subscriptions.ts
@@ -1,8 +1,8 @@
import { NativeModules, NativeEventEmitter, Platform } from 'react-native';
import type { AddListener, WatchEvents } from './types';
-import { LIBRARY_NAME, IOS_NOT_SUPPORTED_WARNING } from './constants';
+import { appleWatchEvents } from './applewatch/AppleWatchConnector';
-const _addListener: AddListener = (event, cb) => {
+const androidAddListener: AddListener = (event, cb) => {
const nativeWatchEventEmitter = new NativeEventEmitter(
NativeModules.AndroidWearCommunication
);
@@ -21,20 +21,33 @@ const _addListener: AddListener = (event, cb) => {
return () => sub.remove();
};
-const _addListenerMock: AddListener = () => {
- console.warn(LIBRARY_NAME + 'watchEvents' + IOS_NOT_SUPPORTED_WARNING);
- return () => {};
-};
+const iosAddListener: AddListener = (event, cb) => {
+ if (!event) {
+ throw new Error('Must pass event');
+ }
-let watchEvents: WatchEvents = {
- addListener: _addListenerMock,
- on: _addListenerMock,
+ switch (event) {
+ case 'message':
+ break;
+ default:
+ throw new Error(`Unknown watch event "${event}"`);
+ }
+
+ const sub = appleWatchEvents.addListener(event, cb);
+ return () => sub.remove();
};
-if (Platform.OS !== 'ios') {
+let watchEvents: WatchEvents;
+
+if (Platform.OS === 'ios') {
+ watchEvents = {
+ addListener: iosAddListener,
+ on: iosAddListener,
+ };
+} else {
watchEvents = {
- addListener: _addListener,
- on: _addListener,
+ addListener: androidAddListener,
+ on: androidAddListener,
};
}