This is very simple and easy to use protocol, allowing you to discover other devices on a Wifi network that all agree on protocol implementation. This library lets you do so on Android with few lines of code.
This library uses a simple JSON protocol, over UDP (User Datagram Packets). UDP allows you to send packets over a Wifi network, including broadcasts which are sent to all connected devices.
When you send a discovery request, you broadcast a message that asks all devices on the network to respond, making them visible to you.
{
"type": "discover",
"version": 1
}
When you receive a discovery request, you can choose to send a response which makes you visible to the requester. This is sent directly to the requester, not as a broadcast.
{
"type": "response",
"version": 1
}
You can exchange short messages directly with entities. A payload object can contain whatever you'd like, the values need to be strings (even for numbers, booleans, etc.).
{
"payload": {
"entry1": "value1",
"entry2": "another value?"
}
}
The overall JSON needs to be 1024 bytes or less, including the brackets, quotes, etc.
The Gradle dependency is available via jCenter. jCenter is the default Maven repository used by Android Studio.
Add this to your module's build.gradle
file:
dependencies {
// ... other dependencies
compile 'com.afollestad:udpdiscovery:1.1.0'
}
This library makes managing these messages and broadcasts easy, along with parsing the data.
Discovering entities means finding other devices on that network.
Discovery.instance(this)
.discover(entity -> {
// Do something with the entity
});
This automatically broadcasts a discovery request, and waits for responses indefinitely.
You can manually send out further discovery requests with the refresh method:
Discovery.instance(this).refresh();
Responding to entities means sending responses for discovery requests. This makes you visible to the requester.
Discovery.instance(this)
.respond(entity -> {
// If you return true, a response is sent to the entity, making you visible
return true;
});
You can also choose to automatically respond to all, if you don't want to do any filtering.
Discovery.instance(this)
respondToAll();
As seen in the sample project, you can provide a second callback to the discover
and respond
methods to receive errors asynchronously. If these callbacks are not specified, exceptions are
thrown instead.
Discovery.instance(this)
.discover(entity -> {
// Entity discovered
}, throwable -> {
// Error related to discovery, or packet retrieval in general
})
.respond(entity -> {
// Discovery request received
return true;
}, throwable -> {
// Error related to discovery responses, or sending packets in general
});
Even respondToAll()
has an optional error handler parameter.
Notice that you can also chain methods.
You can to exchange short messages directly with entities.
Entity recipient = ...
Map<String, String> payload = new HashMap<>();
payload.put("body", "Hello!");
Discovery.instance(this)
.message(recipient, payload);
An optional third parameter accepts an error listener; without that, an exception is thrown if an error occurs during sending.
The overall transmission needs to be 1024 bytes or less. The above would look like this:
{"payload":{"body":"Hello!"}}
That's only 29 characters; since they are latin characters, they will directly translate to 29 UTF-8 bytes. But, payloads could increase in size quickly if you're not careful.
When you are done with the library, e.g. when your app closes, you should do cleanup.
Discovery.destroy();
I recommend doing this in onPause()
, and reinitializing in onResume()
when your app comes into
view again. You probably do not want to leak networking while your Activity
is in the background.
Any type of background networking needs to be done from a Service.