Class 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.bonjourplus 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.
-
Method Summary
Modifier and TypeMethodDescriptionstatic voidRegisters a listener.static voidcancel(int payloadId) Cancels an in-flight payload.static voiddisconnect(Endpoint endpoint) Disconnects one endpoint.static NearbyAvailabilityHow usable the transport is right now.static intThe largest byte payloadsend(Endpoint, Payload)accepts in one call.static booleantruewhen this port implements the nearby transport.static voidRemoves a listener added byaddTransportListener(TransportListener).static AsyncResource<Boolean> requestConnection(Endpoint endpoint, String localName) Asks a discovered endpoint to connect.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.static AsyncResource<Boolean> Sends a payload to several connected endpoints at once, which both platforms do more efficiently than one call each.static AsyncResource<Boolean> Sends a payload to one connected endpoint.static AsyncResource<Boolean> startAdvertising(String serviceId, String localName, TransportStrategy strategy) Starts advertising this device so peers running the same service id can find it.static AsyncResource<Boolean> startDiscovery(String serviceId, TransportStrategy strategy) Starts looking for peers advertising the same service id.static voidstop()Stops advertising and discovery and drops every connection.static voidStops advertising.static voidStops discovery.
-
Method Details
-
isSupported
public static boolean isSupported()truewhen this port implements the nearby transport. -
getAvailability
How usable the transport is right now.
Returns
the current availability, never null
-
getMaxPayloadSize
public static int getMaxPayloadSize()The largest byte payload
send(Endpoint, Payload)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
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: what the app intends to do
Returns
resolves
truewhen 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: the service both ends agreed onlocalName: the name to show peersstrategy: the topology to use; must match on both sides
Returns
resolves
trueonce the platform is advertising -
stopAdvertising
public static void stopAdvertising()Stops advertising. Idempotent; existing connections stay open. -
startDiscovery
Starts looking for peers advertising the same service id. Sightings arrive as
TransportListener.endpointFound(Endpoint).Parameters
serviceId: the service both ends agreed onstrategy: the topology to use; must match on both sides
Returns
resolves
trueonce the platform is discovering -
stopDiscovery
public static void stopDiscovery()Stops discovery. Idempotent; existing connections stay open. -
requestConnection
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(Endpoint)orTransportListener.connectionFailed(Endpoint, NearbyException).Parameters
endpoint: the peer to asklocalName: the name to show them
Returns
resolves
trueonce the request has been sent -
send
Sends a payload to one connected endpoint.
Parameters
endpoint: the recipientpayload: what to send
Returns
resolves
trueonce the payload is handed to the platform. Delivery is reported byTransportListener.payloadProgress(Endpoint, PayloadTransferUpdate). -
send
Sends a payload to several connected endpoints at once, which both platforms do more efficiently than one call each.
Parameters
endpoints: the recipientspayload: what to send
Returns
resolves
trueonce the payload is handed to the platform -
cancel
public static void cancel(int payloadId) Cancels an in-flight payload. Idempotent.
The send reaches
PayloadStatus.CANCELEDon 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: the id fromPayload.getId()
-
disconnect
Disconnects one endpoint. Idempotent.
Parameters
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
Registers a listener. Callbacks arrive on the EDT.
Parameters
l: the listener to add
-
removeTransportListener
Removes a listener added by
addTransportListener(TransportListener).Parameters
l: the listener to remove
-