Android WifiDirect学习(一)

WiFi Direct基本介绍

Wi-Fi Direct标准允许无线网络中的设备无需通过无线路由器即可相互连接。与蓝牙技术类似,这种标准允许无线设备以点对点形式互连,不过在传输速度与传输距离方面则比蓝牙有大幅提升。

Wi-Fi Direct可以支持一对一直连,也可以实现多台设备同时连接

 

WiFiDirect  一对一 搜索/连接/传输基本流程

第一步:初始化WifiDirect模块,一般情况下,只要打开Wifi,WifiDirect就会处于激活状态

第二步:WifiDirect进行搜索状态,只有处于Wifidirect搜索状态的手机才能被其他手机搜索到。

第三步:连接搜索到的手机,建立连接。连接一旦建立,就会停止搜索。

第四步:在建立好连接的网络基础上进行网络传输(socket通信)

第五步:传输完毕后,可以根据需要继续进行传输或者断开连接

 

Android WiFi Direct

Android 4.0(API level 14)之后版本支持

Android WiFi Direct 基本使用方法

Android WiFi Direct API包含以下主要部分:

  • 允许用户发现,请求然后连接对等设备的各种方法,定义在WifiP2pManager类中。
  • 允许用户定义收到调用WifiP2pManager类中方法成功或失败的通知的监听器(ActionListener)。当用户调用WifiP2pManager类中的方法时,每一个方法都可以收到一个以参数形式传过来的特定监听。
  • 通知用户被Wi-Fi直连技术框架检测到的特定事件的Intent,比如一个已丢掉的连接或者一个新的Peer的发现等。

 

 

Android WiFi Direct API 概述

WifiP2pManager类提供了很多方法允许用户通过设备的Wi-Fi模块来进行交互,比如做一些如发现,连接其他对等设备的事情。下列的方法都是可以使用的:

表格1.Wi-Fi直连技术方法


方法名


详细描述


initialize()


通过Wi-Fi框架对应用来进行注册。这个方法必须在任何其他Wi-Fi直连方法使用之前调用。


connect()]


开始一个拥有特定设置的设备的点对点连接。


cancelConnect()


取消任何一个正在进行的点对点组的连接。


requestConnectInfo()


获取一个设备的连接信息。


createGroup()


以当前设备为组拥有者来创建一个点对点连接组。


removeGroup()


移除当前的点对点连接组。


requestGroupInfo()


获取点对点连接组的信息。


discoverPeers()


初始化对等设备的发现。


requestPeers()


获取当前发现的对等设备列表。

 

WifiP2pManager的方法可以让你在一个监听器(ActionListener)里传递参数,这样Wi-fi直连框架就可以通知给你的窗体这个方法调用的状态。

可以被使用的监听器接口和使用监听器的相应的WifiP2pManager的方法的调用都将在下面这张表中有所描述:

表格2. Wi-Fi直连监听器方法


监听器接口


相关联的方法


WifiP2pManager.ActionListener


connect(), cancelConnect(), createGroup(), removeGroup(), and discoverPeers()


WifiP2pManager.ChannelListener


initialize()


WifiP2pManager.ConnectionInfoListener


requestConnectInfo()


WifiP2pManager.GroupInfoListener


requestGroupInfo()


WifiP2pManager.PeerListListener


requestPeers()

 

Wi-Fi直连技术的API定义了一些当特定的Wi-Fi直连事件发生时作为广播的Intent,比如说当一个新的Peer被发现,或者一个Peer的Wi-Fi状态的改变。你可以在你的应用里通过创建一个处理这些Intent的BroadcastReceiver来注册去接收这些Intent。

Table 3. Wi-Fi 直连意图


意图名称


详细描述


WIFI_P2P_CONNECTION_CHANGED_ACTION


当设备的Wi-Fi连接信息状态改变时候进行广播。


WIFI_P2P_PEERS_CHANGED_ACTION


当调用discoverPeers()方法的时候进行广播。在你的应用里处理此意图时,你通常会调用requestPeers()去获得对等设备列表的更新。


WIFI_P2P_STATE_CHANGED_ACTION


当设备的Wi-Fi 直连功能打开或关闭时进行广播。


WIFI_P2P_THIS_DEVICE_CHANGED_ACTION


当设备的详细信息改变的时候进行广播,比如设备的名称

 

 

创建一个Wi-Fi直连的应用

创建一个Wi-Fi直连的应用包括创建和注册一个BroadcastReceiver,发现其他设备,连接其他设备,然后传输数据等步骤。接下来的几个部分描述了怎么去做这些工作。

初始化设置

在使用Wi-Fi直连的API之前,你必须确保你的应用可以访问设备的硬件并且你的设备要支持Wi-Fi直连的通讯协议。如果Wi-Fi直连技术是支持的,你可以获得一个WifiP2pManager的实例对象,然后创建并注册你的BroadcastReceiver,然后开始使用WiFiDirect的API方法。

1.为设备的Wi-Fi硬件获取权限并在Android的清单文件中声明你的应用正确使用的最低SDK版本:

1 <uses-sdk android:minSdkVersion="14" />
2 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
3 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
4 <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
5 <uses-permission android:name="android.permission.INTERNET" />
6 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

 

2.检查设备是否支持Wi-Fi直连技术。一种好的解决办法是当你的BrocastReceiver接收到一个WIFI_P2P_STATE_CHANGED_ACTION Intent。通知你的Activity Wi-Fi直连的状态和相应的反应。

 
 1 @Override
 2 public void onReceive(Context context, Intent intent) {
 3     ...
 4     String action = intent.getAction();
 5     if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
 6         int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
 7         if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
 8             // Wifi Direct is enabled
 9         } else {
10             // Wi-Fi Direct is not enabled
11         }
12     }
13     ...
14 }

 

3.在你的窗体的onCreate()方法里,获得一个WifiP2pManager的实例并调用initialize()方法通过WiFiDirect框架去注册你的应用。这个方法返回一个WifiP2pManager.Channel对象,是被用来连接你的应用和WiFiDirect框架的。你应该再创建一个以WifiP2pManager和WifiP2pManager.Channel为参数且关联你的Activity的BroadcastRecevier的实例。这样你的BroadcastRecevier就可以接收到你感兴趣的事件去通知你的Activity并更新它。它还可以让你在需要的时候操纵设备的Wi-Fi状态。

 1 WifiP2pManager mManager;
 2 Channel mChannel;
 3 BroadcastReceiver mReceiver;
 4 ...
 5 @Override
 6 protected void onCreate(Bundle savedInstanceState){
 7     ...
 8     mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
 9     mChannel = mManager.initialize(this, getMainLooper(), null);
10     mReceiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
11     ...
12 }

 

4.创建一个IntentFilter并把它添加在你的BroadcastReceiver需要处理的Intent上。

 1 IntentFilter mIntentFilter;
 2 ...
 3 @Override
 4 protected void onCreate(Bundle savedInstanceState){
 5     ...
 6     mIntentFilter = new IntentFilter();
 7     mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
 8     mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
 9     mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
10     mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
11     ...
12 }

 

5.注册你的BroadcastReceiver在Acitivity的onResume()方法,解除注册在onPause()方法中。(BroadcastReceiver的register和unregister根据需要可放在不同的位置)

 1 /* register the broadcast receiver with the intent values to be matched */
 2 @Override
 3 protected void onResume() {
 4     super.onResume();
 5     registerReceiver(mReceiver, mIntentFilter);
 6 }
 7 /* unregister the broadcast receiver */
 8 @Override
 9 protected void onPause() {
10     super.onPause();
11     unregisterReceiver(mReceiver);
12 }

 

当你获取到一个WifiP2pManager.Channel对象并且设置好你的BroadcastReceiver时,你的应用就可以调用Wi-Fi直连的方法并且可以接收Wi-Fi直连的Intent。

你可以现在就通过调用WifiP2pManager中的方法取实现你的应用体验Wi-Fi直连技术的特性了。

下面的章节描述了怎样去实现一些常用的操作,比如说发现其他设备(搜索)和连接它们。

发现对等设备

要发现可以使用并连接的对等设备,调用discoverPeers()方法去检测在范围内的可使用设备。这个方法的调用是异步的同时如果你创建了一个WifiP2pManager.ActionListener监听器的话你会通过onSuccess()或者onFailure()方法收到发现成功或失败的消息。onSuccess()方法只能通知你发现的过程是否成功而不能提供任何关于发现设备的信息:

 
 1 manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
 2     @Override
 3     public void onSuccess() {
 4         ...
 5     }
 6
 7     @Override
 8     public void onFailure(int reasonCode) {
 9         ...
10     }
11 });

 

如果发现过程成功且检测到了对等设备,系统将会广播出一个WIFI_P2P_PEERS_CHANGED_ACTION Intent,这样你就可以利用BroadcastReceiver监听并获得发现设备的列表。当你的应用接收到WIFI_P2P_PEERS_CHANGED_ACTION Intent时,你就可以调用requestPeers()方法来获取发现设备的列表,代码如下:

 
 1 PeerListListener myPeerListListener;
 2 ...
 3 if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
 4
 5     // request available peers from the wifi p2p manager. This is an
 6     // asynchronous call and the calling activity is notified with a
 7     // callback on PeerListListener.onPeersAvailable()
 8     if (manager != null) {
 9         manager.requestPeers(channel, myPeerListListener);
10     }
11 }

 

连接到设备

当你已经找到你要连接的设备在获得发现设备列表之后,调用connect()方法去连接指定设备。这个方法的调用需要一个包含待连接设备信息的WifiP2pConfig对象。你可以通过WifiP2pManager.ActionListener接收到连接是否成功的通知。

下面的代码展示了怎样去连接一个想得到的连接:

 
 1 //obtain a peer from the WifiP2pDeviceList
 2 WifiP2pDevice device;
 3 WifiP2pConfig config = new WifiP2pConfig();
 4 config.deviceAddress = device.deviceAddress;
 5 manager.connect(channel, config, new ActionListener() {
 6
 7     @Override
 8     public void onSuccess() {
 9         //success logic
10     }
11
12     @Override
13     public void onFailure(int reason) {
14         //failure logic
15     }
16 });

 

数据传输

一旦连接已经建立,你可以通过Socket来进行数据的传输。基本的数据传输步骤如下(google官方例子,也可以根据需要使用适用Socket通讯的其他方法协议,如HTTP,FTP协议):

1.创建一个ServerSocket对象。这个服务端Socket对象等待一个来自指定地址和端口的客户端的连接且阻塞线程直到连接发生,所以把它建立在一个后台线程里。

2.创建一个客户端Socket.这个客户端Socket对象使用指定ip地址和端口去连接服务端设备。

3.从客户端给服务端发送数据。当客户端成功连接服务端设备后,你可以通过字节流从客户端给服务端发送数据。

4.服务端等待客户端的连接(使用accept()方法)。这个调用阻塞服务端线程直到客户端连接上,所以叫这个过程一个新的线程。当连接建立时,服务端可以接受来自客户端的数据。执行关于数据的任何动作,比如保存数据或者展示给用户。

下来的例子,展示了怎样去创建服务端和客户端的连接和通信,并且使用一个客户端到服务端的服务来传输了一张JPEG图像。如。

 
 1 public static class FileServerAsyncTask extends AsyncTask {
 2
 3     private Context context;
 4     private TextView statusText;
 5
 6     public FileServerAsyncTask(Context context, View statusText) {
 7         this.context = context;
 8         this.statusText = (TextView) statusText;
 9     }
10
11     @Override
12     protected String doInBackground(Void... params) {
13         try {
14
15             /**
16              * Create a server socket and wait for client connections. This
17              * call blocks until a connection is accepted from a client
18              */
19             ServerSocket serverSocket = new ServerSocket(8888);
20             Socket client = serverSocket.accept();
21
22             /**
23              * If this code is reached, a client has connected and transferred data
24              * Save the input stream from the client as a JPEG file
25              */
26             final File f = new File(Environment.getExternalStorageDirectory() + "/"
27                     + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
28                     + ".jpg");
29
30             File dirs = new File(f.getParent());
31             if (!dirs.exists())
32                 dirs.mkdirs();
33             f.createNewFile();
34             InputStream inputstream = client.getInputStream();
35             copyFile(inputstream, new FileOutputStream(f));
36             serverSocket.close();
37             return f.getAbsolutePath();
38         } catch (IOException e) {
39             Log.e(WiFiDirectActivity.TAG, e.getMessage());
40             return null;
41         }
42     }
43
44     /**
45      * Start activity that can handle the JPEG image
46      */
47     @Override
48     protected void onPostExecute(String result) {
49         if (result != null) {
50             statusText.setText("File copied - " + result);
51             Intent intent = new Intent();
52             intent.setAction(android.content.Intent.ACTION_VIEW);
53             intent.setDataAndType(Uri.parse("file://" + result), "image/*");
54             context.startActivity(intent);
55         }
56     }
57 }

 

 

在客户端,使用客户端套接字连接服务端套接字并传输数据。这个例子从客户端的文件系统里传输了一张JPEG的图像到服务端。

 1 Context context = this.getApplicationContext();
 2 String host;
 3 int port;
 4 int len;
 5 Socket socket = new Socket();
 6 byte buf[]  = new byte[1024];
 7 ...
 8 try {
 9     /**
10      * Create a client socket with the host,
11      * port, and timeout information.
12      */
13     socket.bind(null);
14     socket.connect((new InetSocketAddress(host, port)), 500);
15
16     /**
17      * Create a byte stream from a JPEG file and pipe it to the output stream
18      * of the socket. This data will be retrieved by the server device.
19      */
20     OutputStream outputStream = socket.getOutputStream();
21     ContentResolver cr = context.getContentResolver();
22     InputStream inputStream = null;
23     inputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg"));
24     while ((len = inputStream.read(buf)) != -1) {
25         outputStream.write(buf, 0, len);
26     }
27     outputStream.close();
28     inputStream.close();
29 } catch (FileNotFoundException e) {
30     //catch logic
31 } catch (IOException e) {
32     //catch logic
33 }
34
35 /**
36  * Clean up any open sockets when done
37  * transferring or if an exception occurred.
38  */
39 finally {
40     if (socket != null) {
41         if (socket.isConnected()) {
42             try {
43                 socket.close();
44             } catch (IOException e) {
45                 //catch logic
46             }
47         }
48     }
49 }

 

 
时间: 2024-08-08 22:00:47

Android WifiDirect学习(一)的相关文章

Android WiFiDirect 学习(二)——Service Discovery

Service Discovery 简介 在Android WifiDirect学习(一 )中,简单介绍了如何使用WifiDirect进行搜索——连接——传输. 这样会有一个问题,那就是你会搜索到到附近所有处于WifiDirect搜索状态的网络设备,而这些设备中不一定都是你想进行连接的. Android WifiDirect Api提供了一个仅搜索特定网络设备的搜索方式,叫做Service Discovery,它是Wi-Fi Direct API在Android 4.1中被增强以支持在WifiP

Android WifiDirect 学习(三) 一些基础知识和问题

P2P架构介绍 P2P架构中定义了三个组件,一个设备,两种角色.这三个组件分别是: P2P Device:它是P2P架构中角色的实体,读者可把它当做一个Wi-Fi设备. P2P Group Owner(GO):P2P网络建立时会产生一个Group. P2P Group Client(GC): 在组建P2P Group(即P2P Network)之前,智能终端都是一个一个的P2P Device. 当这些P2P Device设备之间完成P2P协商后,那么其中将有一个并且只能有一个Device来扮演G

java/android 设计模式学习笔记(14)---外观模式

这篇博客来介绍外观模式(Facade Pattern),外观模式也称为门面模式,它在开发过程中运用频率非常高,尤其是第三方 SDK 基本很大概率都会使用外观模式.通过一个外观类使得整个子系统只有一个统一的高层的接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节.当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块.ImageLoader 模块等.其实我们在开发过程中可能已经使用过很多次外观模式,只是没有从理论层面去了解它. 转载请注明出处:http://bl

java/android 设计模式学习笔记(10)---建造者模式

这篇博客我们来介绍一下建造者模式(Builder Pattern),建造者模式又被称为生成器模式,是创造性模式之一,与工厂方法模式和抽象工厂模式不同,后两者的目的是为了实现多态性,而 Builder 模式的目的则是为了将对象的构建与展示分离.Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程.一个复杂的对象有大量的组成部分,比如汽车它有车轮.方向盘.发动机.以及各种各样的小零件,要将这些部件装配成一辆汽车,这个装配过

java/android 设计模式学习笔记(一)---单例模式

前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使用的时候也会有一些坑. PS:对技术感兴趣的同鞋加群544645972一起交流 设计模式总目录 java/android 设计模式学习笔记目录 特点 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 单例模式的使用很广泛,比如:线程池(threadpool).缓存(cache).对

Android NDK学习笔记(一) 为什么要用NDK?

NDK是什么 NDK是Native Development Kit的简称,即本地开发工具包.通过NDK,Android允许开发人员使用本地代码语言(例如C/C++)来完成应用的部分(甚至全部)功能.注意:由于翻译原因,有些地方也把Native翻译为"原生". NDK是SDK的一个补充,可以帮助你做这些事情: 生成可以在ARM CPU,Android 1.5(及以上)平台运行的JNI兼容的共享库. 将生成的共享库放置在应用程序项目路径的合适位置,使其能自动地添加进你最终的(和经过签名的)

Android:日常学习笔记(8)———探究UI开发(5)

Android:日常学习笔记(8)---探究UI开发(5) ListView控件的使用 ListView的简单用法 public class MainActivity extends AppCompatActivity { private String[] data={"Apple","Banana","Orange","Watermelon","Pear","Grape","

java/android 设计模式学习笔记(7)---装饰者模式

这篇将会介绍装饰者模式(Decorator Pattern),装饰者模式也称为包装模式(Wrapper Pattern),结构型模式之一,其使用一种对客户端透明的方式来动态的扩展对象的功能,同时它也是继承关系的一种替代方案之一,但比继承更加灵活.在现实生活中也可以看到很多装饰者模式的例子,或者可以大胆的说装饰者模式无处不在,就拿一件东西来说,可以给它披上无数层不一样的外壳,但是这件东西还是这件东西,外壳不过是用来扩展这个东西的功能而已,这就是装饰者模式,装饰者的这个角色也许各不相同但是被装饰的对

【转】Android开发学习总结(一)——搭建最新版本的Android开发环境

最近由于工作中要负责开发一款Android的App,之前都是做JavaWeb的开发,Android开发虽然有所了解,但是一直没有搭建开发环境去学习,Android的更新速度比较快了,Android1.0是2008年发布的,截止到目前为止Android已经更新Android5.0.1,学习Android开发的第一步就是搭建Android的开发环境,博客园里面有不少人也写了关于如何搭建Android开发环境的文章,我也看了一下,但是感觉都比较旧了,对照着做不一定能够搭建成功,但是有些搭建步骤是还是可