@haykmkrtich/react-native-patriot-native
Version:
[](https://badge.fury.io/js/%40haykmkrtich%2Freact-native-patriot-native) [](https://opensource.or
280 lines (210 loc) • 7.7 kB
Markdown
# Mobile App Integration Guide
## `@haykmkrtich/react-native-patriot-native`
A guide for integrating WearOS watch communication into your React Native mobile app.
---
## Prerequisites
| Requirement | Minimum |
|---|---|
| React Native | >= 0.77.0 (New Architecture / TurboModules) |
| Android API | 24+ (Android 7.0) |
| Java | 17+ |
| Hardware | Paired WearOS watch |
| Platform | Android only (iOS calls are rejected) |
---
## 1. Install the Package
```bash
npm install @haykmkrtich/react-native-patriot-native
# or
yarn add @haykmkrtich/react-native-patriot-native
```
No manual linking needed — TurboModule autolinking handles it. After installing, rebuild:
```bash
npx react-native clean
npx react-native run-android
```
---
## 2. Exported API
```typescript
import {
getConnectedDevices,
installWatchface,
isAppInstalledOnWatch,
sendMessageToWatch,
} from '@haykmkrtich/react-native-patriot-native';
```
| Function | Purpose |
|---|---|
| `getConnectedDevices()` | List all connected WearOS watches |
| `installWatchface(packageName, nodeId?)` | Trigger Play Store install on a specific or all watches |
| `isAppInstalledOnWatch(packageName)` | Check if an app/capability exists on watches |
| `sendMessageToWatch(nodeId, path, data?)` | Send a message to one specific watch |
---
## 3. TypeScript Types
```typescript
interface ConnectedDevice {
id: string; // Node ID — use this for sendMessageToWatch
displayName: string; // e.g. "Galaxy Watch 5"
isNearby: boolean; // Bluetooth proximity
type: string; // "watch"
platform: string; // "wearOS" | "unknown"
}
interface AppInstallStatus {
isInstalled: boolean; // true if found on any watch
installedOnNodes: string[]; // node IDs where it's installed
}
```
---
## 4. Common Workflows
### A. Discover Connected Watches
```typescript
const devices = await getConnectedDevices();
// Returns ConnectedDevice[] — empty array if nothing connected
```
### B. Install a Watchface on All Connected Watches
Omit the second argument to broadcast to every connected watch.
```typescript
await installWatchface('com.example.mywatchface');
// Opens Play Store install prompt on ALL connected watches
```
### C. Install a Watchface on a Specific Watch
Pass the `nodeId` from `getConnectedDevices()` to target one watch.
```typescript
const devices = await getConnectedDevices();
if (devices.length === 0) {
throw new Error('No watch connected');
}
// Target the first (or only) connected watch
const watch = devices[0];
await installWatchface('com.example.mywatchface', watch.id);
// Opens Play Store install prompt only on that watch
```
### D. Full Flow: Check Then Install on a Specific Watch
```typescript
async function installOnWatch(packageName: string): Promise<void> {
// Step 1: Get connected watches
const devices = await getConnectedDevices();
if (devices.length === 0) {
throw new Error('No watch connected');
}
const watch = devices[0];
console.log(`Found: ${watch.displayName}`);
// Step 2: (Optional) Check if already installed
const status = await isAppInstalledOnWatch(packageName);
if (status.isInstalled) {
console.log('Already installed, skipping');
return;
}
// Step 3: Install on that specific watch
await installWatchface(packageName, watch.id);
// Phone shows a toast, watch shows Play Store install prompt
}
await installOnWatch('com.example.mywatchface');
```
### E. Send a Custom Message to a Specific Watch
Use `sendMessageToWatch` to send arbitrary data to a watch node.
```typescript
const devices = await getConnectedDevices();
const watch = devices[0];
// path = routing key, data = optional string payload
await sendMessageToWatch(watch.id, '/sync-settings', JSON.stringify({
theme: 'dark',
}));
```
---
## 5. Error Handling
Every function rejects with an `Error` that has a `.code` property:
```typescript
try {
await installWatchface('com.example.watchface');
} catch (error: any) {
switch (error.code) {
case 'NO_NODES':
// No watches connected
break;
case 'INSTALL_FAILED':
// WearOS API rejected the install request
break;
}
}
```
| Error Code | Thrown By | Meaning |
|---|---|---|
| `NO_NODES` | `installWatchface` | No connected WearOS device |
| `INSTALL_FAILED` | `installWatchface` | Install request failed |
| `DETECTION_FAILED` | `getConnectedDevices` | WearOS API communication error |
| `CHECK_FAILED` | `isAppInstalledOnWatch` | Capability query failed |
| `MESSAGE_FAILED` | `sendMessageToWatch` | Message delivery failed |
Any call on iOS rejects with `"PatriotNative is only supported on Android"`.
---
## 6. Full Example: Install Screen Component
```typescript
import React, { useEffect, useState } from 'react';
import { View, Text, Button, Alert, Platform } from 'react-native';
import {
getConnectedDevices,
installWatchface,
isAppInstalledOnWatch,
ConnectedDevice,
} from '@haykmkrtich/react-native-patriot-native';
const WATCHFACE_PACKAGE = 'com.example.mywatchface';
export function WatchInstallScreen() {
const [watch, setWatch] = useState<ConnectedDevice | null>(null);
const [installed, setInstalled] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (Platform.OS !== 'android') return;
(async () => {
try {
const devices = await getConnectedDevices();
if (devices.length > 0) {
setWatch(devices[0]);
const status = await isAppInstalledOnWatch(WATCHFACE_PACKAGE);
setInstalled(status.isInstalled);
}
} catch (e) {
console.error(e);
} finally {
setLoading(false);
}
})();
}, []);
const handleInstall = async () => {
try {
// Target the specific connected watch by its node ID
await installWatchface(WATCHFACE_PACKAGE, watch!.id);
Alert.alert('Success', 'Install prompt sent to your watch');
} catch (error: any) {
if (error.code === 'NO_NODES') {
Alert.alert('Error', 'No watch connected');
} else {
Alert.alert('Error', 'Installation failed');
}
}
};
if (Platform.OS !== 'android') {
return <Text>WearOS features are only available on Android</Text>;
}
if (loading) return <Text>Detecting watch...</Text>;
if (!watch) return <Text>No watch connected</Text>;
return (
<View>
<Text>Connected: {watch.displayName}</Text>
<Text>Nearby: {watch.isNearby ? 'Yes' : 'No'}</Text>
<Text>Platform: {watch.platform}</Text>
{installed ? (
<Text>Watchface already installed</Text>
) : (
<Button title="Install Watchface" onPress={handleInstall} />
)}
</View>
);
}
```
---
## 7. Important Notes
1. **Android only** — always gate calls behind `Platform.OS === 'android'` or let the library's built-in check reject gracefully.
2. **`installWatchface` supports targeting** — pass a `nodeId` (from `getConnectedDevices()`) to install on a specific watch, or omit it to broadcast to all connected watches.
3. **Google Play pairing** — for production, the mobile app and WearOS app must share the same package name in Google Play Console. This is a Google requirement, not a library limitation.
4. **Deprecated API** — do NOT use `getConnectedWatchProperties()`. Use `getConnectedDevices()` instead.
5. **All functions are async** — every call returns a `Promise`. Always `await` or handle `.then()/.catch()`.
6. **Rebuild after install** — this is a native module. `npx react-native clean && npx react-native run-android` is required after adding the package. Hot reload alone won't pick it up.