Options and limits

The plugin reads all NearbyOptions values once at startup. Set them in the configure delegate of AddNearbyConnectivity(...), shown in Register the plugin. A change after startup has no effect.

The presence is the one value that can change later, through SetPresence. The Presence option is its initial value.

NearbyOptions.Android exists on every target, so shared code compiles without #if. On other platforms it has no effect.

Options

Member Platform Default Description
ServiceId Both None. Required. The identifier that both devices must share. Only devices with the same ServiceId find each other. 1 to 15 characters: ASCII lowercase letters, digits, and hyphens. At least one letter. No hyphen at the start, at the end, or next to another hyphen. On iOS, it is also the service type that the system advertises. See Set up Android and iOS. Startup validation throws if the value is not set or is invalid.
Presence Both DeviceInfo.Name, empty info The data that other devices see before a connection exists. It has a DisplayName of at most 63 UTF-8 bytes and at most 57 bytes of opaque Info. The option sets the initial value only. See Show a presence before connecting. Public and unverified. The plugin broadcasts it unencrypted, and any device can claim any presence.
OfferWindow Both 2 minutes The time that a connect or an inbound request waits for an answer, on both ends. At most 30 minutes. Startup validation rejects zero, negative values, and Timeout.InfiniteTimeSpan. The value travels with the request, so the peer's prompt, through NearbyConnectionRequest.ExpiresAt, and an accepted handshake expire at the same moment. When the time elapses, ConnectAsync and AcceptAsync throw NearbyConnectException with TimedOut. A request that a consent policy answers has a separate limit. See Consent policies.
DiscoveryRefreshInterval Both null, never restarts The interval at which discovery restarts to find which devices are still in range. The plugin removes devices that the new pass does not report again. It never removes a device that is connected or in a handshake. With the default, discovery never restarts on its own, and Discoverer.RefreshAsync restarts it on request.
FileTransferInactivityTimeout Both 10 seconds Outbound only. If a file send makes no progress within this time, the plugin abandons the send with NearbyTransferTimeoutException. null disables the check, as it does for DiscoveryRefreshInterval. An inbound transfer that stops has no time limit: watch InboundTransfersAsync and call CancelInboundTransferAsync.
Android.Topology Android NearbyTopology.Cluster How devices can connect. Cluster is many-to-many. Star is one-to-many. PointToPoint is one-to-one, with the highest bandwidth. The advertising device and the discovering device must use the same value, or they never find each other.
Android.ConnectionType Android NearbyConnectionType.Balanced How hard the radio works after a connection opens: Balanced, HighBandwidth, or NonDisruptive.
Android.UseLowPower Android false When true, the plugin uses only low-power mediums such as BLE. The result is less battery use, less range, and less throughput.

Inbound consent is not an option, because it can change at run time. Advertiser.SetConsent sets it. See Answer an inbound request.

Limits

This table lists every fixed number that the plugin enforces. The plugin validates each one and never truncates a value silently.

What Limit Where it applies
ServiceId length 1 to 15 characters Startup validation throws outside this range
NearbyPresence.DisplayName 63 UTF-8 bytes, NearbyPresence.MaxDisplayNameBytes ArgumentException that names the member
NearbyPresence.Info 57 bytes, NearbyPresence.MaxInfoBytes ArgumentException that names the member
A bytes payload 32 KiB, NearbyConnection.MaxBytesPayloadLength SendAsync(ReadOnlyMemory<byte>) throws ArgumentOutOfRangeException. A file or a stream carries more
A stream name 1024 UTF-8 bytes OpenStreamAsync throws
OfferWindow 30 minutes Startup validation rejects a longer value, zero, negative values, and Timeout.InfiniteTimeSpan. The plugin clamps a value that a peer declared to the same limit on arrival.
Unread payloads on one connection None. At 64, the plugin logs a warning The plugin drops nothing and pauses nothing. See the buffer has no bound

The 57-byte Info limit comes from the plugin's connect request frame. It is the space that remains after the frame header, the offer window, and a 63-byte name of maximum length. Both limits come from the frame, not from one platform, so they apply on both platforms.

An inbound file has no size limit. See Treat every payload as hostile input.

A consent policy controls how the plugin answers inbound connection requests. Advertiser.SetConsent is the only way to set it, and each call replaces both the policy and the decide callback. To answer requests yourself, see Answer an inbound request.

Policy What it does
Hold, the default Moves the device to RequestReceived with the request on device.Request, and waits
AcceptAll Accepts every request for you. The device moves directly to Connected and never reports RequestReceived, so a UI that waits only for requests shows nothing
RejectAll Declines every request for you

A request that the policy answers for you does not use the offer window. It has 30 seconds to complete its handshake. The offer window covers delivery, the decision of a person, and the handshake, and a policy that answers removes the decision. When the 30 seconds elapse, the plugin abandons the handshake, the device returns to Visible, and the plugin logs a warning. A request that a person answers through AcceptAsync still has the full window that the requesting device declared.

Connection end reasons

NearbyConnection.Closed completes with one of these four values. NearbyEndReason has ten values. The other six describe a handshake or a change to Devices, and appear in NearbyDeviceChange.Reason instead.

Reason What happened
ClosedLocally This side called CloseAsync or DisconnectAsync
PeerDisconnected The peer closed the connection, or the link was lost. Neither platform distinguishes the two
SessionStopped StopAllAsync stopped the session
AppSuspended The plugin stopped the session because the iOS app moved to the background

Next