Table of Contents

Class NearbyConnection

Namespace
Plugin.Maui.NearbyConnectivity
Assembly
Plugin.Maui.NearbyConnectivity.dll

Represents an established connection to a nearby device, over which payloads can be sent and received.

public sealed class NearbyConnection
Inheritance
NearbyConnection
Inherited Members

Remarks

Obtain an instance from ConnectAsync(CancellationToken), AcceptAsync(CancellationToken), or Connection. All three return the same instance for a given remote device.

Deliberately not disposable. The session owns the connection and every holder shares one instance, so a using block would let whichever holder exited first disconnect everyone else, a bug with no compile-time signal, since the code reads exactly like correct C#. Closing is a network operation rather than a resource-cleanup one, so it is named as one: CloseAsync(), which any holder may call and which closes the connection for all of them. Shaped after ClientWebSocket, where the same distinction applies.

Fields

MaxBytesPayloadLength

Gets the largest byte payload SendAsync(ReadOnlyMemory<byte>, CancellationToken) accepts.

public const int MaxBytesPayloadLength = 32768

Field Value

int

Remarks

One cap on every platform, so a payload that sends on one sends on the other. It is the lowest any supported backend accepts rather than the most any one of them could carry. Send anything larger as a file.

Properties

AuthenticationCode

Gets a six-digit code derived from the platform's handshake, for the two people to compare out loud before they trust the connection.

public string AuthenticationCode { get; }

Property Value

string

Six ASCII digits, such as "482107", identical on both ends of the same connection. Empty when the platform handshake produced nothing to derive a code from; the plugin logs a warning, and the two people have nothing to compare.

Remarks

Encryption alone proves that nobody can read the traffic, not who is on the other end: a machine in the middle can hold one encrypted connection to each person and relay between them. It cannot make the two codes match, because each is derived from the handshake it terminated. Two people who read the same six digits to each other have ruled that out; two who read different ones should close the connection.

The comparison has to happen over a channel the relay does not control — out loud, across a table, or over a call where the voice is recognised. Comparing the codes by sending them over this connection proves nothing.

Nothing enforces the check. The plugin derives and shows the code; whether a connection may carry payloads before somebody confirms it is the application's decision.

The derivation is an implementation detail and may change between releases; both ends of a connection run the same build, so only the comparison is guaranteed, never a specific value.

See Also

Closed

Gets a task that completes once this connection ends, carrying why.

public Task<NearbyEndReason> Closed { get; }

Property Value

Task<NearbyEndReason>

A task that completes when the connection ends, from either side and for any reason.

Remarks

Four of the ten NearbyEndReason values reach here: ClosedLocally, PeerDisconnected, SessionStopped and AppSuspended. The rest describe a handshake that never opened or a device leaving the device set, neither of which this task reports.

Safe to await alongside a read of PayloadsAsync(CancellationToken). It does not consume the payload stream. Never faults or is canceled: a dropped connection is not an error at this boundary, so this task always completes successfully. Continuations are queued to the thread pool, never run inline on the platform callback that ended the connection.

IsOpen

Gets whether this connection is still open.

public bool IsOpen { get; }

Property Value

bool

true until the connection ends, from either side and for any reason.

Remarks

A snapshot. The connection can end between reading this and acting on the result, so a send on a connection this reported open can still fail. Treat it as a display value, and let SendAsync(ReadOnlyMemory<byte>, CancellationToken) report the authoritative answer.

RemoteDevice

Gets the remote device this connection is established with.

public NearbyDevice RemoteDevice { get; }

Property Value

NearbyDevice

The device on the other end of the connection.

Methods

CancelInboundTransferAsync(long)

Cancels one inbound file transfer on this connection. The connection stays open.

public Task CancelInboundTransferAsync(long payloadId)

Parameters

payloadId long

The PayloadId that InboundTransfersAsync(CancellationToken) reported for the transfer.

Returns

Task

A Task that represents the asynchronous operation. The task completes once the cancel is handed to the platform, not when the transfer stops.

Remarks

Use it to refuse a file that is larger than your app expects: watch TotalBytes and cancel that transfer, instead of closing the connection.

The result arrives on InboundTransfersAsync(CancellationToken): a terminal Canceled snapshot when the cancel took effect, or Completed when the transfer finished first, in which case the payload is delivered as usual. The sender's SendFileAsync throws NearbyTransferCanceledException.

A transfer can end between a progress snapshot and this call, so an id that is unknown, belongs to a transfer that already ended, or arrives after the connection closed is ignored. The call never throws because of the state of the transfer.

Takes no CancellationToken, like CloseAsync(): the platform call it makes cannot be interrupted.

CloseAsync()

Closes this connection.

public Task CloseAsync()

Returns

Task

A Task that represents the asynchronous operation. The task completes once the disconnect has been signaled to the platform and any in-flight inbound work for this connection has drained or timed out.

Remarks

Closes it for every holder, not just the caller. There is one connection per device and one instance representing it, so closing is a network operation with a remote effect, not the release of a local handle. This is the same contract as DisconnectAsync(), which reaches the same connection by device id.

Idempotent: a second call performs no additional work. Closed completes with ClosedLocally.

Takes no CancellationToken, like the stop methods on INearbyConnectivity: teardown is work the caller wants finished, and the drain it waits for is already bounded internally.

InboundTransfersAsync(CancellationToken)

Watches the progress of inbound file transfers on this connection.

public IAsyncEnumerable<NearbyTransferProgress> InboundTransfersAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

A token to end the enumeration.

Returns

IAsyncEnumerable<NearbyTransferProgress>

An IAsyncEnumerable<T> yielding each progress snapshot in order, for every inbound transfer on this connection. The last snapshot for a transfer carries a terminal Status: Completed once the payload has been delivered, or Failed or Canceled when it never will be.

Remarks

A stream rather than a settable IProgress property, so it follows the same rule as everything else that changes over time here, and so several components can watch independently: each enumeration gets its own feed.

Outbound progress is a parameter on each SendAsync overload instead, because the caller starting the transfer already knows which provider to use. An inbound transfer begins on a platform callback before any caller could supply one.

Snapshots arrive on a thread-pool thread; see the thread-safety notes on INearbyConnectivity.

OpenStreamAsync(string, CancellationToken)

Opens a named one-way byte stream to the remote device, for unknown-length or live data.

[Experimental("NEARBY001", UrlFormat = "https://phunkeler.github.io/Plugin.Maui.NearbyConnectivity/docs/payloads.html#open-a-stream")]
public Task<Stream> OpenStreamAsync(string name, CancellationToken cancellationToken = default)

Parameters

name string

The stream's name, shown to the remote application. At most 1024 UTF-8 bytes.

cancellationToken CancellationToken

A token to abandon opening the stream.

Returns

Task<Stream>

The writable stream. Dispose it to end the stream. The remote reader then observes the end of its half. A dropped connection ends the stream from either side.

Remarks

Experimental. Streams have not been tested between two devices, and their behavior and API can change in any release. Code that uses this method gets build error NEARBY001. To opt in, add NEARBY001 to NoWarn in the project file, or suppress it with #pragma warning disable NEARBY001.

The remote side receives a NearbyStreamPayload, the readable half plus this name, through PayloadsAsync(CancellationToken). Both platforms carry this natively: a stream payload on Android, a named MultipeerConnectivity stream on iOS. The name arrives with the stream on both. Writes are not bounded by FileTransferInactivityTimeout: the application owns the stream's lifetime and pacing.

Exceptions

ArgumentNullException

name is null.

ArgumentException

name exceeds 1024 UTF-8 bytes, the limit the name travels under.

NearbyException

The remote device disconnected before this call, so no active connection remains.

NearbyTransferException

The platform returned an error opening the stream.

OperationCanceledException

cancellationToken was canceled.

SendAsync(ReadOnlyMemory<byte>, CancellationToken)

Sends raw bytes to the remote device.

public Task SendAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken = default)

Parameters

data ReadOnlyMemory<byte>

The bytes to send.

cancellationToken CancellationToken

A token to abandon the send.

Returns

Task

A Task that represents the asynchronous operation. The task completes once the bytes are handed off to the platform.

Remarks

Completing is not a delivery receipt. It means the platform accepted the bytes for sending. The peer may have left range immediately afterwards, and nothing raises an error. This differs from SendFileAsync, which completes when the transfer itself finished.

To know the peer received something, acknowledge it in your own protocol: send an identifier, and have the peer send it back once it has stored the work. That is also the only acknowledgement that means the receiving application kept it, which no transport-level signal can promise. See the payloads guide.

Takes a ReadOnlyMemory<T> rather than an array, so the caller keeps ownership of the buffer and can send a slice without slicing into a new array first. Both platform SDKs need contiguous native memory, so the bytes are copied once at that boundary.

Exceptions

OperationCanceledException

cancellationToken was canceled.

NearbyTransferException

The platform returned an error for the send.

ArgumentOutOfRangeException

data is longer than MaxBytesPayloadLength bytes.

ArgumentException

data starts with the 4-byte signature of the plugin's control frames, so the remote device would consume or drop it and not deliver it.

NearbyException

The remote device disconnected before this call, so no active connection remains to send on.

SendFileAsync(FileResult, IProgress<NearbyTransferProgress>?, CancellationToken)

Sends the specified file to the remote device.

public Task SendFileAsync(FileResult file, IProgress<NearbyTransferProgress>? progress = null, CancellationToken cancellationToken = default)

Parameters

file FileResult

The file to send.

progress IProgress<NearbyTransferProgress>

An optional provider that receives progress updates for the outgoing transfer, or null to ignore progress. Reported on the platform SDK's own callback thread, so pass a Progress<T> rather than a hand-written IProgress<T> that touches the user interface or blocks.

cancellationToken CancellationToken

A token to abandon the transfer.

Returns

Task

A Task that represents the asynchronous operation. The task completes once the transfer finishes.

Remarks

Accepts the same FileResult type that NearbyFilePayload exposes, so a received file can be forwarded without conversion.

A FileResult from a picker does not always carry a readable file-system path: on iOS FullPath may be a bare file name. When that is the case, the file is copied to a temporary location through its stream, sent from there, and the temporary copy is deleted once the transfer ends. Pass a picker result directly; no staging of your own is needed.

The receiver sees FileName, not the name of the file on disk. A picker's FullPath is often a temporary copy with a generated name.

Exceptions

ArgumentNullException

file is null.

OperationCanceledException

cancellationToken was canceled.

NearbyTransferTimeoutException

No transfer progress was reported within FileTransferInactivityTimeout.

NearbyTransferCanceledException

The other device canceled the transfer, or the platform did.

NearbyTransferException

The platform returned an error for the send.

NearbyException

The remote device disconnected before this call, so no active connection remains to send on.

SendFileAsync(string, IProgress<NearbyTransferProgress>?, CancellationToken)

Sends the file at the specified path to the remote device.

public Task SendFileAsync(string path, IProgress<NearbyTransferProgress>? progress = null, CancellationToken cancellationToken = default)

Parameters

path string

The file to send: a file-system path on every platform, or a content:// URI on Android.

progress IProgress<NearbyTransferProgress>

An optional provider that receives progress updates for the outgoing transfer, or null to ignore progress. Reported on the platform SDK's own callback thread, so pass a Progress<T>, which marshals to the thread it was constructed on, rather than a hand-written IProgress<T> that touches the user interface or blocks, which would stall the SDK's callback.

cancellationToken CancellationToken

A token to abandon the transfer.

Returns

Task

A Task that represents the asynchronous operation. The task completes once the transfer finishes.

Remarks

The lower-level of the two file overloads: it sends what the path names, with no staging. Use it whenever the application already holds a real, readable file-system path: a file it wrote itself, one downloaded to its cache, one produced by a background job. Prefer SendFileAsync(FileResult, IProgress<NearbyTransferProgress>?, CancellationToken) only for a picker result, whose path is not always real.

Exceptions

ArgumentNullException

path is null.

OperationCanceledException

cancellationToken was canceled.

NearbyTransferTimeoutException

No transfer progress was reported within FileTransferInactivityTimeout.

NearbyTransferCanceledException

The other device canceled the transfer, or the platform did.

NearbyTransferException

The file could not be sent: for example, the path does not identify a readable file, or the platform returned an error for the send.

NearbyException

The remote device disconnected before this call, so no active connection remains to send on.

See Also