Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

documentation, lint and typescript errors #9

Merged
merged 11 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 69 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,92 @@
# react-native-wear-connectivity

Enstablish a two-way connection with wearOS
- Create a [Wear OS][1] app using react-native
- Connect two react-native apps (Wear OS and Android phone)
- **Both apps are written in react-native**

[1]: https://wearos.google.com

## Installation

```sh
yarn add react-native-wear-connectivity
```

or

```sh
npm install react-native-wear-connectivity
```

## Usage

```js
import { multiply } from 'react-native-wear-connectivity';
import { sendMessage, watchEvents } from 'react-native-wear-connectivity';

function CounterScreen() {
const [count, setCount] = React.useState(0);

// listen for messages from wearOS/phone
useEffect(() => {
const unsubscribe = watchEvents.on('message', () => {
setCount((prevCount) => prevCount + 1);
});

return () => {
unsubscribe();
};
}, []);

// send a message from/to wearOS
const onSuccess = (result) => console.log(result);
const onError = (error) => console.log(error);

const sendMessageToWear = () => {
const json = { text: 'hello', event: 'message' };
sendMessage(json, onSuccess, onError);
};

return (
<View>
<Text>{count}</Text>
<Button title="increase counter" onPress={sendMessageToWear} />
</View>
);
}
```

## How to create a WearOS app using react-native

- Create a copy of your react-native project. For Example:

```bash
cp my-react-native-project my-react-native-wear-project
```

- Add the following line to the new project AndroidManifest (file ):

// ...

const result = await multiply(3, 7);
```xml
<!--the file is my-react-native-wear-project/android/app/src/main/AndroidManifest.xml-->
<uses-feature android:name="android.hardware.type.watch" />
```

- Pair the Android emulator with the Wear OS emulator (instructions [here][21]). I suggest using the emulator [WearOS Large round][22], as the other emulator has issues with the react-native dev menu.
- Start the metro server on port 8082 with `yarn start --port=8082`
- Open the `react native dev menu` and change the bundle location to `your-ip:8082` (for ex. `192.168.18.2:8082`).
- Repeat the same steps for the Android Phone Emulator and use a different port (for ex. 8081).
- **Important Note**: Before publishing to Google Play, make sure that both apps are signed using the same key (instructions [here][20])

You can now build the app with `yarn android`. JS fast-refresh and the other metro functionalities work without problem (no need to build for JS changes).

[20]: https://reactnative.dev/docs/next/signed-apk-android
[21]: https://developer.android.com/training/wearables/get-started/connect-phone
[22]: https://gist.github.com/assets/24992535/f6cb9f84-dc50-492b-963d-6d9e9396f451 'wear os large round'

## Contributing

See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.

## License

MIT

---

Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
3 changes: 1 addition & 2 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from 'react';
import LoginScreen from './LoginScreen';
import { Platform } from 'react-native';
import { default as CounterScreenAndroid } from './CounterScreen/index.android';
import { default as CounterScreenIos } from './CounterScreen/index.ios';

const App = () => {
const CounterScreen =
Platform.OS == 'ios' ? CounterScreenIos : CounterScreenAndroid;
Platform.OS === 'ios' ? CounterScreenIos : CounterScreenAndroid;
return <CounterScreen />;
};

Expand Down
9 changes: 6 additions & 3 deletions example/src/CounterScreen/index.android.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, { useEffect } from 'react';
import { View, StyleSheet, Text, Button } from 'react-native';
import { sendMessage, watchEvents } from '../../../src/index';
import type { ReplyCallback, ErrorCallback } from '../../../src/index';
import { sendMessage, watchEvents } from 'react-native-wear-connectivity';
import type {
ReplyCallback,
ErrorCallback,
} from 'react-native-wear-connectivity';

function CounterScreen() {
const [disabled, setDisabled] = React.useState(false);
const [count, setCount] = React.useState(0);

useEffect(() => {
const unsubscribe = watchEvents.on('message', (message: Function) => {
const unsubscribe = watchEvents.on('message', () => {
setCount((prevCount) => prevCount + 1);
});

Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,13 @@
"@types/jest": "^28.1.2",
"@types/react": "~17.0.21",
"@types/react-native": "0.70.0",
"@typescript-eslint/eslint-plugin": "latest",
"@typescript-eslint/parser": "latest",
"commitlint": "^17.0.2",
"del-cli": "^5.0.0",
"eslint": "^8.4.1",
"eslint": "latest",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest": "^27.6.3",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^28.1.1",
"pod-install": "^0.1.0",
Expand Down
12 changes: 1 addition & 11 deletions src/NativeWearConnectivity.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';

// Messages
export type Payload = Object;
export type ReplyCallback = (reply: Payload) => void;
export type ErrorCallback = (err: string) => void;
import type { SendMessage, Payload } from './types';

const UNHANDLED_CALLBACK =
'The sendMessage function was called without a callback function. ';
Expand All @@ -20,12 +16,6 @@ export const defaultErrCb = (err: string) => {
console.warn(UNHANDLED_CALLBACK + UNHANDLED_CALLBACK_ERROR, err);
};

export type SendMessage = (
message: Payload,
cb: ReplyCallback,
errCb: ErrorCallback
) => void;

export interface Spec extends TurboModule {
sendMessage: SendMessage;
}
Expand Down
5 changes: 5 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const LIBRARY_NAME = 'react-native-wear-connectivity ';
const IOS_NOT_SUPPORTED_WARNING =
' does not support iOS. Please use react-native-watch-connectivity library for iOS.';

export { LIBRARY_NAME, IOS_NOT_SUPPORTED_WARNING };
29 changes: 12 additions & 17 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { NativeModules, Platform } from 'react-native';
import { watchEvents } from './subscriptions';
import { sendMessage } from './messages';
import type { ReplyCallback, ErrorCallback } from './NativeWearConnectivity.ts';
import { watchEvents, watchEventsMock } from './subscriptions';
import { sendMessage, sendMessageMock } from './messages';
import type {
ReplyCallback,
ErrorCallback,
SendMessage,
WatchEvents,
} from './types';

const LINKING_ERROR =
`The package 'react-native-wear-connectivity' doesn't seem to be linked. Make sure: \n\n` +
Expand All @@ -27,22 +32,12 @@ const WearConnectivity = WearConnectivityModule
}
);

let sendMessageExport;
let watchEventsExport;
// let WearConnectivity;

const LIBRARY_NAME = 'react-native-wear-connectivity ';
const IOS_NOT_SUPPORTED_WARNING =
' does not support iOS. Please use react-native-watch-connectivity library for iOS.';
const iosFunctionMock = (methodName: String) => () =>
console.warn(LIBRARY_NAME + methodName + IOS_NOT_SUPPORTED_WARNING);
let sendMessageExport: SendMessage;
let watchEventsExport: WatchEvents;

if (Platform.OS === 'ios') {
sendMessageExport = iosFunctionMock('sendMessage');
watchEventsExport = {
addListener: iosFunctionMock('addListener'),
on: iosFunctionMock('watchEvents'),
};
sendMessageExport = sendMessageMock;
watchEventsExport = watchEventsMock;
} else {
sendMessageExport = sendMessage;
watchEventsExport = watchEvents;
Expand Down
8 changes: 6 additions & 2 deletions src/messages.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { SendMessage } from './NativeWearConnectivity';
import type { SendMessage } from './types';
import { defaultReplyCb, defaultErrCb } from './NativeWearConnectivity';
import { WearConnectivity } from './index';
import { LIBRARY_NAME, IOS_NOT_SUPPORTED_WARNING } from './constants';

const sendMessage: SendMessage = (message, cb, errCb) => {
const callbackWithDefault = cb ?? defaultReplyCb;
Expand All @@ -12,4 +13,7 @@ const sendMessage: SendMessage = (message, cb, errCb) => {
);
};

export { sendMessage };
const sendMessageMock: SendMessage = () =>
console.warn(LIBRARY_NAME + 'message' + IOS_NOT_SUPPORTED_WARNING);

export { sendMessage, sendMessageMock };
19 changes: 15 additions & 4 deletions src/subscriptions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { NativeModules, NativeEventEmitter } from 'react-native';

type EventType = 'message';
type AddListener = (event: EventType, cb: Function) => UnsubscribeFn;
import type { AddListener, WatchEvents } from './types';
import { LIBRARY_NAME, IOS_NOT_SUPPORTED_WARNING } from './constants';

const _addListener: AddListener = (event, cb) => {
if (!event) {
Expand All @@ -23,7 +22,19 @@ const nativeWatchEventEmitter = new NativeEventEmitter(
NativeModules.AndroidWearCommunication
);

export const watchEvents = {
const _addListenerMock: AddListener = () => {
console.warn(LIBRARY_NAME + 'watchEvents' + IOS_NOT_SUPPORTED_WARNING);
return () => {};
};

const watchEventsMock: WatchEvents = {
addListener: _addListenerMock,
on: _addListener,
};

const watchEvents: WatchEvents = {
addListener: _addListener,
on: _addListener,
};

export { watchEvents, watchEventsMock };
24 changes: 24 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Messages
export type Payload = {};
export type ReplyCallback = (reply: Payload) => void;
export type ErrorCallback = (err: string) => void;

export type SendMessage = (
message: Payload,
cb: ReplyCallback,
errCb: ErrorCallback
) => void;

// Subscriptions
export type EventType = 'message';
type UnsubscribeFn = Function;
type CallbackFunction = (event: any) => void;
export type AddListener = (
event: EventType,
cb: CallbackFunction
) => UnsubscribeFn;

export type WatchEvents = {
addListener: AddListener;
on: AddListener;
};
Empty file removed src/types.tsx
Empty file.
8 changes: 5 additions & 3 deletions watch-example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React, { useEffect, useState } from 'react';

import { StyleSheet, View, Text, TouchableOpacity } from 'react-native';
import { sendMessage, watchEvents } from '../../src/index';
import type { ReplyCallback, ErrorCallback } from '../../src/index';
import { sendMessage, watchEvents } from 'react-native-wear-connectivity';
import type {
ReplyCallback,
ErrorCallback,
} from 'react-native-wear-connectivity';

export default function App() {
const [count, setCount] = useState(0);
Expand All @@ -19,7 +22,6 @@ export default function App() {

const onSuccess: ReplyCallback = (result) => console.log(result);
const onError: ErrorCallback = (error) => console.log(error);

const sendMessageToPhone = () => {
const json = { text: 'hello', event: 'message' };
sendMessage(json, onSuccess, onError);
Expand Down
Loading