WLAN 感知概览(Wi-Fi Aware)

原文: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允许应用程序执行以下操作:

  • 发现其他设备:这个API有一个查找其他附近设备的机制当一个设备发布一个或多个可发现的服务时,进程开始然后,当设备订阅一个或多个服务并进入发布服务器的Wi-Fi范围时,订阅服务器接收到已发现匹配发布服务器的通知订户发现发布服务器后,可以发送短消息或与发现的设备建立网络连接设备可以同时是发布者和订阅者。
  • 创建网络连接:在两个设备发现彼此后,它们可以创建一个双向Wi-Fi感知网络连接,而无需访问点。

与蓝牙连接相比,支持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。此方法执行以下操作:

  • 打开 Wi-Fi Aware hardware.
  • 加入或形成Wi-Fi感知群集
  • 创建具有唯一命名空间的Wi-Fi感知会话,该命名空间充当在其中创建的所有发现会话的容器。

如果应用程序连接成功,系统将执行onAttached()回调此回调提供一个WifiAwareSession对象,应用程序应将其用于所有后续会话操作应用程序可以使用会话发布服务或订阅服务。

应用程序应该只调用attach()一次。如果您的应用程序多次调用attach(),应用程序将为每个调用接收不同的会话,每个会话都有自己的名称空间。这在复杂的场景中可能有用,但通常应该避免。

发布服务

要使服务可被发现,请调用publish()方法,该方法接受以下参数:

  • PublishConfig指定服务的名称和其他配置属性,如匹配筛选器。
  • DiscoverySessionCallback指定事件发生时要执行的操作,例如当订阅服务器接收到消息时。

下面是一个例子:

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指定要订阅的服务的名称和其他配置属性,如匹配筛选器。
  • DiscoverySessionCallback指定事件发生时(如发现发布服务器时)要执行的操作。

下面是一个例子:

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()方法。

发送消息

要将消息发送到其他设备,您需要以下对象:

  • 一个DiscoverySession。 这个对象允许您拨打的sendMessage()。 您的应用程序或者通过发布服务或订阅服务得到了DiscoverySession。
  • 其它设备的PeerHandle,路由消息。 您的应用程序得到另一台设备的PeerHandle两种方法之一:
    • 你的应用程序发布服务并从订阅服务器接收消息您的应用程序从onMessageReceived()回调获取订阅者的PeerHandle。
    • 您的应用程序订阅服务。然后,当它发现一个匹配的发布者时,应用程序从onServiceDiscovered()回调获取发布者的PeerHandle。

要发送消息,请调用sendMessage()然后可能发生以下回调:

  • 当对等端成功接收到消息时,系统将调用发送应用程序中的onMessageSendSucceeded()回调。
  • 当对等方收到消息时,系统调用接收应用程序中的onMessageReceived()回调。

尽管PeerHandle是与对等方通信所必需的,但您不应将其作为对等方的永久标识符应用程序可以使用更高级别的标识符——嵌入到发现服务本身或后续消息中可以使用PublishConfig或SubscribeConfig的setMatchFilter()或setServiceSpecificInfo()方法在发现服务中嵌入标识符setMatchFilter()方法影响发现,而setServiceSpecificInfo()方法不影响发现。
在消息中嵌入标识符意味着修改消息字节数组以包含标识符(例如,作为第一对字节)。

创建连接

Wi-Fi Aware支持两个Wi-Fi Aware设备之间的客户机-服务器网络。
要设置客户机-服务器连接,请执行以下操作:

  • 使用Wi-Fi感知发现发布服务(在服务器上)和订阅服务(在客户端上)。
  • 一旦订阅服务器发现发布服务器,请从订阅服务器向发布服务器发送消息。
  • 在发布服务器设备上启动服务器套接字,然后设置或获取其端口:
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);`

  • 使用与发布服务器相同的方法在订阅服务器上请求Wi-Fi感知网络创建NetworkSpecifier时不要指定端口当网络连接可用、更改或丢失时,将调用相应的回调方法。
  • 一旦在订阅服务器上调用onAvailable()方法,就可以使用网络对象打开一个套接字以与发布服务器上的服务器套接字通信,但您需要知道服务器套接字的IPv6地址和端口您可以从onCapabilitySchanged()回调函数中提供的NetworkCapabilities对象获取这些信息:
WifiAwareNetworkInfo peerAwareInfo = (WifiAwareNetworkInfo) networkCapabilities.getTransportInfo();
Inet6Address peerIpv6 = peerAwareInfo.getPeerIpv6Addr();
int peerPort = peerAwareInfo.getPort();
...
Socket socket = network.getSocketFactory().createSocket(peerIpv6, peerPort);
  • 完成网络连接后,请调用unregisterNetworkCallback()。

测距对等点和位置感知发现

具有Wi-Fi RTT定位功能的设备可以直接测量到对等点的距离,并使用此信息限制Wi-Fi感知服务发现。

Wi-Fi RTT API允许使用其MAC地址或PeerHandle直接测距到Wi-Fi感知的对等端。

Wi-Fi感知的发现可以限制为仅发现特定地理围栏内的服务例如,您可以设置地理围栏,允许发现发布“感知文件共享服务名称”服务的设备,该服务距离不小于3米(指定为3000毫米),距离不超过10米(指定为10000毫米)。

要启用地理围栏,发布服务器和订阅服务器都必须采取以下操作:

  • 发布服务器必须使用setRangingEnabled(true)在已发布的服务上启用范围设置。
    如果发布服务器不启用范围设置,则忽略订阅服务器指定的任何地理围栏约束,并执行常规发现,忽略距离。
  • 订阅服务器必须使用setMinDistanceMm和setMaxDistanceMm的某种组合指定地理围栏。
    对于这两个值,未指定的距离表示没有限制仅指定最大距离意味着最小距离为0。仅指定最小距离就意味着没有最大值。

当在geofence中发现对等服务时,将触发onServiceDiscoveredWithinRange回调,它提供到对等服务器的测量距离然后可以根据需要调用直接Wi-Fi RTT API,以便在以后测量距离。

发布了67 篇原创文章 · 获赞 62 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43804080/article/details/102943828