使用Wi-Fi Direct技术可让具有硬件支持的设备在没有中间接入点的状况下进行直接互联。Android 4.0(API版本14)及之后的系统都提供了对Wi-Fi Direct的API支持。经过对这些API的使用,开发者能够实现支持Wi-Fi Direct的设备间进行相互探测和链接,从而得到较之蓝牙更远距离的高速数据通讯效果。对于诸如多人游戏、图片共享等须要在用户之间传输数据的应用而言,这一技术无疑是十分有价值的。html
关于Wi-Fi Direct的API函数的使用须要注意一下几个要点:
·用于探测(discover)对等设备(peers)、向对等设备发起请求(request)以及创建链接(connect)的方法定义在类WifiP2pManager中。
·经过设置监听器(Listener)能够获知WifiP2pManager中方法调用的成功与否。监听器以参数的形式传递给被调用的方法。
·当发现新对等设备或连接丢失的时候,Wi-Fi Direct系统(framework)以意向(Intent)的方式根据检测到的不一样事件作出相应的通知。android
开发中,以上三点的配合使用至关广泛。简单举个例子,定义一个监听器WifiP2pManager.ActionListener并调用函数discoverPeers(),当相应事件发生的时候就会在ActionListener.onSuccess()和ActionListener.onFailure()两个方法中获得通知。当discoverPeers()方法检测到了对等设备列表变化的时候,能够收到由系统广播(broadcast)发出一个WIFI_P2P_PEERS_CHANGED_ACTION意向。服务器
建立广播接收器以处理Wi-Fi Direct意向的基本步骤以下:
一、建立一个继承BroadcastReceiver类的新类。构造函数的参数分别传递WifiP2pManager,WifiP2pManager.Channel,以及在这个广播接收器中须要注册的活动(activity)。这是一种最多见的参数设置模式,它让广播接收器可以引发活动做出更新,同时又能在必要时使用Wi-Fi硬件和通讯信道。
二、在广播接收器的onReceive()函数中,针对感兴趣的特定意向能够执行相应的动做(actions)。例如,当广播接收器收到了意向WIFI_P2P_PEERS_CHANGED_ACTION,就能够调用requestPeers()方法来列举出当前探测到的对等设备。异步
建立Wi-Fi Direct应用:
完整的Wi-Fi Direct应用包含建立并注册广播接收器、检测对等设备、链接对等设备以及在对等设备间传输数据几个方面的功能。下面将详细介绍如何实现。
准备工做:在使用Wi-Fi Direct API以前,首先要确保应用程序可以访问硬件,而且设备支持Wi-Fi Direct协议。若是这些条件都知足,就能够获取一个WifiP2pManager实例,建立并注册广播接收器,最后就是使用Wi-Fi Direct API了。
在Android manifest文件中加入如下内容,容许使用Wi-Fi设备上的硬件并声明应用程序正确支持了调用API所需的最低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.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> socket
检查Wi-Fi Direct支持并已开启。推荐在广播接收器收到WIFI_P2P_STATE_CHANGED_ACTION意向的时候进行检测。检测结果须要通告相应的活动并作出处理:
@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 Direct is enabled
} else {
// Wi-Fi Direct is not enabled
}
}
...…
} async
在活动的onCreate()方法中获取WifiP2pManager对象的一个实例,经过该对象的initialize()方法向Wi-Fi Direct系统注册当前的应用程序。注册成功后,会返回一个WifiP2pManager.Channel,经过它,应用程序就能和Wi-Fi Direct系统交互。WifiP2pManager和WifiP2pManager.Channel对象以及一个活动的引用最后都被做为参数传递给自定义的广播接收器。这样,该活动就可以响应广播接收器的通知并做出相应的更新。固然,这样作也使程序具有了操纵设备Wi-Fi状态的能力:
WifiP2pManager mManager;
Channel mChannel;
BroadcastReceiver mReceiver;
......
@Override
protected void onCreate(Bundle savedInstanceState){
.…..
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);
mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
... ….
} ide
建立一个意向过滤器(intent filter),其中添加的意向种类和广播接收器中的保持一致:
IntentFilter mIntentFilter;
......
@Override
protected void onCreate(Bundle savedInstanceState){
......
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
......
}函数
在活动的onResume()方法中注册广播接收器,并在活动的onPause()方法中注销它:
/* register the broadcast receiver with the intent values to be matched */
@Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
}
/* unregister the broadcast receiver */
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
一旦成功获取WifiP2pManager.Channel并建立了广播接收器,应用程序就已经具有了使用Wi-Fi Direct相关函数和接收Wi-Fi Direct意向的能力。尽管放手使用WifiP2pManager为你提供的方法,让程序也拥有Wi-Fi Direct的特殊能力吧!oop
探测对等设备(Discovering peers)
调用discoverPeers()函数能够探测到有效距离内的对等设备。它是一个异步函数,调用成功与否会在程序所建立WifiP2pManager.ActionListener监听器的onSuccess()和onFailure()中给出通知。值得注意的是,onSuccess()方法只会对成功探测到对等设备这一事件作出通知,而并不会提供任何关于已发现的对等设备的具体信息:
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
.…..
}
@Override
public void onFailure(int reasonCode) {
.…..
}
}); this
当成功检测到对等设备存在的时候,系统会广播WIFI_P2P_PEERS_CHANGED_ACTION意向。程序接收到该意向后,经过调用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()方法一样是一个异步函数,当它准备好一份对等设备列表的时候,就会通知监听器WifiP2pManager.PeerListListener中定义的onPeersAvailable()方法。而onPeersAvailable()方法中所能获取到的对等设备列表以WifiP2pDeviceList形式存储,经过遍历这个列表能够选择出但愿链接的设备。
链接对等设备(Connecting to peers)
肯定了要链接的设备,还需调用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
}
});
传输数据(Transferring data)
链接一旦创建成功,数据传输也就是瓜熟蒂落的事情。如下是经过socket发送数据的基本步骤:
一、建立ServerSocket。它将被用于监听特定端口,等待客户端发起的链接请求。该操做须要在后台线程中实现。
二、建立客户端Socket。客户端经过ServerSocket对应的IP和端口链接到服务设备。
三、客户端向服务器发生数据。客户socket成功链接到服务socket后,就能以字节流的形式向服务器发生数据了。
四、服务器socket经过accept()方法等待客户端数据链接的到来。该方法在收到客户端数据以前一直处于阻塞状态。所以,须要在单独的线程中调用它。数据链接一旦创建,服务设备就能接收到客户端的数据。这时要作的就是施以相应的动做,例如将数据保存到文件,或者是直接显示到用户界面上,等等。
如下代码修改自SDK自带的示例Wi-Fi Direct Demo。它演示了如何创建一对客户端-服务器链接,并由客户端向服务器发送JPEG图片。若需完整的演示工程,只需编译并运行SDK示例Wi-Fi Direct Demo便可。
public static class FileServerAsyncTask extends AsyncTask {
private Context context;
private TextView statusText;
public FileServerAsyncTask(Context context, View statusText) {
this.context = context;
this.statusText = (TextView) statusText;
}
@Override
protected String doInBackground(Void... params) {
try {
/* Create a server socket and wait for client connections. This call blocks until a connection is accepted from a client */
ServerSocket serverSocket = new ServerSocket(8888);
Socket client = serverSocket.accept();
/*If this code is reached, a client has connected and transferred data Save the input stream from the client as a JPEG file */
final File f = new File(Environment.getExternalStorageDirectory() + "/"
+ context.getPackageName() + "/wifip2pshared-"
+ System.currentTimeMillis() + ".jpg");
File dirs = new File(f.getParent());
if (!dirs.exists())
dirs.mkdirs();
f.createNewFile();
InputStream inputstream = client.getInputStream();
copyFile(inputstream, new FileOutputStream(f));
serverSocket.close();
return f.getAbsolutePath();
} catch (IOException e) {
Log.e(WiFiDirectActivity.TAG, e.getMessage());
return null;
}
}
// Start activity that can handle the JPEG image
@Override
protected void onPostExecute(String result) {
if (result != null) {
statusText.setText("File copied - " + result);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + result), "image/*");
context.startActivity(intent);
}
}
}
On the client, connect to the server socket with a client socket and transfer data. This example transfers a JPEG file on the client device's file system:
Context context = this.getApplicationContext();
String host;
int port;
int len;
Socket socket = new Socket();
byte buf[] = new byte[1024];
...
try {
/* Create a client socket with the host, port, and timeout information.*/
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)), 500);
/* Create a byte stream from a JPEG file and pipe it to the output stream of the socket. This data will be retrieved by the server device. */
OutputStream outputStream = socket.getOutputStream();
ContentResolver cr = context.getContentResolver();
InputStream inputStream = null;
inputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg"));
while ((len = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
}
outputStream.close();
inputStream.close();
} catch (FileNotFoundException e) {
//catch logic
} catch (IOException e) {
//catch logic
}
/* Clean up any open sockets when done transferring or if an exception occurred. */
finally {
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
//catch logic
}
}
}
}
官方参考连接:http://developer.android.com/reference/android/net/wifi/p2p/WifiP2pManager.html
参考连接:http://blog.csdn.net/yichigo/article/details/8472570
代码下载连接:http://download.csdn.net/detail/klcf0220/5894381
http://www.apkbus.com/android-137269-1-1.html
转载:http://klcf0220.cnblogs.com/