Wednesday, July 20, 2016

Connecting your App to a Wi-Fi Device

Posted by Rich Hyndman, Android Developer Advocate




With the growth of the Internet of Things, connecting Android applications to
Wi-Fi enabled devices is becoming more and more common. Whether you�re building
an app for a remote viewfinder, to set up a connected light bulb, or to control
a quadcopter, if it�s Wi-Fi based you will need to connect to a hotspot that may
not have Internet connectivity.



From Lollipop onwards the OS became a little more intelligent, allowing multiple
network connections and not routing data to networks that don�t have Internet
connectivity. That�s very useful for users as they don�t lose connectivity when
they�re near Wi-Fis with captive portals. Data routing APIs were added for
developers, so you can ensure that only the appropriate app traffic is routed
over the Wi-Fi connection to the external device.



To make the APIs easier to understand, it is good to know that there are 3 sets
of networks available to developers:


  • WiFiManager#startScan returns a list of available Wi-Fi networks. They are
    primarily identified by SSID.
  • WiFiManager#getConfiguredNetworks returns a list of the Wi-Fi networks
    configured on the device, also indexed by SSID, but they are not necessarily
    currently available.
  • ConnectivityManager#getAllNetworks returns a list of networks that are being
    interacted with by the phone. This is necessary as from Lollipop onwards a
    device may be connected to multiple networks at once, Wi-Fi, LTE, Bluetooth,
    etc� The current state of each is available by calling href="https://developer.android.com/reference/android/net/ConnectivityManager.html#getNetworkInfo(android.net.Network)">ConnectivityManager#getNetworkInfo
    and is identified by a network ID.


In all versions of Android you start by scanning for available Wi-Fi networks
with href="https://developer.android.com/reference/android/net/wifi/WifiManager.html#startScan()">WiFiManager#startScan,
iterate through the href="https://developer.android.com/reference/android/net/wifi/ScanResult.html">ScanResults
looking for the SSID of your external Wi-Fi device. Once you�ve found it you can
check if it is already a configured network using href="https://developer.android.com/reference/android/net/wifi/WifiManager.html#getConfiguredNetworks()">WifiManager#getConfiguredNetworks
and iterating through the href="https://developer.android.com/reference/android/net/wifi/WifiConfiguration.html">WifiConfigurations
returned, matching on SSID. It�s worth noting that the SSIDs of the configured
networks are enclosed in double quotes, whilst the SSIDs returned in href="https://developer.android.com/reference/android/net/wifi/ScanResult.html">ScanResults
are not.



If your network is configured you can obtain the network ID from the
WifiConfiguration object. Otherwise you can configure it using href="https://developer.android.com/reference/android/net/wifi/WifiManager.html#addNetwork(android.net.wifi.WifiConfiguration)">WifiManager#addNetwork
and keep track of the network id that is returned.



To connect to the Wi-Fi network, register a BroadcastReceiver that listens for
href="https://developer.android.com/reference/android/net/wifi/WifiManager.html#NETWORK_STATE_CHANGED_ACTION">WifiManager.NETWORK_STATE_CHANGED_ACTION
and then call href="https://developer.android.com/reference/android/net/wifi/WifiManager.html#enableNetwork(int,%20boolean)">WifiManager.enableNetwork
(int netId, boolean disableOthers), passing in your network ID. The
enableNetwork call disables all the other Wi-Fi access points for the next scan,
locates the one you�ve requested and connects to it. When you receive the
network broadcasts you can check with href="https://developer.android.com/reference/android/net/wifi/WifiManager.html#getConnectionInfo()">WifiManager#getConnectionInfo
that you�re successfully connected to the correct network. But, on Lollipop and
above, if that network doesn�t have internet connectivity network, requests will
not be routed to it.



Routing network requests



To direct all the network requests from your app to an external Wi-Fi device,
call href="https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network)">ConnectivityManager#setProcessDefaultNetwork
on Lollipop devices, and on Marshmallow call href="https://developer.android.com/reference/android/net/ConnectivityManager.html#bindProcessToNetwork(android.net.Network)">ConnectivityManager#bindProcessToNetwork
instead, which is a direct API replacement. Note that these calls require
android.permission.INTERNET; otherwise they will just return false.



Alternatively, if you�d like to route some of your app traffic to the Wi-Fi
device and some to the Internet over the mobile network:


  • For HTTP requests you can use href="https://developer.android.com/reference/android/net/Network.html#openConnection(java.net.URL)">Network#openConnection(java.net.URL),
    directly routing your request to this network.
  • For low-level socket communication, open a socket and call href="https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket)">Network#bindSocket(java.net.Socket),
    or alternatively use href="https://developer.android.com/reference/android/net/Network.html#getSocketFactory()">Network#getSocketFactory.


Now you can keep your users connected whilst they benefit from your innovative
Wi-Fi enabled products.

No comments:

Post a Comment