public final class NearbyTransport

  1. Object
  2. NearbyTransport

Moving bytes and files to a device that is physically nearby, with no access point, no pairing and no internet.

The platform picks and combines the radios itself – Bluetooth to find each other, then Wi-Fi to move the data – so an app advertises a service id, discovers peers using the same id, connects, and sends payloads.

This transport does not cross ecosystems

Android talks to Android and Apple talks to Apple, and the two do not meet. Underneath are Google’s Nearby Connections and Apple’s MultipeerConnectivity, which share no wire protocol; nothing in this API papers over that, because a portable-looking API that silently never finds the peer is worse than an honest limitation.

For an iPhone that must talk to an Android phone, the framework already has two things that do work across the divide:

  • com.codename1.bluetooth.le.L2capChannel – a raw bidirectional byte stream over BLE, on every platform that has BLE.
  • com.codename1.io.bonjour plus ordinary sockets, when both devices are on the same Wi-Fi network.

Quick start

NearbyTransport.addTransportListener(new TransportAdapter() {
    public void endpointFound(Endpoint e) {
        NearbyTransport.requestConnection(e, "Shai's phone");
    }
    public void connectionRequested(IncomingConnection r) {
        // show r.getAuthenticationToken() on both screens before this
        r.accept();
    }
    public void connected(Endpoint e) {
        NearbyTransport.send(e, Payload.fromBytes(data));
    }
    public void payloadReceived(Endpoint e, Payload p) {
        process(p.getBytes());
    }
});
NearbyTransport.startAdvertising("com.example.chat", "Shai's phone",
        TransportStrategy.CLUSTER);
NearbyTransport.startDiscovery("com.example.chat", TransportStrategy.CLUSTER);

Threading

Every callback here is delivered on the EDT.

Methods

public static boolean isSupported()true when this port implements the nearby transport.
public static NearbyAvailability getAvailability()How usable the transport is right now.
public static int getMaxPayloadSize()The largest byte payload send accepts in one call.
public static AsyncResource<Boolean> requestPermissions(NearbyPermission... permissions)Asks for the runtime permissions the transport needs – on Android that is the Bluetooth trio plus nearby Wi-Fi, which is a lot to ask for at once, so ask when the user reaches the feature rather than at startup.
public static AsyncResource<Boolean> startAdvertising(String serviceId, String localName, TransportStrategy strategy)Starts advertising this device so peers running the same service id can find it.
public static void stopAdvertising()Stops advertising.
public static AsyncResource<Boolean> startDiscovery(String serviceId, TransportStrategy strategy)Starts looking for peers advertising the same service id.
public static void stopDiscovery()Stops discovery.
public static AsyncResource<Boolean> requestConnection(Endpoint endpoint, String localName)Asks a discovered endpoint to connect.
public static AsyncResource<Boolean> send(Endpoint endpoint, Payload payload)Sends a payload to one connected endpoint.
public static AsyncResource<Boolean> send(Endpoint[] endpoints, Payload payload)Sends a payload to several connected endpoints at once, which both platforms do more efficiently than one call each.
public static void cancel(int payloadId)Cancels an in-flight payload.
public static void disconnect(Endpoint endpoint)Disconnects one endpoint.
public static void stop()Stops advertising and discovery and drops every connection.
public static void addTransportListener(TransportListener l)Registers a listener.
public static void removeTransportListener(TransportListener l)Removes a listener added by addTransportListener.

Inherited methods

Method details

isSupported

public static boolean isSupported()
true when this port implements the nearby transport.

getAvailability

public static NearbyAvailability getAvailability()
How usable the transport is right now.

Returns

the current availability, never null

getMaxPayloadSize

public static int getMaxPayloadSize()
The largest byte payload send accepts in one call. Anything bigger has to go as a file payload.

Returns

the limit in bytes, or zero when the transport is unsupported

requestPermissions

public static AsyncResource<Boolean> requestPermissions(NearbyPermission... permissions)
Asks for the runtime permissions the transport needs – on Android that is the Bluetooth trio plus nearby Wi-Fi, which is a lot to ask for at once, so ask when the user reaches the feature rather than at startup.

Parameters

permissions NearbyPermission...
what the app intends to do

Returns

resolves true when every requested permission is granted

startAdvertising

public static AsyncResource<Boolean> startAdvertising(String serviceId, String localName, TransportStrategy strategy)

Starts advertising this device so peers running the same service id can find it.

The service id must match exactly on both sides. On iOS it also becomes the Bonjour service type, which the platform restricts to fifteen characters of lowercase letters, digits and hyphens – so a reverse-DNS string works on Android and is rejected on iOS. Pick a short one.

Parameters

serviceId String
the service both ends agreed on
localName String
the name to show peers
strategy TransportStrategy
the topology to use; must match on both sides

Returns

resolves true once the platform is advertising

stopAdvertising

public static void stopAdvertising()
Stops advertising. Idempotent; existing connections stay open.

startDiscovery

public static AsyncResource<Boolean> startDiscovery(String serviceId, TransportStrategy strategy)
Starts looking for peers advertising the same service id. Sightings arrive as TransportListener.endpointFound.

Parameters

serviceId String
the service both ends agreed on
strategy TransportStrategy
the topology to use; must match on both sides

Returns

resolves true once the platform is discovering

stopDiscovery

public static void stopDiscovery()
Stops discovery. Idempotent; existing connections stay open.

requestConnection

public static AsyncResource<Boolean> requestConnection(Endpoint endpoint, String localName)

Asks a discovered endpoint to connect.

The resource here resolves once the request has been sent, which is not the same as being connected: the far side still has to accept, and that answer arrives as TransportListener.connected or TransportListener.connectionFailed.

Parameters

endpoint Endpoint
the peer to ask
localName String
the name to show them

Returns

resolves true once the request has been sent

send

public static AsyncResource<Boolean> send(Endpoint endpoint, Payload payload)
Sends a payload to one connected endpoint.

Parameters

endpoint Endpoint
the recipient
payload Payload
what to send

Returns

resolves true once the payload is handed to the platform. Delivery is reported by TransportListener.payloadProgress.

send

public static AsyncResource<Boolean> send(Endpoint[] endpoints, Payload payload)
Sends a payload to several connected endpoints at once, which both platforms do more efficiently than one call each.

Parameters

endpoints Endpoint[]
the recipients
payload Payload
what to send

Returns

resolves true once the payload is handed to the platform

cancel

public static void cancel(int payloadId)

Cancels an in-flight payload. Idempotent.

The send reaches PayloadStatus.CANCELED on this side, and a transfer the platform can still recall is recalled – which for a file is every byte not yet sent, on all three implementations.

A BYTE payload is a different matter, and the same on every one of them: it is handed to the platform whole, and no platform offers a handle to take it back. Cancelling one that has already been accepted stops this side reporting it as delivered, but the peer may receive it anyway. Cancel a byte payload to stop waiting on it, not to prevent its arrival.

Parameters

payloadId int
the id from Payload.getId()

disconnect

public static void disconnect(Endpoint endpoint)
Disconnects one endpoint. Idempotent.

Parameters

endpoint Endpoint
the peer to drop

stop

public static void stop()
Stops advertising and discovery and drops every connection. Call it when the feature’s UI closes: both platforms keep the radios busy until something says stop.

addTransportListener

public static void addTransportListener(TransportListener l)
Registers a listener. Callbacks arrive on the EDT.

Parameters

l TransportListener
the listener to add

removeTransportListener

public static void removeTransportListener(TransportListener l)
Removes a listener added by addTransportListener.

Parameters

l TransportListener
the listener to remove