原文:https://developer.android.google.cn/guide/topics/connectivity/wifi-aware
http://androidxref.com/9.0.0_r3/xref/frameworks/base/wifi/java/android/net/wifi/aware/
Wi-Fi感知功能使运行Android 8.0(API级别26)及更高版本的设备能够发现彼此并直接连接,而无需它们之间的任何其他类型的连接Wi-Fi感知也称为邻居感知网络(NAN)。
Wi-Fi感知网络的工作原理是与相邻设备形成群集,或者如果设备是某个区域中的第一个设备,则创建新群集此群集行为适用于整个设备,并由Wi-Fi感知系统服务管理;应用程序无法控制群集行为应用程序使用Wi-Fi-Aware api与Wi-Fi-Aware系统服务通信,后者管理设备上的Wi-Fi-Aware硬件。
支持Wi-Fi的API允许应用程序执行以下操作:
与蓝牙连接相比,支持Wi-Fi的网络连接支持更长距离的更高吞吐量这些类型的连接对于在用户之间共享大量数据的应用程序非常有用,例如照片共享应用程序。
要将应用程序设置为使用Wi-Fi感知发现和网络,请执行以下步骤:
1.请求应用程序清单中的以下权限:
<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_FINE_LOCATION" />
2.使用PackageManager API检查设备是否支持Wi-Fi感知,如下所示:
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE);
3.检查Wi-Fi感知当前是否可用Wi-Fi感知可能存在于设备上,但由于用户已禁用Wi-Fi或位置,因此目前可能无法使用。根据其硬件和固件功能,如果使用Wi-Fi Direct、SoftAP或tethering,某些设备可能不支持Wi-Fi感知要检查Wi-Fi Aware当前是否可用,请调用isAvailable()。
Wi-Fi感知的可用性可以随时更改。你的应用应该注册一个广播接收器来接收操作WIFI-AWARE-STATE-CHANGED
,当可用性改变时发送当您的应用程序接收到广播意图时,它应该丢弃所有现有会话(假设Wi-Fi感知服务被中断),然后检查可用性的当前状态并相应地调整其行为。例如:
WifiAwareManager wifiAwareManager =
(WifiAwareManager)context.getSystemService(Context.WIFI_AWARE_SERVICE)
IntentFilter filter =
new IntentFilter(WifiAwareManager.ACTION_WIFI_AWARE_STATE_CHANGED);
BroadcastReceiver myReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// discard current sessions
if (wifiAwareManager.isAvailable()) {
...
} else {
...
}
}
};
context.registerReceiver(myReceiver, filter);
要开始使用Wi-Fi感知,您的应用程序必须通过调用attach()获得一个WifiAwareSession。此方法执行以下操作:
如果应用程序连接成功,系统将执行onAttached()回调此回调提供一个WifiAwareSession对象,应用程序应将其用于所有后续会话操作应用程序可以使用会话发布服务或订阅服务。
应用程序应该只调用attach()一次。如果您的应用程序多次调用attach(),应用程序将为每个调用接收不同的会话,每个会话都有自己的名称空间。这在复杂的场景中可能有用,但通常应该避免。
要使服务可被发现,请调用publish()方法,该方法接受以下参数:
下面是一个例子:
PublishConfig config = new PublishConfig.Builder()
.setServiceName(“Aware_File_Share_Service_Name”)
.build();
awareSession.publish(config, new DiscoverySessionCallback() {
@Override
public void onPublishStarted(PublishDiscoverySession session) {
...
}
@Override
public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
...
}
}, null);
如果发布成功,则调用onPublishStarted()回调方法。
发布后,当运行匹配订阅服务器应用的设备移动到发布设备的Wi-Fi范围内时,订阅服务器将发现该服务当订阅服务器发现发布服务器时,发布服务器不会收到通知;但是,如果订阅服务器向发布服务器发送消息,则发布服务器会收到通知发生这种情况时,将调用onMessageReceived()回调方法可以使用此方法中的PeerHandle参数将消息发送回订阅服务器或创建到订阅服务器的连接。
要停止发布服务,请调用DiscoverySession.close()发现会话与其父WifiAwareSession关联如果父会话已关闭,则其关联的发现会话也将关闭虽然丢弃的对象也会关闭,但系统不保证何时关闭范围外会话,因此建议显式调用close()方法。
要订阅服务,请调用subscribe()方法,该方法接受以下参数:
下面是一个例子:
SubscribeConfig config = new SubscribeConfig.Builder()
.setServiceName("Aware_File_Share_Service_Name")
.build();
awareSession.subscribe(config, new DiscoverySessionCallback() {
@Override
public void onSubscribeStarted(SubscribeDiscoverySession session) {
...
}
@Override
public void onServiceDiscovered(PeerHandle peerHandle,
byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
...
}
}, null);
如果订阅操作成功,系统将在应用程序中调用onSubscribeStarted()回调由于可以在应用程序发现发布服务器后使用回调中的SubscribeDiscoverySession参数与该发布服务器通信,因此应保存此引用您可以通过在发现会话上调用updateSubscribe()随时更新订阅会话。
此时,您的订阅将等待匹配的发布服务器进入Wi-Fi范围发生这种情况时,系统将执行onServiceDiscovered()回调方法可以使用此回调中的PeerHandle参数发送消息或创建到该发布服务器的连接。
要停止订阅服务,请调用DiscoverySession.close()发现会话与其父WifiAwareSession关联如果父会话已关闭,则其关联的发现会话也将关闭虽然丢弃的对象也会关闭,但系统不保证何时关闭范围外会话,因此建议显式调用close()方法。
要将消息发送到其他设备,您需要以下对象:
要发送消息,请调用sendMessage()然后可能发生以下回调:
尽管PeerHandle是与对等方通信所必需的,但您不应将其作为对等方的永久标识符应用程序可以使用更高级别的标识符——嵌入到发现服务本身或后续消息中可以使用PublishConfig或SubscribeConfig的setMatchFilter()或setServiceSpecificInfo()方法在发现服务中嵌入标识符setMatchFilter()方法影响发现,而setServiceSpecificInfo()方法不影响发现。
在消息中嵌入标识符意味着修改消息字节数组以包含标识符(例如,作为第一对字节)。
Wi-Fi Aware支持两个Wi-Fi Aware设备之间的客户机-服务器网络。
要设置客户机-服务器连接,请执行以下操作:
ServerSocket ss = new ServerSocket(0);
int port = ss.getLocalPort();
使用ConnectivityManager在发布服务器上使用WifiAwareNetworkSpecifier请求支持Wi-Fi的网络,指定从订阅服务器发送的消息中获取的订阅服务器的发现会话和PeerHandle:
`NetworkSpecifier networkSpecifier = new WifiAwareNetworkSpecifier.Builder(discoverySession, peerHandle)
.setPskPassphrase(“somePassword”)
.setPort(port)
.build();
NetworkRequest myNetworkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
.setNetworkSpecifier(networkSpecifier)
.build();
ConnectivityManager.NetworkCallback callback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
…
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
…
}
@Override
public void onLost(Network network) {
…
}
};
ConnectivityManager connMgr.requestNetwork(networkRequest, callback);`
WifiAwareNetworkInfo peerAwareInfo = (WifiAwareNetworkInfo) networkCapabilities.getTransportInfo();
Inet6Address peerIpv6 = peerAwareInfo.getPeerIpv6Addr();
int peerPort = peerAwareInfo.getPort();
...
Socket socket = network.getSocketFactory().createSocket(peerIpv6, peerPort);
具有Wi-Fi RTT定位功能的设备可以直接测量到对等点的距离,并使用此信息限制Wi-Fi感知服务发现。
Wi-Fi RTT API允许使用其MAC地址或PeerHandle直接测距到Wi-Fi感知的对等端。
Wi-Fi感知的发现可以限制为仅发现特定地理围栏内的服务例如,您可以设置地理围栏,允许发现发布“感知文件共享服务名称”服务的设备,该服务距离不小于3米(指定为3000毫米),距离不超过10米(指定为10000毫米)。
要启用地理围栏,发布服务器和订阅服务器都必须采取以下操作:
当在geofence中发现对等服务时,将触发onServiceDiscoveredWithinRange回调,它提供到对等服务器的测量距离然后可以根据需要调用直接Wi-Fi RTT API,以便在以后测量距离。
关注公众号,获取更多开发必备知识