react-native-google-nearby-messages
Version:
An async Google Nearby Messages API Wrapper for React Native (Android & iOS)
203 lines (144 loc) • 9.68 kB
Markdown
<p align="center">
<img src="img/nearby-messages-icon.png" height="120" />
<h2 align="center">react-native-google-nearby-messages</h2>
</p>
An async **Google Nearby Messages** API Wrapper for **React Native** (Android & iOS), supporting autolinking, custom discovery modes (`broadcast`, `scan`, ..), custom discovery mediums (`bluetooth`, `audio`, ..), awaitable native invokations and React hooks!
> Also, this is a good example on how to use _Swift_ in a React Native - Native Module.
[](https://badge.fury.io/js/react-native-google-nearby-messages)
[](https://GitHub.com/mrousavy/react-native-google-nearby-messages/stargazers/)
[](https://github.com/mrousavy?tab=followers)
<a href='https://ko-fi.com/F1F8CLXG' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi2.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
## Install
> This packages uses React Native autolinking (> 0.60)
```sh
npm i react-native-google-nearby-messages
# for iOS
cd ios && pod install && cd ..
```
> Note (iOS): Everytime you run `pod install` an entry called `Assets.car` is created in your **Build Phases** -> **[CP] Copy Pods Resources** which causes the build to fail. This is a known bug in the Google **NearbyMessages** pod. A workaround is to manually remove this file everytime you run `pod install`. See [#4 (comment)](https://github.com/mrousavy/react-native-google-nearby-messages/issues/4#issuecomment-649961499) for an automatic fix. Please [create a PR here](https://github.com/mrousavy/react-native-google-nearby-messages/pulls) if you found a better solution for this!
## Usage
See the [example app](example/).
### iOS Setup
> See: https://developers.google.com/nearby/messages/ios/get-started
1. Add bluetooth permissions (`NSBluetoothPeripheralUsageDescription`, `NSBluetoothAlwaysUsageDescription` for 'ble', and `NSMicrophoneUsageDescription` for 'audio') to `Info.plist`
2. Create your API Key at [the Google Developer Console](https://console.developers.google.com/flows/enableapi?apiid=copresence&keyType=CLIENT_SIDE_IOS&reusekey=true).
3. (Optionally): Add the [react-native-permissions](https://github.com/react-native-community/react-native-permissions) library to check if Bluetooth is available on the device (it's `'unavailable'` on iOS Simulators!) If it's `'unavailable'`, calls to subscribe or publish might crash the app (`EXC_BAD_ACCESS`) so only call if Bluetooth permission is `denied`, `granted` or `blocked`. This library will handle the permission checking for you when you call `publish()` or `subscribe()` for the first time.
4. Pass the generated API Key as a parameter using the `connect` function
### Android Setup
> See: https://developers.google.com/nearby/messages/android/get-started
1. Create your API Key at [the Google Developer Console](https://console.developers.google.com/flows/enableapi?apiid=copresence&keyType=CLIENT_SIDE_ANDROID&reusekey=true).
2. Add your generated API Key and Permissions to your `AndroidManifest.xml`:
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.sample.app" >
<!-- For BLE/Bluetooth -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- For Audio -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application ...>
<meta-data
android:name="com.google.android.nearby.messages.API_KEY"
android:value="API_KEY" />
<activity>
...
</activity>
</application>
</manifest>
```
3. (Optionally): Call `checkBluetoothAvailability()` to ensure that Bluetooth capabilities are available on the current device.
4. Call `connect` without any key.
### Publishing
```ts
import { connect, publish, addOnErrorListener } from 'react-native-google-nearby-messages';
const removeListener = addOnErrorListener((kind, message) => console.error(`${kind}: ${message}`));
const disconnect = await connect({ apiKey: GOOGLE_API_KEY });
const unpublish = await publish('hello !');
// later, e.g. in componentWillUnmount()
removeListener();
unpublish();
disconnect();
```
> Make sure to unpublish, disconnect and remove any listeners as they won't be removed automatically! I don't know if that's possible, if so, please create a Pull Request.
### Subscribing
```ts
import { connect, subscribe, addOnErrorListener } from 'react-native-google-nearby-messages';
const removeListener = addOnErrorListener((kind, message) => console.error(`${kind}: ${message}`));
const disconnect = await connect({ apiKey: GOOGLE_API_KEY });
const unsubscribe = await subscribe(
(m) => {
console.log(`new message found: ${m}`);
},
(m) => {
console.log(`message lost: ${m}`);
});
// later, e.g. in componentWillUnmount()
removeListener();
unsubscribe();
disconnect();
```
> Make sure to unpublish, disconnect and remove any listeners as they won't be removed automatically! I don't know if that's possible, if so, please create a Pull Request.
### Bluetooth Availability
Check if the user has granted Bluetooth Permissions. This feature is experimental, and strongly differs between iOS and Android.
```ts
import { checkBluetoothPermission } from 'react-native-google-nearby-messages';
const hasPermission = await checkBluetoothPermission();
```
Check if bluetooth is available on this device. This feature is experimental, and strongly differs between iOS and Android. Make sure to use a library like **react-native-permissions** to check if Bluetooth is really available, otherwise your Application might crash with a `EXEC_BAD_ACCESS` error. See [troubleshooting](#troubleshooting)
```ts
import { checkBluetoothAvailability } from 'react-native-google-nearby-messages';
const isBluetoothAvailable = await checkBluetoothAvailability();
```
### React Hooks
This library also provides react hooks for common use cases. In case you're not familiar with hooks, please read the [hooks documentation](https://reactjs.org/docs/hooks-intro.html). When the component unmounts, the hooks automatically stop publishing, subscribing, remove error listeners and disconnect for you. You can also look into the [hooks source code](https://github.com/mrousavy/react-native-google-nearby-messages/blob/master/index.ts#L140-L259) and tweak them for your use case.
Make sure to memoize the `NearbyConfig` object using `useMemo`, otherwise the hooks will fall into an infinite loop of re-renders because the config object gets re-created each time and therefore _has changed_. (See: [react useEffect's deps](https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects))
#### useNearbyPublication
Publishes a message and returns a state which describes the Nearby API status. (e.g.: `connecting`, `published`, `error`, ...)
```ts
export default function App() {
const nearbyConfig = useMemo<NearbyConfig>(() => ({ apiKey: GOOGLE_API_KEY }), []);
const nearbyStatus = useNearbyPublication(nearbyConfig, 'Hello from Nearby!');
// ...
}
```
#### useNearbySubscription
Subscribe to nearby messages and return a state for all messages in an array, as well as a state describing the Nearby API Status. (e.g.: `connecting`, `published`, `error`, ...)
```tsx
export default function App() {
const nearbyConfig = useMemo<NearbyConfig>(() => ({ apiKey: GOOGLE_API_KEY }), []);
const { nearbyMessages, nearbyStatus } = useNearbySubscription(nearbyConfig);
return (
<FlatList
data={nearbyMessages}
renderItem={({ item }) => <Text>{item}</Text>}
/>
);
}
```
#### useNearbySearch
Search for a specific message using nearby messages. The `isNearby` local specifies whether the string `iPhone 11` could be found using the Nearby API, and the `nearbyStatus` local describes the current status of the Nearby API. (e.g.: `connecting`, `published`, `error`, ...)
```tsx
export default function App() {
const nearbyConfig = useMemo<NearbyConfig>(() => ({ apiKey: GOOGLE_API_KEY }), []);
const { isNearby, nearbyStatus } = useNearbySearch(nearbyConfig, 'iPhone 11');
return (
<Text>{isNearby ? 'iPhone 11 is nearby!' : 'iPhone 11 is far, far away.'}</Text>
);
}
```
#### useNearbyErrorCallback
Subscribe to any errors emitted from the Nearby API.
```ts
export default function App() {
useNearbyErrorCallback((kind, message) => {
console.log(`Nearby API Error: ${kind}: ${message}`)
});
}
```
## Troubleshooting
If you're having any trouble getting the Nearby API working, please make sure you've read [the Troubleshooting Page](./TROUBLESHOOTING.md).
If that doesn't help either, [create an issue](https://github.com/mrousavy/react-native-google-nearby-messages/issues).
<a href='https://ko-fi.com/F1F8CLXG' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi2.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
## Resources
* [This medium article](https://teabreak.e-spres-oh.com/swift-in-react-native-the-ultimate-guide-part-1-modules-9bb8d054db03)