Concluding our series about local multiplayer via WiFi, we are going to address the Android bug that prevents local hostname resolution, and we will see the aspects to consider when using directly IP addresses instead of host names.
At first, using the device IP address instead of its host name may seem like no big deal, but Apple has a good document on why in fact it's a really bad pratice.
In our specific case, there are 2 important aspects to take into consideration:
- The device has more than 1 network interface, and therefore more than 1 IP address (for example: 1 IP address for the WiFi network, and 1 IP address for the Cellular network)
- The device can be compatible with both IPv4 and IPv6, and therefore have both IPv4 and IPv6 addresses, but the server could be listening only on IPv4 or only on IPv6
Therefore, we cannot use directly the IP addresses returned by the zeroconf.watch function, because we don't know which IP address to use.
The solution here is that on the server side we first have to know whether the device is listgening on IPv4 or IPv6, and then advertise the IPv4 or IPv6 address of the WiFi interface on the Zeroconf TXT record, so the server setup will become something like:
var
SERVICE_TYPE = '_my-service._tcp.',
HOST_NAME = 'my host'
;
// Specify 0 as the port number, so that a random free port is used
wsserver.start(0, {
onStart: function (addr, port) {
var
interface,
ip_addresses
;
if (cordova.platformId === 'android') {
// On Android the WiFi interface name is wlan0
interface = 'wlan0';
} else if (cordova.platformId === 'ios') {
// On iOS the WiFi interface name is en0
interface = 'en0';
}
// Check whether we are listening on IPv4 or IPv6
if (/^[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}$/.test(addr)) {
ip_addresses = 'ipv4Addresses';
} else {
ip_addresses = 'ipv6Addresses';
}
// Call getInterfaces in order to know the IP addresses of each network interface
wsserver.getInterfaces(function(result) {
zeroconf.register(SERVICE_TYPE, 'local.', HOST_NAME, port, {
// Publish the correct IP address on the TXT record
server_ip: result[interface][ip_addresses][0]
}, function (result) {
// Here we have successfully advertised the service
});
});
},
// Other server stuff...
});
For the client side, remember that we are working around a bug that is specific to Android, so let's treat only the Android platform as a special case, like this:
var connection;
zeroconf.watch(SERVICE_TYPE, 'local.', function (result) {
var
service = result.service,
hostname,
url
;
if (result.action === 'added') {
if (cordova.platformId === 'android') {
// On Android use the IP address published on the TXT record
hostname = service.txtRecord.server_ip;
} else {
// Remove any trailing dots from the hostname
hostname = service.hostname.replace(/[.]+$/g, '');
}
url = ['ws://', hostname, ':', service.port, '/'].join('');
connection = new WebSocket(url);
connection.onopen = function() {
// Now the client is connected
}
}
});
And at last, now we have a multi-platform connection that works on both iOS and Android.
We are going to implement WiFi local multiplayer on the next version of Dawn Of Ultra Pong, so stay tuned.
Comments !