Android平台Wifi_Direct使用

Wifi_Direct是目前设备间最快的无线数据连接方式,速度可以达到40Mb/s。Google从Android 4.0(ICS)开始支持Wifi_Direct,而三星则更早些就在它自己的设备上支持了Wifi_Direct。几年来,Wifi_Direct的发展一直不温不火,但是目前市面上支持Wifi_Direct的设备并不是很多。
        从目前接触过得设备来看,三星I9100的Wifi_Direct功能其实使用了Wifi的硬件,所以,它在使用Wifi_Direct功能时,无法使用wifi;nexus7、Padfone infinite(A80)则有独立的硬件来支持Wifi_Direct,所以,在使用Wifi_Direct功能的时候,Wifi仍旧可用。
          Android framework提供了一个android.net.wifi.p2p包来提供对于Wifi_Direct的支持,其中包含了7个class和9个interface。其中WifiP2pManager为最核心的class,其他的class和interface都为它所用。
          使用Wifi_P2p需要的Permission有两个:

public static final String ACCESS_WIFI_STATE
Added in API level 1
Allows applications to access information about Wi-Fi networks
Constant Value: “android.permission.ACCESS_WIFI_STATE”
public static final String CHANGE_WIFI_STATE
Added in API level 1
Allows applications to change Wi-Fi connectivity state
Constant Value: “android.permission.CHANGE_WIFI_STATE”

Wifi_Direct的大致配对流程如下:

        1. WifiP2pManager.discoverPeers()开始扫描设备
        2. 获取扫描到的设备,选择其中一个设备进行连接配对WifiP2pManager.connect
        3. 配对成功后,根据WifiP2pInfo.isGroupOwner和WifiP2pInfo.groupOwnerAddress进行连接。
        流程图如下:
        个人认为Wifi_Direct配对需要注意的问题:
        1. Setting中启用/关闭WifiP2p按钮,应该是和Wifi的启用/关闭按钮放在一起了(其实,有些设备的实现中,Wifip2p使用的就是wifi的硬件),所以使用WifiP2p功能需要开启Wifi。
        2. Setting中BlueTooth有一个“让自己可见”的按钮,而Wifi_Direct没有这样的设置,仅提供了一个启动scan的按钮。本人尚未明确在未启动scan的情况下,设备对于其他wifi_direct是否是可见的,但是可以明确scan中的wifi_direct设备对其他设备来说是可见的。所以,建议需要进行配对的两台Wifi_Direct设备都进行scan。
        3. 配对成功的前提条件是:进行配对的两台设备都必须能够扫描到对方。所以,两台设备都进行scan操作的根本原因在这里。
        4. 开发者无法决定GroupOwner是哪台设备,但是可以通过WifiP2pConfig.groupOwnerIntent参数进行建议。
        从测试的结果来说,Wifi_Direct的表现受具体设备的影响很大,配对的速度也有较大差异,从10秒到2分钟甚至更久。大概的来说,nexus7成功的概率较高,个人感觉可以达到70%的成功率,Padfone infinite(A80)的成功率在50%以下。
         为了兼容传统的Wifi设备,Wifi_Direct其实还存在另一种使用方式,暂且称为兼容模式。兼容模式的特点在于,只需要担任GroupOwner的设备支持Wifi_Direct,而其他设备只需要支持传统的Wifi就可以了(个人觉得其实这种使用模式很像Android的便携热点功能)。
         操作流程为:
         1. 支持Wifi_Direct的设备创建group,WifiP2pManager.createGroup(),成为GroupOwner。
         2.  其他设备扫描Wifi_Direct设备创建group后产生的Wifi热点并连接即可。
         兼容模式存在的一个问题是:因为作为group member的设备是使用Wifi硬件接入到group中,所以会导致member进行wifi 热点切换以及网络中断,可能对正在进行的网络操作造成影响,而group owner则不存在这个问题。另外,而WifiP2p配对的使用方式,WifiP2p和Wifi可以独立运作,相互不受影响。
          但是,兼容模式因为省去了扫描和配对的过程,所以建立连接的成功率明显提升,并且建立连接的速度要快不少(具体时间比较随机)。
          从个人的使用感觉来讲,这WifiP2p这套API接口高度的异步化,API都需要以回调的方式获取操作结果(包内interface比较多的原因就在于此)。更加麻烦的是,几个关键API(例如WifiP2pManager.connect)的回调获取到的结果仅仅是执行是否开始,真正的结果还得注册broadcast receiver,通过监听广播来获得,才能进行下一步操作。异步的设计提高了代码的逻辑复杂度。
         使用NFC来实现WifiP2p的连接:
         1. 使用NFC将owner设备创建的group的SSID和密码传递给member设备
         2. owner开始监听指定端口,等待member的连接
         3. member接收到nfc传递过来的数据后,根据SSID和密码连接到group
         4. 连接成功以后,过去owner设备的ip地址(获取gateway ip即可),连接到owner的指定端口
          常见问题:
          1. WifiP2p相关的广播有哪些,各自有哪些参数?
WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION:当WifiP2p扫描开始或者停止时,触发该广播
该广播包含一个int型extra, key为WifiP2pManager.EXTRA_DISCOVERY_STATE,其值为WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED或者WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED.
WifiP2pManager.WIFI_P2P_STATE_CHANGED_ATIONIC:当WifiP2p状态发生变化时触发(如果WifiP2p可用,那么当BroadcastReceiverregister时,也会收到该广播)
该广播包含一个int型extra,key为WifiP2pManager.EXTRA_WIFI_STATE,其值为WifiP2pManager.WIFI_P2P_STATE_ENABLED或者WifiP2pManager.WIFI_P2P_STATE_DISABLED。
WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:当设备的WifiP2p状态发生变化时触发广播(如果WifiP2p可用,那么当BroadcastReceiverregister时,也会收到该广播)
该广播包含一个类型为WifiP2pDevice的extra,key为WifiP2pManager.EXTRA_WIFI_P2P_DEVICE.
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION:当WifiP2p扫描时,发现device列表发生变化时,触发该广播
该广播不含extra,开发者应该接收到此广播后,调用WifiP2pManager.requestPeers()函数查询当前设别列表。
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION:当WifiP2p的group发生变化时,触发该广播。
该广播包含两个extra:
key:WifiP2pManager.EXTRA_NETWORK_INFO,其值为NetworkInfo类型。
key:WifiP2pManager.EXTRA_P2P_INFO,其值为WifiP2pInfo类型。
PS:这里的WifiP2p group发生变化包含如下情况:
1. 建立group
2. member加入到group
3. member退出group
4. 关闭group
        2. 如何获得WifiP2pGroupInfo,它有什么用?
WifiP2pManager.requestGroupInfo()函数,可以获取GroupInfo,较为有用的api有:
1. GroupInfo.getClientList()可以获得连接到group的member列表
2. GroupInfo.getNetWorkName()可以获得group的wifi热点名称(SSID)
3. GroupInfo.getPassphrase() 可以获得连接到wifi 热点的密码
        3. 如何获得WifiP2pInfo?
可以从WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION广播中的extra中获取
也可以从WifiP2pManager.requestConnectionInfo()函数获取。
        4. 如何防止配对产生的提示框?
在不修改framework的情况下,本人暂时为找到可行的方案。
这个提示狂是由系统提供的,具体表现视设备而定。nexus只在第一次配对的时候弹出,而A80每一次配对都会弹出。
但是,使用兼容模式使用Wifi_Direct是没有提示框的。
         5. 如何实现wifi热点的连接?
 经过测试,在A80上,如下代码可以实现连接到热点。

  1. // build a wifi config
  2. final WifiConfiguration config = new WifiConfiguration();
  3. config.allowedAuthAlgorithms.clear();
  4. config.allowedPairwiseCiphers.clear();
  5. config.allowedGroupCiphers.clear();
  6. config.allowedKeyManagement.clear();
  7. config.allowedProtocols.clear();
  8. config.SSID = “\”” + ssid + “\””;<span style=“color:#009900;”>//设定ssid</span>
  9. config.preSharedKey = “\”” + pw + “\””;<span style=“color:#009900;”>//设定密码</span>
  10. config.hiddenSSID = false;
  11. config.status = WifiConfiguration.Status.ENABLED;
  12. config.priority = 1;
  13. config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
  14. config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
  15. config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
  16. config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
  17. config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
  18. config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
  19. config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
  20. config.allowedPairwiseCiphers.set(3);
  21. config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
  22. config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
  23. // connect to ap
  24. int id = WifiManager.addNetwork(config);
  25. config.networkId = id;
  26. if (id != –1 && mWifiManager.enableNetwork(id, true)) {
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s