Capacitor plugin for Google Nearby & iOS Multipeer Connectivity. This plugin enables cross-platform peer-to-peer communication between Android and iOS devices using Google Nearby Connections API on Android and Multipeer Connectivity framework on iOS.
- Cross-platform communication between Android and iOS devices
- Bluetooth support for direct device-to-device communication
- Automatic fallback to Bluetooth when Nearby Connections is not available
- Simple API for advertising, discovery, and message exchange
- Proper permission handling for Android 12+ (API 31+)
- Shared BLE characteristic UUID between Android and iOS for improved cross-platform compatibility
npm install @squareetlabs/capacitor-nearby-multipeer
npx cap sync
Here's a simple example of how to use the plugin:
import { NearbyMultipeer } from '@squareetlabs/capacitor-nearby-multipeer';
// Initialize the plugin
async function initializeNearby() {
try {
// Initialize with a unique service ID
await NearbyMultipeer.initialize({ serviceId: 'my-unique-service' });
// Set the connection strategy (optional)
await NearbyMultipeer.setStrategy({ strategy: 'P2P_STAR' });
// Start advertising this device
await NearbyMultipeer.startAdvertising({ displayName: 'My Device' });
// Start discovering other devices
await NearbyMultipeer.startDiscovery();
console.log('Nearby initialized successfully');
} catch (error) {
console.error('Error initializing Nearby:', error);
}
}
// Connect to a discovered endpoint
async function connectToEndpoint(endpointId: string) {
try {
await NearbyMultipeer.connect({
endpointId: endpointId,
displayName: 'My Device'
});
console.log('Connection request sent');
} catch (error) {
console.error('Error connecting to endpoint:', error);
}
}
// Send a message to a connected endpoint
async function sendMessage(endpointId: string, message: string) {
try {
await NearbyMultipeer.sendMessage({
endpointId: endpointId,
data: message
});
console.log('Message sent successfully');
} catch (error) {
console.error('Error sending message:', error);
}
}
// Disconnect from an endpoint
async function disconnect(endpointId: string) {
await NearbyMultipeer.disconnectFromEndpoint({ endpointId: endpointId });
console.log('Disconnected from endpoint');
}
// Clean up when done
async function cleanup() {
await NearbyMultipeer.stopAdvertising();
await NearbyMultipeer.stopDiscovery();
await NearbyMultipeer.disconnect(); // Disconnect from all endpoints
console.log('Cleaned up Nearby resources');
}
This plugin uses events to communicate state changes and incoming data. You should listen for these events to properly handle the peer-to-peer communication:
import { NearbyMultipeer } from '@squareetlabs/capacitor-nearby-multipeer';
// Listen for endpoint discovery
const endpointFoundListener = await NearbyMultipeer.addListener('endpointFound', (event) => {
console.log('Endpoint found:', event.endpointId, event.endpointName);
// You might want to connect to this endpoint
});
// Listen for connection requests
const connectionRequestedListener = await NearbyMultipeer.addListener('connectionRequested', (event) => {
console.log('Connection requested from:', event.endpointId, event.endpointName);
// Decide whether to accept or reject the connection
NearbyMultipeer.acceptConnection({ endpointId: event.endpointId });
});
// Listen for connection results
const connectionResultListener = await NearbyMultipeer.addListener('connectionResult', (event) => {
console.log('Connection result for:', event.endpointId, 'Status:', event.status);
// Status: 0 = success, -1 = error
});
// Listen for incoming messages
const messageListener = await NearbyMultipeer.addListener('message', (event) => {
console.log('Message from:', event.endpointId, 'Data:', event.data);
// Process the received message
});
// Listen for disconnections
const endpointLostListener = await NearbyMultipeer.addListener('endpointLost', (event) => {
console.log('Disconnected from:', event.endpointId);
});
// Listen for transfer updates
const transferUpdateListener = await NearbyMultipeer.addListener('payloadTransferUpdate', (event) => {
console.log('Transfer update:', {
endpointId: event.endpointId,
bytesTransferred: event.bytesTransferred,
totalBytes: event.totalBytes,
status: event.status // 2 = in progress, 3 = completed
});
});
// Remove individual listeners when done
function removeListeners() {
endpointFoundListener.remove();
connectionRequestedListener.remove();
connectionResultListener.remove();
messageListener.remove();
endpointLostListener.remove();
transferUpdateListener.remove();
}
// Or remove all listeners at once
async function cleanup() {
await NearbyMultipeer.removeAllListeners();
}
This plugin requires several permissions to function properly on Android. Add the following permissions to your AndroidManifest.xml
:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:maxSdkVersion="30" android:name="android.permission.BLUETOOTH" />
<uses-permission android:maxSdkVersion="30" android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:minSdkVersion="29" android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:minSdkVersion="31" android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:minSdkVersion="31" android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:minSdkVersion="31" android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:minSdkVersion="32" android:name="android.permission.NEARBY_WIFI_DEVICES" />
For Android 12+ (API 31+), you need to request Bluetooth permissions at runtime. Here's an example of how to do this:
import { Permissions } from '@capacitor/core';
async function requestBluetoothPermissions() {
if (Capacitor.getPlatform() === 'android') {
const permissions = [
'android.permission.BLUETOOTH_SCAN',
'android.permission.BLUETOOTH_CONNECT',
'android.permission.BLUETOOTH_ADVERTISE'
];
for (const permission of permissions) {
const status = await Permissions.query({ name: permission });
if (status.state !== 'granted') {
await Permissions.request({ name: permission });
}
}
}
}
// Call this before initializing the plugin
await requestBluetoothPermissions();
For iOS, the plugin uses the Multipeer Connectivity framework which doesn't require special permissions. However, you should add a description for Bluetooth usage in your Info.plist
:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>We use Bluetooth to connect with nearby devices</string>
<key>NSLocalNetworkUsageDescription</key>
<string>We use the local network to discover and connect to nearby devices</string>
The plugin uses Bluetooth Low Energy (BLE) for cross-platform communication between Android and iOS:
- Both platforms use a common Service UUID:
fa87c0d0-afac-11de-8a39-0800200c9a66
- Both platforms use a common Characteristic UUID:
34B1CF4D-1069-4AD6-89B6-E161D79BE4D8
These shared identifiers ensure that devices can discover and communicate with each other across platforms.
initialize(options: { serviceId: string, serviceUUIDString?: string }): Promise<void>
setStrategy(options: { strategy: string }): Promise<void>
startAdvertising(options: { displayName?: string }): Promise<void>
stopAdvertising(): Promise<void>
startDiscovery(): Promise<void>
stopDiscovery(): Promise<void>
connect(options: { endpointId: string, displayName?: string }): Promise<void>
acceptConnection(options: { endpointId: string }): Promise<void>
rejectConnection(options: { endpointId: string }): Promise<void>
disconnectFromEndpoint(options: { endpointId: string }): Promise<void>
disconnect(): Promise<void>
sendMessage(options: { endpointId: string, data: string }): Promise<void>
connectionRequested
: Fired when a connection request is receivedconnectionResult
: Fired when a connection attempt completesendpointFound
: Fired when a new endpoint is discoveredendpointLost
: Fired when an endpoint is lostmessage
: Fired when a message is receivedpayloadTransferUpdate
: Fired during payload transfer
interface ConnectionRequestEvent {
endpointId: string;
endpointName: string;
authenticationToken: string;
isIncomingConnection: boolean;
}
interface ConnectionResultEvent {
endpointId: string;
status: number; // 0 = success, -1 = error
}
interface EndpointFoundEvent {
endpointId: string;
endpointName: string;
serviceId: string;
}
interface EndpointLostEvent {
endpointId: string;
}
interface MessageReceivedEvent {
endpointId: string;
data: string;
}
interface PayloadTransferUpdateEvent {
endpointId: string;
bytesTransferred: number;
totalBytes: number;
status: number; // 2 = in progress, 3 = completed
}
import { NearbyMultipeer } from '@squareetlabs/capacitor-nearby-multipeer';
await NearbyMultipeer.initialize({
serviceId: 'mi-servicio',
serviceUUIDString: 'fa87c0d0-afac-11de-8a39-0800200c9a66' // Opcional, UUID BLE personalizado
});
serviceId
: Identificador lógico del servicio (obligatorio)serviceUUIDString
: UUID BLE que se usará para el advertising y escaneo (opcional, por defecto:fa87c0d0-afac-11de-8a39-0800200c9a66
)
Este UUID debe ser el mismo en Android e iOS para que ambos sistemas puedan descubrirse mutuamente por BLE.