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
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
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
payloadIdlongThe 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
cancellationTokenCancellationTokenA 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
namestringThe stream's name, shown to the remote application. At most 1024 UTF-8 bytes.
cancellationTokenCancellationTokenA 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
nameis null.- ArgumentException
nameexceeds 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
cancellationTokenwas canceled.
SendAsync(ReadOnlyMemory<byte>, CancellationToken)
Sends raw bytes to the remote device.
public Task SendAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken = default)
Parameters
dataReadOnlyMemory<byte>The bytes to send.
cancellationTokenCancellationTokenA 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
cancellationTokenwas canceled.- NearbyTransferException
The platform returned an error for the send.
- ArgumentOutOfRangeException
datais longer than MaxBytesPayloadLength bytes.- ArgumentException
datastarts 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
fileFileResultThe file to send.
progressIProgress<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.
cancellationTokenCancellationTokenA 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
fileis null.- OperationCanceledException
cancellationTokenwas 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
pathstringThe file to send: a file-system path on every platform, or a
content://URI on Android.progressIProgress<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.
cancellationTokenCancellationTokenA 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
pathis null.- OperationCanceledException
cancellationTokenwas 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.