![]() |
VOOZH | about |
dotnet add package Plugin.Maui.NearbyConnections --version 0.3.0-preview.1
NuGet\Install-Package Plugin.Maui.NearbyConnections -Version 0.3.0-preview.1
<PackageReference Include="Plugin.Maui.NearbyConnections" Version="0.3.0-preview.1" />
<PackageVersion Include="Plugin.Maui.NearbyConnections" Version="0.3.0-preview.1" />Directory.Packages.props
<PackageReference Include="Plugin.Maui.NearbyConnections" />Project file
paket add Plugin.Maui.NearbyConnections --version 0.3.0-preview.1
#r "nuget: Plugin.Maui.NearbyConnections, 0.3.0-preview.1"
#:package Plugin.Maui.NearbyConnections@0.3.0-preview.1
#addin nuget:?package=Plugin.Maui.NearbyConnections&version=0.3.0-preview.1&prereleaseInstall as a Cake Addin
#tool nuget:?package=Plugin.Maui.NearbyConnections&version=0.3.0-preview.1&prereleaseInstall as a Cake Tool
A .NET MAUI plugin for peer-to-peer (P2P) connectivity with nearby devices by unifying Google's Nearby Connections and Apple's Multipeer Connectivity capabilities.
👁 NuGet Version
👁 GitHub License
Peer-to-peer communication happens in two phases.
Phase 1 — Finding peers. One device advertises its presence; another scans for advertisers. This is a continuous IAsyncEnumerable stream of "device appeared" / "device disappeared" events. Nothing is connected yet — you are learning who is nearby.
Phase 2 — Talking to them. Once you pick a peer and connect (or accept their inbound request), a NearbyConnection is established. That object is itself an async stream of incoming payloads, and exposes SendAsync for the outbound direction.
The tier-1 API (INearbyConnections) exposes these two phases directly as AdvertiseAsync / DiscoverAsync streams. For MAUI app code, the tier-2 services (INearbyAdvertiser / INearbyDiscoverer) stitch both phases into a single EventsAsync stream per role — lifecycle events and payload delivery unified, with current state replayed atomically on subscribe.
| Platform | Minimum Version |
|---|---|
| Android | API 24 (Android 7.0) |
| iOS | iOS 13.0 |
| Dependency | Android | iOS |
|---|---|---|
| ✅ | ✅ | |
| Microsoft.Maui.Core | ✅ | ✅ |
| Xamarin.GooglePlayServices.Nearby | ✅ |
Plugin.Maui.NearbyConnections is available on nuget.org
dotnet add package Plugin.Maui.NearbyConnections
</details>
// MauiProgram.cs
public static MauiApp CreateMauiApp()
=> MauiApp.CreateBuilder()
.UseMauiApp<App>()
.AddNearbyConnections()
.Build();
Add to AndroidManifest.xml:
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation" />
Add to Info.plist:
<key>NSBonjourServices</key>
<array>
<string>_yourserviceid._tcp</string>
<string>_yourserviceid._udp</string>
</array>
<key>NSLocalNetworkUsageDescription</key>
<string>Used to discover and connect to nearby devices.</string>
The service ID in NSBonjourServices must match NearbyConnectionsOptions.ServiceId (default: app name).
One device advertises while the other discovers, or both do both simultaneously.
using var cts = new CancellationTokenSource();
await foreach (var request in nearbyConnections.AdvertiseAsync(cts.Token))
{
Console.WriteLine($"Connection request from: {request.RemoteDevice.DisplayName}");
// Accept to get an established NearbyConnection
NearbyConnection connection = await request.AcceptAsync(cts.Token);
Console.WriteLine($"Connected to {connection.RemoteDevice.DisplayName}");
// Send and receive on this connection (see section 4)
}
To reject a request call request.RejectAsync() instead of AcceptAsync().
using var cts = new CancellationTokenSource();
await foreach (var evt in nearbyConnections.DiscoverAsync(cts.Token))
{
if (evt.Type == NearbyDeviceEventType.Found)
{
Console.WriteLine($"Found: {evt.Device.DisplayName}");
NearbyConnection connection = await nearbyConnections.ConnectAsync(evt.Device, cts.Token);
Console.WriteLine($"Connected to {connection.RemoteDevice.DisplayName}");
// Send and receive on this connection (see section 4)
}
}
NearbyConnection is obtained from AcceptAsync (advertiser) or ConnectAsync (discoverer).
byte[] data = Encoding.UTF8.GetBytes("Hello!");
await connection.SendAsync(data, cancellationToken);
// Pass a file:// URI, or a content:// URI on Android
await connection.SendAsync("file:///path/to/file.bin", cancellationToken: cancellationToken);
var progress = new Progress<NearbyTransferProgress>(p =>
Console.WriteLine($"Sent {p.BytesTransferred}/{p.TotalBytes} ({p.Fraction:P0})"));
await connection.SendAsync("file:///path/to/file.bin", progress, cancellationToken);
await foreach (var payload in connection.ReceiveAsync(cancellationToken))
{
if (payload is BytesPayload bytes)
{
string message = Encoding.UTF8.GetString(bytes.Data);
Console.WriteLine($"From {connection.RemoteDevice.DisplayName}: {message}");
}
else if (payload is FilePayload file)
{
Console.WriteLine($"Received file: {file.FileResult.FullPath}");
}
}
Received files are saved to NearbyConnectionsOptions.ReceivedFilesDirectory (default: FileSystem.AppDataDirectory).
// Disconnect from a specific peer
await connection.DisposeAsync();
// Stop advertising or discovering by canceling the token passed to AdvertiseAsync/DiscoverAsync
cts.Cancel();
// Dispose the plugin when done (e.g. in page OnDisappearing)
await nearbyConnections.DisposeAsync();
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-android36.0 net10.0-android36.0 is compatible. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-ios26.0 net10.0-ios26.0 is compatible. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.3.0-preview.1 | 55 | 5/24/2026 |