Wi-Fi Aware, also known as Neighbor Awareness Networking or NAN, provides devices running the Android O Developer Preview with the appropriate hardware to discover and connect directly to each other via Wi-Fi Aware without any other type of connectivity between them, such as Wi-Fi Access Point or Cellular.
Wi-Fi Aware networking works by forming clusters with neighboring devices, or by creating a new cluster if the device is the first one in an area. This clustering behavior is device-wide—apps have no control over clustering behavior—and the behavior is managed by the Wi-Fi Aware system service. Apps use the Wi-Fi Aware APIs to talk to the Wi-Fi Aware system service which, in turn, manages the Wi-Fi Aware hardware on the device.
The Wi-Fi Aware APIs are available to apps that target Android O and let apps perform the following operations:
-
Discover other devices - The API has a mechanism for finding other devices in the vicinity. The process starts when one device publishes a discoverable service. Then, when a device subscribes to one or more services and enters the publisher's Wi-Fi range, the subscriber receives a notification that a matching publisher has been discovered. After the subscriber discovers a publisher, the subscriber can either send a short message or establish a network connection with the discovered device.
-
Create a network connection - After two devices have discovered each other, either through Wi-Fi Aware discovery or some other mechanism like Bluetooth or BLE, they can create a bi-directional Wi-Fi Aware network connection without an access point.
Wi-Fi Aware network connections are more reliable than Wi-Fi P2P connections and support higher throughput rates across longer distances than Bluetooth connections. These types of connections are useful for apps that share data between users, such as photo-sharing apps.
Initial setup
To set up your app to use Wi-Fi Aware, perform the following steps:
-
Request the following permissions in your app's manifest:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-
Check if the device supports Wi-Fi Aware by calling the
PackageManageras shown below:context.getPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
-
Check if Wi-Fi Aware is currently available. Wi-Fi Aware may exist on the device, but may not be currently available because the user has disabled Wi-Fi. Depending on their hardware and firmware capabilities, some devices may not support Wi-Fi Aware if Wi-Fi Direct, SoftAP, or tethering is in use. To check whether Wi-Fi Aware is currently available, call
isAvailable().The availability of Wi-Fi Aware can change at any time. Your app should register a
BroadcastReceiverto receiveACTION_WIFI_AWARE_STATE_CHANGED, which is sent whenever availability changes. When your app receives the broadcast intent, the app should check the current state of availability and adjust its behavior accordingly. For example:IntentFilter filter = new IntentFilter(WifiAwareManager.WIFI_AWARE_STATE_CHANGED_ACTION); BroadcastReceiver myReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { if (WifiAwareManager.isAvailable()) { ... } else { ... } } }; context.registerReceiver(myReceiver, filter);For more information, see Broadcasts.
Obtain a session
To start using Wi-Fi Aware, your app must obtain a
WifiAwareSession by calling
attach(). This method
does the following:
- Turns on the Wi-Fi Aware hardware.
- Forms a cluster if none exists.
- Creates a Wi-Fi Aware session with a unique namespace that acts as a container for all discovery sessions created within it.
If the app attaches successfully, the system executes the
onAttached() callback.
This callback provides a WifiAwareSession object
that your app should use for all further session operations. An app can now use
the session to publish a service or subscribe to a
service.
Your app should call
attach() only once. If
you call attach()
multiple times, your app receives different sessions, each with its own
namespace. This could be useful in complex scenarios, but should generally be
avoided.
Publish a service
To make a service discoverable, call the
publish() method, which
takes the following parameters:
PublishConfig- specifies the name of the service and other configuration properties, such as match filter.DiscoverySessionCallback- specifies the actions to execute when events occur, such as when the subscriber receives a message.
Here's an example:
PublishConfig config = new PublishConfig.Builder()
.setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
.build();
mAwareSession.publish(config, new DiscoverySessionCallback() {
@Override
public void onPublishStarted(PublishDiscoverySession session) {
...
}
@Override
public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
...
}, null);
If publication succeeds, then the
onPublishStarted()
callback method is executed.
At this point, when devices running matching subscriber apps move into the Wi-Fi
range of the publishing device, the subscribers discover the service. When a
subscriber discovers a publisher, the publisher doesn't receive a notification.
If the subscriber sends a message to the publisher, however, then the publisher
receives a notification. When that happens, the
onMessageReceived()
callback method is executed. You can use the
PeerHandle argument from this method to send a
message back to the subscriber or create a
connection to it.
To stop publishing the service, call DiscoverySession.close().
Discovery sessions are associated with their parent WifiAwareSession. If the parent session is closed, its
associated discovery sessions are also closed. However, the system doesn't
guarantee when out-of-scope sessions are closed, so we recommend that you
manually call DiscoverySession.close().
Subscribe to a service
To subscribe to a service, call the
subscribe() method,
which takes the following parameters:
-
SubscribeConfig- specifies the name of the service to subscribe to and other configuration properties, such as match filter. DiscoverySessionCallback- specifies the actions to execute when events occur, such as when a publisher is discovered.
Here's an example:
SubscribeConfig config = new SubscribeConfig.Builder()
.setServiceName(AWARE_FILE_SHARE_SERVICE_NAME)
.build();
mAwareSession.subscribe(config, new DiscoverySessionCallback() {
@Override
public void onSubscribeStarted(SubscribeDiscoverySession session) {
....
}
@Override
public void onServiceDiscovered(PeerHandle peerHandle,
byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
...
}
}, null);
If the subscribe operation succeeds, the system executes the
onSubscribeStarted()
callback in your app. Because you can use the
SubscribeDiscoverySession argument in the
callback to communicate with a publisher after your app has discovered one, you
should save this reference. You can update the description at any time by
calling
updateSubscribe()
on the discovery session.
At this point, your subscription waits for matching publishers to come into
Wi-Fi range. When this happens, the system executes the
onServiceDiscovered()
callback method. You can use the PeerHandle
argument from this callback to send a message or
create a connection to that publisher.
To stop subscribing to a service, call DiscoverySession.close().
Discovery sessions are associated with their parent WifiAwareSession. If the parent session is closed, its
associated discovery sessions are also closed. However, the system doesn't
guarantee when out-of-scope sessions are closed, so we recommend that you
manually call DiscoverySession.close().
Send a message
To send a message to another device, you need the following objects:
-
A
DiscoverySession. This object allows you to callsendMessage(). Your app gets aDiscoverySessionby either publishing a service or subscribing to a service. -
The other device's
PeerHandle, so you know where to send the message. Your app gets another device'sPeerHandlein one of two ways:- Your app publishes a service. Then, when it receives a message from a
subscriber, your app gets the subscriber's
PeerHandlefrom theonMessageReceived()callback. - Your app subscribes to a service. Then, when it discovers a matching
publisher, your app gets the publisher's
PeerHandlefrom theonServiceDiscovered()callback.
- Your app publishes a service. Then, when it receives a message from a
subscriber, your app gets the subscriber's
To send a message, call
sendMessage(). The
following callbacks might then occur:
- When the message is successfully received by the peer, the system executes the
onMessageSendSucceeded()callback in the sending app. - When the peer receives a message, the system executes the
onMessageReceived()callback in the receiving app.
Create a connection
There are two ways to create a Wi-Fi Aware connection. The first way assumes
that you have used Wi-Fi Aware to discover the other device and you have the
other device's PeerHandle. The second way
assumes that you have discovered the other device's MAC address through some
other mechanism, such as Bluetooth
or BLE. This is known as
out-of-band discovery, or OOB.
Regardless of which method you choose, there are always two devices in a Wi-Fi Aware connection: an initiator and a responder. If you're using Wi-Fi Aware discovery, then the roles are fixed and don't need to be explicitly specified: the subscriber is the initiator and the publisher is the responder. If you are using out-of-band discovery, then the devices need to negotiate these roles on their own.
To create a connection, complete the following sequence of steps:
-
Create a network specifier:
-
For Wi-Fi Aware discovery, call either
DiscoverySession.createNetworkSpecifierOpen()orDiscoverySession.createNetworkSpecifierPassphrase()from the publisher and subscriber. -
For OOB discovery, call either
WifiAwareSession.createNetworkSpecifierOpen()orWifiAwareSession.createNetworkSpecifierPassphrase()from both devices.
The responder isn't required to provide a MAC address or a
PeerHandle. If no MAC address orPeerHandleis specified, the device accepts all connection requests. -
-
Build a network request, setting the transport mechanism to
TRANSPORT_WIFI_AWARE:NetworkRequest myNetworkRequest = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE) .setNetworkSpecifier(networkSpecifier) .build(); -
Call
requestNetwork()and provide the following callback methods:mCallback = new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { ... } @Override public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { ... } @Override public void onLost(Network network) { ... } }; mConnMgr.requestNetwork(networkRequest, mCallback);The appropriate callback methods are executed when the network connection is available, changed, or lost.
-
When you're finished with the network connection, call
unregisterNetworkCallback().