赞
踩
Wi-Fi Direct®支持Wi-Fi设备相互直接连接,并非Android设备独有的,是WIfi联盟提供的一种设备与设备之间直接联网通讯的技术,实现点对点的连接,我们常说的Wifi P2P连接。
最大的特点和优势就是无需接入网络就可连接设备
有了Wi-Fi Direct,手机、摄像头、打印机、个人电脑和游戏设备无需互联网连接,就能够建立自己的Wi-Fi网络。Wi-Fi Direct设备相互连接后,通过设备设置,就可快速简便地传送或显示内容、玩游戏以及分享应用。这些设备可以一对一地连接,或者几个设备形成的一组设备可以同时连接。由于无需接入点或互联网连接,因此设备在哪里,哪里就有Wi-Fi Direct网络。设备之间建立的Wi-Fi Direct连接对包括Miracast®在内的很多应用而言属于底层技术。诸如智能手机、摄像头、打印机、电视机、个人电脑、游戏机等成千上万的设备均已通过认证。
随时随地建立连接
即使附近没有Wi-Fi网络可用,Wi-Fi Direct设备之间也可以随时随地建立连接。Wi-Fi Direct设备向同一区域内的其他设备发送信号,让这些设备知道可以建立连接。用户可以查看可用设备并请求连接,也可以接收另一台设备发出的连接邀请。两个或更多个经过Wi-Fi Direct认证的设备直接连接时,会使用Wi-Fi Protected Setup™形成一个Wi-Fi Direct设备组。
Android API 概览
WifiP2pManager 类提供的方法使您可以在设备上与 WLAN 硬件交互,以执行发现和连接对等设备等操作。可执行的操作如下:
initialize() | 通过 WLAN 框架注册应用。必须先调用此方法,然后再调用任何其他 WLAN P2P 方法。 |
---|---|
connect() | 启动与具有指定配置的设备的对等连接。 |
cancelConnect() | 取消任何正在进行的对等群组协商。 |
requestConnectInfo() | 请求设备连接信息。 |
createGroup() | 以群组所有者的身份,使用当前设备创建对等群组。 |
removeGroup() | 移除当前对等群组。 |
requestGroupInfo() | 请求对等群组信息。 |
discoverPeers() | 启动对等设备发现 |
requestPeers() | 请求已发现对等设备的当前列表。 |
WifiP2pManager 方法使您可以在侦听器中进行传递,以便 WLAN P2P 框架可以向您的 Activity 通知通话状态。下表介绍可用的侦听器接口和使用侦听器的相应 WifiP2pManager 方法调用:
侦听器接口 | 相关操作 |
---|---|
WifiP2pManager.ActionListener | connect()、cancelConnect()、createGroup()、removeGroup() 和 discoverPeers() |
WifiP2pManager.ChannelListener | initialize() |
WifiP2pManager.ConnectionInfoListener | requestConnectInfo() |
WifiP2pManager.GroupInfoListener | requestGroupInfo() |
WifiP2pManager.PeerListListener | requestPeers() |
WLAN P2P API 定义当发生特定 WLAN P2P 事件时会广播的 Intent,例如发现新的对等设备时,或设备的 WLAN 状态更改时。您可以通过创建处理这些 Intent 的广播接收器,在应用中注册接收这些 Intent:
Intent | 说明 |
---|---|
WIFI_P2P_CONNECTION_CHANGED_ACTION | 当设备的 WLAN 连接状态更改时广播。 |
WIFI_P2P_PEERS_CHANGED_ACTION | 当您调用 discoverPeers() 时广播。如果您在应用中处理此 Intent,则通常需要调用 requestPeers() 以获取对等设备的更新列表。 |
WIFI_P2P_STATE_CHANGED_ACTION | 当 WLAN P2P 在设备上启用或停用时广播。 |
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION | 当设备的详细信息(例如设备名称)更改时广播。 |
创建 WLAN P2P 应用涉及为应用创建并注册广播接收器、发现对等设备,连接到对等设备,以及将数据传输到对等设备。以下部分将介绍如何完成此操作。
初始设置
在使用 WLAN P2P API 之前,您必须确保您的应用可以访问硬件,并且设备支持 WLAN P2P API 协议。如果设备支持 WLAN P2P,您可以获得 WifiP2pManager 的实例,创建并注册广播接收器,然后开始使用 WLAN P2P API。
请求在设备上使用 WLAN 硬件的权限,同时声明您的应用在 Android 清单中具有正确的最低 SDK 版本:
<uses-sdk android:minSdkVersion="14" />
<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" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
检查 WLAN P2P 是否开启并受支持。您可以在广播接收器收到 WIFI_P2P_STATE_CHANGED_ACTION Intent 时,在接收器中检查此项。向您的 Activity 通知 WLAN P2P 的状态,并作出相应回应:
@Override
public void onReceive(Context context, Intent intent) {
...
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
// Wifi P2P is enabled
} else {
// Wi-Fi P2P is not enabled
}
}
...
}
获取和初始化P2P资源
获取 WifiP2pManager 的实例,并通过调用 initialize(),在 WLAN P2P 框架中注册您的应用。此方法会返回 WifiP2pManager.Channel,用于将您的应用连接到 WLAN P2P 框架。此外,您还应该通过 WifiP2pManager 和 WifiP2pManager.Channel 对象以及对 Activity 的引用,创建广播接收器实例。这样广播接收器便可通知 Activity 感兴趣的事件并进行相应更新。此外,您还可以操纵设备的 WLAN 状态(如有必要):
WifiP2pManager manager;
Channel channel;
BroadcastReceiver receiver;
...
@Override
protected void onCreate(Bundle savedInstanceState){
...
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
receiver = new WiFiDirectBroadcastReceiver(manager, mChannel, this);
...
}
创建 Intent 过滤器,然后添加与广播接收器检查内容相同的 Intent:
IntentFilter intentFilter;
...
@Override
protected void onCreate(Bundle savedInstanceState){
...
intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
...
}
在 Activity 的 onResume() 方法中注册广播接收器,然后在 Activity 的onPause() 方法中取消注册该接收器:
/* register the broadcast receiver with the intent values to be matched */
@Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, intentFilter);
}
/* unregister the broadcast receiver */
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
如要发现可连接的对等设备,请调用 discoverPeers(),以检测范围内的可用对等设备。对此功能的调用为异步操作,如果您已创建 WifiP2pManager.ActionListener,则系统会通过 onSuccess() 和 onFailure() 告知应用成功与否。onSuccess() 方法仅会通知您发现进程已成功,但不会提供有关其发现的实际对等设备(如有)的任何信息:
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
...
}
@Override
public void onFailure(int reasonCode) {
...
}
});
如果发现进程成功并检测到对等设备,则系统会广播 WIFI_P2P_PEERS_CHANGED_ACTION Intent,您可以在广播接收器中侦听该 Intent,以获取对等设备列表。当应用接收到 WIFI_P2P_PEERS_CHANGED_ACTION Intent 时,您可以通过 requestPeers() 请求已发现对等设备的列表。以下代码展示如何完成此项设置:
PeerListListener myPeerListListener;
...
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// request available peers from the wifi p2p manager. This is an
// asynchronous call and the calling activity is notified with a
// callback on PeerListListener.onPeersAvailable()
if (manager != null) {
manager.requestPeers(channel, myPeerListListener);
}
}
requestPeers() 方法也为异步操作,并可在对等设备列表可用时通过 onPeersAvailable()(定义见 WifiP2pManager.PeerListListener 接口)通知您的 Activity。onPeersAvailable() 方法为您提供 WifiP2pDeviceList,您可对其进行迭代以查找希望连接的对等设备。
获取可能对等设备的列表,且已确定您要连接的设备后,调用connect() 方法即可连接到相应设备。调用此方法需要使用 WifiP2pConfig 对象,其中包含要连接的设备的信息。您可以通过 WifiP2pManager.ActionListener 获知连接是否成功。以下代码展示如何创建与所需设备的连接:
//obtain a peer from the WifiP2pDeviceList WifiP2pDevice device; WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = device.deviceAddress; manager.connect(channel, config, new ActionListener() { @Override public void onSuccess() { //success logic } @Override public void onFailure(int reason) { //failure logic } });
当P2P连接完成后,IP地址是由DHCPServer分配的,一般是Group Owner所在的设备开启DHCPServer给自己和对端(GC端)分贝IP地址。
如果当前设置是GC(Group Client),那么可通过WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION广播直接拿到GO端的IP地址
if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { NetworkInfo networkInfo = (NetworkInfo) intent .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); WifiP2pInfo p2pInfo = (WifiP2pInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO); WifiP2pGroup p2pGroup = (WifiP2pGroup) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP); if (networkInfo.isConnected()) { device_addr[0] = p2pInfo.groupOwnerAddress.getHostAddress(); mController.setGroupModule(false); WifiP2pDevice device = p2pGroup.getOwner(); if (device != null && device.getWfdInfo() != null) { mPort = String.valueOf(device.getWfdInfo().getControlPort()); mIp = p2pInfo.groupOwnerAddress.getHostAddress(); } else { Log.d(TAG, "device or device wfdInfo is null"); } } }
如果当前设备是GO(Group Owner)那么就需要用其他方法获取到对端IP地址了,Android 原生未提供直接获取GC IP的方法
如果可以修改AOSP源码的话,可以通过DHCPServer给GC分配IP地址时,把地址给到当前的程序:
Android 源码:packages/modules/NetworkStack/src/android/net/dhcp/DhcpServer.java
transmitAck方法中添加以下code
private boolean transmitAck(@NonNull DhcpPacket packet, @NonNull DhcpLease lease, @NonNull MacAddress clientMac)
Intent notifyMiracast = new Intent(WIFI_P2P_IP_ADDR_CHANGED_ACTION);
notifyMiracast.putExtra(WIFI_P2P_PEER_IP_EXTRA,lease.getNetAddr().toString().substring(1));
notifyMiracast.putExtra(WIFI_P2P_PEER_MAC_EXTRA,lease.getHwAddr().toString());
Log.d(TAG,"sendBroadcast IP " + notifyMiracast.getStringExtra(WIFI_P2P_PEER_IP_EXTRA)
+ "MAC " + notifyMiracast.getStringExtra(WIFI_P2P_PEER_MAC_EXTRA));
mContext.sendBroadcast(notifyMiracast);
也可以读取ARP方法来获取IP
private String macAddressFromRoute(String macAddress){ String ipAddress = null; BufferedReader reader = null; try { reader = new BufferedReader(new FileReader("/proc/net/arp")); // Skip over the line bearing column titles String line = reader.readLine(); while ((line = reader.readLine()) != null) { String[] tokens = line.split("[ ]+"); if (tokens.length < 6) { continue; } // ARP column format is // Address HWType HWAddress Flags Mask IFace String ip = tokens[0]; String mac = tokens[3]; if (mac.equals(macAddress)) { ipAddress = ip; break; } } if (ipAddress == null) { loge("Did not find remoteAddress {" + macAddress+ "} in /proc/net/arp"); } } catch (FileNotFoundException e) { loge("Could not open /proc/net/arp to lookup mac address"); } catch (IOException e) { loge("Could not read /proc/net/arp to lookup mac address"); } finally { try { if (reader != null) { reader.close(); } } catch (IOException e) { // Do nothing } } return ipAddress; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。