Android网络通信之WiFi Direct

使用Wi-Fi Direct技术可以让具备硬件支持的设备在没有中间接入点的情况下进行直接互联。Android 4.0(API版本14)及以后的系统都提供了对Wi-Fi Direct的API支持。通过对这些API的使用,开发者可以实现支持Wi-Fi Direct的设备间进行相互探测和连接,从而获得较之蓝牙更远距离的高速数据通信效果。对于诸如多人游戏、图片共享等需要在用户之间传输数据的应用而言,这一技术无疑是十分有价值的。

关于Wi-Fi Direct的API函数的使用需要注意一下几个要点:
·用于探测(discover)对等设备(peers)、向对等设备发起请求(request)以及建立连接(connect)的方法定义在类WifiP2pManager中。
·通过设置监听器(Listener)可以获知WifiP2pManager中方法调用的成功与否。监听器以参数的形式传递给被调用的方法。
·当发现新对等设备或链接丢失的时候,Wi-Fi Direct系统(framework)以意向(Intent)的方式根据检测到的不同事件做出相应的通知。

开发中,以上三点的配合使用相当普遍。简单举个例子,定义一个监听器WifiP2pManager.ActionListener并调用函数discoverPeers(),当相应事件发生的时候就会在ActionListener.onSuccess()和ActionListener.onFailure()两个方法中得到通知。当discoverPeers()方法检测到了对等设备列表变化的时候,可以收到由系统广播(broadcast)发出一个WIFI_P2P_PEERS_CHANGED_ACTION意向。

创建广播接收器以处理Wi-Fi Direct意向的基本步骤如下:
1、创建一个继承BroadcastReceiver类的新类。构造函数的参数分别传递WifiP2pManager,WifiP2pManager.Channel,以及在这个广播接收器中需要注册的活动(activity)。这是一种最常见的参数设置模式,它让广播接收器能够引起活动作出更新,同时又能在必要时使用Wi-Fi硬件和通信信道。
2、在广播接收器的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" />

检查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  
        }  
    }  
    ...… 
}

在活动的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);  
    ... …. 
}

创建一个意向过滤器(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的特殊能力吧!

探测对等设备(Discovering peers)
调用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意向。程序接收到该意向后,通过调用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发送数据的基本步骤:
1、创建ServerSocket。它将被用于监听特定端口,等待客户端发起的连接请求。该操作需要在后台线程中实现。
2、创建客户端Socket。客户端通过ServerSocket对应的IP和端口连接到服务设备。
3、客户端向服务器发生数据。客户socket成功连接到服务socket后,就能以字节流的形式向服务器发生数据了。
4、服务器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/

时间: 2024-10-07 04:04:13

Android网络通信之WiFi Direct的相关文章

马上搞定Android平台的Wi-Fi Direct开发

导语 移动互联网时代,很多用户趋向于将大量的资料保存在移动设备上.但在给用户带来便利的同时引发了一个新的问题——保存在移动设备上的资料该怎样共享出去?到了思考时间,普通青年这样想:折腾什么劲啊,直接用数据线不就行了:而文艺青年可能这样想:咱们建个群吧,大家有好的东西都可以共享:二逼青年不高兴了,都特么互联网时代了,来点新意,好么?直接上网盘啊,大家互相研究研究,你懂的,嘿嘿.然而我是这样想的:都特么别BB,技术要以时俱进,来个新潮点的不行么?直接上Wi-Fi Direct.好用简单不解释.那么我

【Android】 Android-wifi 直连 wifi direct wifi p2p

现在,Android的支持Wi -Fi的直接点对点点对点(P2P)Android系统的供电设备和其他类型的设备,没有一个热点或互联网连接之间的连接.Android框架提供了一套Wi - Fi的P2P的API,允许你去发现和连接到其他设备时,每个设备的Wi -Fi的直接支持,然后沟通跨越距离远远长于蓝牙连接迅速??连接. android.net.wifi.p2p,一个新的软件包,包含所有的API执行同行等连接与Wi - Fi. 你需要与主类是WifiP2pManager,您可以调用getSyste

Android WiFi 通信 -- WiFi 和 Wifi Direct 简介

WiFi简介 Wi-Fi可分为五代:第一代802.11,1997年制定,只运行于2.4GHz,最快2Mbit/s 第二代802.11b,只运行于2.4GHz,最快11Mbit/s,正逐渐淘汰 第三代802.11g/a,分别运行于2.4GHz和5GHz,最快54Mbit/s 第四代802.11n,可运行于2.4GHz或5GHz,20和40MHz带宽下最快72和150Mbit/s 第五代802.11ac,只运行于5GHz 由于ISM频段中的2.4GHz频段被广泛使用,例如微波炉.蓝牙,它们会干扰Wi

Android 4.2 Wifi Display 之 Settings 源码分析(一)

一.简单背景 简单背景:随着无线互联的深入,不管是蓝牙.WIFI或者各种基于此的规范不管是UPNP还是DLNA都随着用户的需求得到了很大的发展,google 自从android 4.0引入wifi direct后,又在11月份公布的android 4.2中引入了Miracast无线显示共享,其协议在此可以下载.具体的协议部分内容比较多,本人由于水平有限,就不在这里罗列协议的内容了,只附上一份架构图供大家对其有个大致的印象. 英文缩写对应如下: HIDC: Human Interface Devi

17、Wi-Fi Direct

Wi-Fi Direct简介 从Android4.0(API Level=14)开始,允许通过Wi-Fi模块在两个移动设备之间建立直接连接(这种技术称为Wi-Fi Direct),这种连接不需要无线路由作为中介,而只是像蓝牙一样在两个设备之间直接建立的数据传输通道.在Android SDK中提供了一些API,通过这些API可以发现其它支持Wi-Fi Direct的设备,也可以接收其它设备的Wi-Fi Direct请求.在Wi-Fi Direct出现之前,通常使用蓝牙或利用无线路由连接多部Andr

Android代码连接Wifi时被系统切换到其他Wifi的问题

首先说下Android代码连接Wifi的几个步骤:(以下涉及到具体API函数自查哈,写的时候凭借印象大致写了下) 转载请注明出处: 胖虎:http://blog.csdn.net/ljphhj 1.首先要开启Wifi连接开关,mWifiManager.setWifiEnabled(true) 2.通过获取List<ScanResult>来获取到Wifi连接列表.(mWifiManager.getScanResults) 3.获取List<WifiConfiguration>列表.(

Android 查看 无wifi/usb设备的logcat方法

Android 查看 无wifi/usb设备的logcat方法 一.情况 一个定制Android设备,wifi被去掉,我需要调试一个USB设备这样也无法用usb来输出logcat. 因为这个USB设备需要内核驱动支持,因此无法在其它设备调试. 因此有的方法有,一般想到用蓝牙输出logcat,但这是Android wear 才支持的特性. 在代码中加入捕获错误和异常代码,写入sd卡,这个工作量较大,而且麻烦 二.简单的解决办法 1.安装Android Terminal 软件. 一个可用链接是 ht

Android连接指定Wifi的方法

本篇博客主要记录一下Android中打开Wifi.获取Wifi接入点信息及连接指接入点的方法. 自己写的demo主要用于测试接口的基本功能,因此界面及底层逻辑比较粗糙. demo的整体界面如下所示: 上图中的OPEN按键负责开启Wifi: GET按键负责获取扫描到的接入点信息. 当获取到接入点信息后,我选取了其中的名称及信号强度,以列表的形式显示在主界面下方,如下图: 当点击列表中的Item时,就会去连接对应的接入点. 自己的逻辑比较简单,测试时的代码,假定连接的是不许要密码或密码已知的接入点.

Android网络通信Volley框架源码浅析(三)

尊重原创 http://write.blog.csdn.net/postedit/26002961 通过前面浅析(一)和浅析(二)的分析,相信大家对于Volley有了初步的认识,但是如果想更深入的理解,还需要靠大家多多看源码. 这篇文章中我们主要来研究一下使用Volley框架请求大量图片的原理,在Android的应用中,通过http请求获取的数据主要有三类: 1.json 2.xml 3.Image 其中json和xml的获取其实原理很简单,使用Volley获取感觉有点大财小用了,了解Volle