Android Wi-Fi Peer-to-Peer(Android的Wi-Fi P2P对等网络)
Wi-Fi peer-to-peer(P2P,对等网络),它同意具备对应硬件的Android 4.0(API level 14)或者更高版本号的设备能够直接通过wifi而不须要其他中间中转节点就能直接通信(Android的Wi-Fi P2P框架符合Wi-Fi联盟的Wi-Fi Direct™直连认证标志)。使用这些API。你能够搜索并连接其他相同支持Wi-Fi P2P的设备,然后再通过一个快速的连接进行互相通信,而且这个连接的有效距离要比蓝牙连接的有效距离要长的多。
这对于须要在用户之间共享数据的应用程序很实用,比如多玩家游戏或者照片分享之类应用。
Android的Wi-Fi P2P API主要包括下面几个部分:
* 使用WifiP2pManager类定义的方法搜索、请求并连接到其他对等设备。
* 监听WiFiP2pManager的方法调用是否成功或者失败的Listener(监听器)。
当调用WiFiP2pManager的方法时,每个方法都能够接收一个指定的监听器作为參数。
* 由Wi-Fi P2P框架识别并发送的指定事件类型的Intent,比如撤销一个连接或者新发现了一个对等设备。
通常你须要一起使用这三个主要部分的API。
比如。你能够在调用discoverPeers()方法的时候提供WifiP2pManager.ActionListener监听器对象。这样你就能得到ActionListener.onSuccess()和ActionListener.onFailure()方法的通知。假设discoverPeers()方法发现对等设备列表有更新,相同也会发送WIFI_P2P_PEERS_CHANGE_ACTION类型的Intent广播。
1、API概览
WifiP2pManager类提供了与设备上的Wi-Fi硬件进行交互的方法。比如搜索和连接对等设备。下面是可用的操作:
表一:Wi-Fi P2P方法
方法 | 描写叙述 |
initialize() | 在Wi-Fi框架上注冊应用程序。这种方法必须在调用其他Wi-Fi P2P方法之前调用。 |
connect() | 使用指定配置与一台设备開始一个P2P对等连接。 |
cancelConnect() | 取消正在进行中的P2P对等网络组的交互。 |
requestConnectInfo() | 请求一台设备连接信息。 |
createGroup() | 创建一个对等网络组,并将当前设备作为群组的拥有者。 |
removeGroup() | 移除当前的P2P对等网络组。 |
requestGroupInof() | 请求P2P对等网络组信息。 |
discoverPeers() | 開始搜索对等网络(设备)。 |
requestPeers() | 请求当前已发现的对等网络(设备)。 |
WifiP2pManager的方法同意你传递一个listener监听器,这样Wi-Fi P2P框架才干通知你的activity所调用方法的状态。可使用的listener监听器接口和对应调用这些监听器的WifiP2pManager方法例如以下表:
表二:Wi-Fi P2P监听器
监听器接口 | 可被使用的操作 |
WifiP2pManager.ActionListener | connect(),cancelConnect(),createGroup(),removeGroup(),discoverPeers() |
WifiP2pManager.ChannelListener | initialize() |
WifiP2pManager.ConnectionInfoListener | requestConnectInfo() |
WifiP2pManager.GroupInfoListener | requestGroupInfo() |
WifiP2pManager.PeerListListener | requestPeers() |
Wi-Fi P2P的API定义某些Wi-Fi P2P事件发生时要广播的Intent。比如发现了一个新的对等网络(设备)或者一台设备的Wi-Fi状态改变的事件。你能够在你的应用程序中创建并注冊一个广播接受者来处理以下这些Intent:
表三:Wi-Fi P2P Intents
Intent | 描写叙述 |
WIFI_P2P_CONNECTION_CHANGED_ACTION | 当设备的Wi-Fi连接状态改变时会发送这个广播。 |
WIFI_P2P_PEERS_CHANGED_ACTION | 当你调用discoverPeers()方法就会收到这个广播。假设你在你的应用程序中处理这个intent,你相同须要调用requestPeers()来获取一个最新的对等网络(设备)列表。 |
WIFI_P2P_STATE_CHANGED_ACTION | 当设备的Wi-Fi P2P启用或者禁用时会发送这个广播。当设备的Wi-Fi P2P启用或者禁用时会发送这个广播。 |
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION | 当设备的细节被改动时会发送这个广播,比如设备的名字。 |
2、为Wi-Fi P2P的Intent创建一个广播接收器
广播接收器(broadcase receiver)同意你接收Android系统广播出来的Intent,这样你的应用程序才干响应你所感兴趣的时间。创建一个广播接收器来处理Wi-Fi P2P intent的基本过程例如以下:
2.1 创建一个继承BroadcaseReceiver的类。
在这个类的构造方法中。你最好将WifiP2pManager、WifiP2pManager.Channel。还有注冊了这个广播接收器的activity作为參数传递进来。这样才干让广播接收器向activity发送更新的同一时候,还能在须要的时候訪问Wi-Fi硬件和通信的信道。
2.2 在广播接收器中。检查onReceive()方法中你所感兴趣的intent。基于接收到的intent完毕一些必要的操作。比如,假设广播接收器接收到一个WIFI_P2P_PEERS_CHANGE_ACTION类型的Intent,你能够调用requestPeers()方法来获取当前已发现的对等网络(设备)。
以下的代码展示怎样创建一个典型的广播接收器。
这个广播接收器携带一个WifiP2pManager对象和一个activity最为參数,并在广播接收器接到一个intent的时候。使用这两个对象来适当完毕所须要的操作:
/**
* 一个接收Wi-Fi P2P重要事件的广播接收器
*/
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver { private WifiP2pManager mManager;
private Channel mChannel;
private MyWiFiActivity mActivity; public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
MyWifiActivity activity) {
super();
this.mManager = manager;
this.mChannel = channel;
this.mActivity = activity;
} @Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
// 检查Wi-fi是否已经启用。并通知适当的activity
} else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// 调用WifiP2pManager.requestPeers()来获取当前的对等网络(设备)列表
} else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
// 响应新的连接或者断开连接
} else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
// 响应本台设备wifi状态的改变
}
}
}
3、创建一个Wi-Fi P2P应用程序
创建一个Wi-Fi P2P应用程序涉及到为应用程序创建并注冊一个广播接收器。搜索对等网络(设备),连接一台对等设备,还有向一台对等设备数据传输。
以下的章节描写叙述怎样完毕这些操作。
3.1 初始设置
在使用Wi-Fi P2P的API之前,你必须确认你的应用程序可以訪问相应的硬件而且设备支持Wi-Fi P2P协议。假设支持Wi-Fi P2P,你就行获取一个WifiP2pManager实例,创建并注冊你的广播接收器,然后開始使用Wi-Fi P2P的API。
3.1.1 在Android的manifest文件里请求使用设备上Wi-Fi硬件的权限。并为你的应用程序声明正确的最小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" />
3.1.2 检查Wi-Fi P2P可以支持而且已经启用。
进行这项检查的一个较好的地方是在你的广播接收器中,当广播接收器接收到WIFI_P2P_STATE_CHANGED_ACTION的时候。从而通知你的activity关于Wi-Fi 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已经启用
} else {
// Wi-Fi P2P没有启用
}
}
...
}
3.1.3 在你的activity的onCreate()方法中获取一个WifiP2pManager实例,并通过调用initialize()方法将你的应用程序注冊到Wi-Fi P2P框架中。这种方法会返回一个WifiP2pManager.Channel对象,这个对象被用于连接你的应用程序和Wi-Fi P2P框架。你相同须要使用这个WifiP2pManager和WifiP2pManager.Channel对象,还有你的activity引用创建一个你的广播接收器实例。这样才干同意你的广播接收器通知你的activity所感兴趣的事件并进行更新。
它相同能让你在须要的时候操作设备的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);
...
}
3.1.4 创建一个intent过滤器。并在你的广播接收器中加入同样的Intent以进行检查:
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);
...
}
3.1.5 在activity的onResume()方法中注冊你的广播接收器,并在onPause()方法中注销:
/* 使用须要匹配的intent值注冊广播接收器 */
@Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
}
/* 注销广播接收器 */
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
当你已经获取到WifiP2pManager.Channel对象而且设置好广播接收器,你的应用程序就能够调用Wi-Fi P2P的方法和接收Wi-Fi P2P的intent。
你如今能够实现你的应用程序而且通过调用WifiP2pManager中的方法来使用Wi-Fi P2P的功能。以下的章节将阐述怎样运行常见的操作,比方搜索和连接对等设备。
3.2 搜索对等网络(设备)
搜索同意被连接的对等设备,能够调用discoverPeers()方法来检測附近范围中同意被发现的对等网络(设备)。
这种方法的运行过程是异步的,假设你有创建并传递一个WifiP2pManager.ActionListener对象作为參数。你能够在这个对象中的onSuccess()和onFailure()方法中接收到操作运行的结果。当中onSuccess()方法仅仅是通知你搜索程序已经成功运行。可是不会提供不论什么实际搜索到的对等设备信息;
mManager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
...
} @Override
public void onFailure(int reasonCode) {
...
}
});
假设搜索程序成功运行而且检測到对等网络和设备,系统将会发送WIFI_P2P_PEERS_CHANGED_ACTION类型的intent广播,你能够在广播接收器中监听这个广播以获取对等网络设备列表。当你的应用程序接收到WIFI_P2P_PEERS_CHANGED_ACTION类型的intent,你就能够使用requestPeers()方法来请求已被发现的对等网络设备列表。
以下的代码展示了怎样设置这些步骤:
PeerListListener myPeerListListener;
...
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { // 从wifi p2p manager请求可使用的对等设备。这是一个异步调用的方法。
// 调用的activity将会在PeerListListener.onPeersAvailable()的回调方法中得到列表结果。 if (mManager != null) {
mManager.requestPeers(mChannel, myPeerListListener);
}
}
这个requestPeers()方法相同是异步运行的方法。当对等设备列表可用时,它会在WifiP2pManager.PeerListListener接口定义的onPeersAvailable()方法中将结果返回给你的activity。onPeersAvailable()方法会提供一个WifiP2pDeviceList对象,你能够通过这个对象找到你想要连接的对等设备。
3.3 连接对等设备
当你从获取到的可连接对等设备列表中找出你想要连接的对等设备之后。你就能够调用connect()方法链接这个设备。
这种方法的调用须要一个WifiP2pConfig对象,这个对象包括了想要连接的设备信息。
你能够通过WifiP2pManager.ActionListener得到连接成功或者失败的结果。以下的代码展示了怎样连接目标设备:
//从WifiP2pDeviceList中获取一个对等设备
WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
mManager.connect(mChannel, config, new ActionListener() { @Override
public void onSuccess() {
//连接成功的逻辑处理操作
} @Override
public void onFailure(int reason) {
//连接失败的逻辑处理操作
}
});
3.4 数据传输
一旦连接建立成功,你就能够在设备之间通过socket数据传输。
传入数据的基本过程例如以下:
3.4.1 创建一个SeverSocket。这个socket会在一个port上等待client的连接,而且会一直堵塞直到连接请求出现。因此这种方法须要在后台线程运行。
3.4.2 创建一个client的Socket。
这个client使用服务端ServerSocket的IP地址和port来连接服务端设备。
3.4.3 从client发送数据到服务端。当client的socket成功连接上服务端的socket之后,你就能够通过字节流将数据从client发送到服务端。
3.4.4 服务端的ServerSocket等待着client的连接(通过accept()方法)。
这种方法会一直堵塞直到client连接上,因此要在其他线程中调用这种方法。当连接上之后。服务端设备就行接收到client发送过来的数据。完毕对这些数据的一些操作,比如保存为一个文件或者显示给用户。
以下的样例改动于Wi-Fi P2P Demo(能够在Android SDK中找到),它展示了怎样创建client和服务端之间的socket通信。并从通过一个service从client向服务端发送了一个JPEG图片。
完整的代码,能够直接查看Wi-Fi P2P 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 { /**
* 创建一个ServerSocket并等待client的连接.这种方法会一直堵塞直到接受了一个client连接
*/
ServerSocket serverSocket = new ServerSocket(8888);
Socket client = serverSocket.accept(); /**
* 假设代码可以运行到这里,说明已经连接上一个client而且開始数据传输
* 将来自client的数据流保存为一个JPEG文件
*/
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;
}
} /**
* 启动可以处理JPEG图片的activity
*/
@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);
}
}
}
在client上。通过一个client的socket连接服务端的socket并数据传输。
这个样例传输了一个client设备文件系统的上的JPEG文件。
Context context = this.getApplicationContext();
String host;
int port;
int len;
Socket socket = new Socket();
byte buf[] = new byte[1024];
...
try {
/**
* 使用服务端IP和端口还有连接超时时间创建一个clientsocket
*/
socket.bind(null);
socket.connect((new InetSocketAddress(host, port)), 500); /**
* 从一个JPEG文件创建一个字节流,而且传输到socket的输出流上。 这些数据将会在服务端设备上接收到。
*/
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
} /**
* 当传输数据完毕或者发生异常时关闭已经打开的socket。 */
finally {
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
//catch logic
}
}
}
}
原文地址:http://developer.android.com/guide/topics/connectivity/wifip2p.html
Android Wi-Fi Peer-to-Peer(Android的Wi-Fi P2P对等网络)的更多相关文章
- Android权限管理之RxPermission解决Android 6.0 适配问题
前言: 上篇重点学习了Android 6.0的运行时权限,今天还是围绕着Android 6.0权限适配来总结学习,这里主要介绍一下我们公司解决Android 6.0权限适配的方案:RxJava+RxP ...
- com.android.build.api.transform.TransformException: com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK assets/com.xx.xx
完整的Error 信息(关键部分) Error:Execution failed for task ':fanwe_o2o_47_mgxz_dingzhi:transformResourcesWith ...
- Android入门(六):Android控件布局属性全解
第一类:属性值为true或falseandroid:layout_centerHrizontal 水平居中 (Hrizontal表示水平)android:layout_centerVertical 垂 ...
- Android入门(一):Android发展史
Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发.尚未有统一中文名称,中国大陆地区较多人使用“安卓” ...
- Android xml资源文件中@、@android:type、@*、?、@+含义和区别
一.@代表引用资源 1.引用自定义资源.格式:@[package:]type/name android:text="@string/hello" 2.引用系统资源.格式:@andr ...
- Android开发新手学习总结(六)——android开发目录结构【图文版】
转载链接:http://bbs.itcast.cn/thread-87059-1-1.html?rss 既然已经搭建好环境了,那就对Android Studio中项目目录结构做个简单的了解了,这里以最 ...
- 0.[WP Developer体验Andriod开发]之从零安装配置Android Studio并编写第一个Android App
0. 所需的安装文件 笔者做了几年WP,近来对Android有点兴趣,尝试一下Android开发,废话不多说,直接进入主题,先安装开发环境,笔者的系统环境为windows8.1&x64. 安装 ...
- android studio 导入一个已有的android studio project作为lib使用
android studio 导入一个已有的android studio project作为lib使用 新项目来了. 需要搭建框架. android studio对我来说还是很陌生,之前一个项目在同事 ...
- 打开android虚拟机时出现a repairable android virtual device
打开android虚拟机时出现a repairable android virtual device,虚拟机可以打开但是一直处于开机状态,具体解决方案如下: 解决方案1:换个版本,不要选 CPU/AB ...
随机推荐
- SB!SB!SB! ----WriteUp
原题 下载图片 http://ctf5.shiyanbar.com/stega/ste.png 用Stegsolve查看 发现有个二维码 扫码可以知道flag
- OpenGL ES 3.0 帧缓冲区对象基础知识
最近在帧缓冲区对象这里卡了一下,不过前面已经了解了相关的OpenGL ES的知识,现在再去了解就感觉轻松多了.现在就进行总结. 基础知识 我们知道,在应用程序调用任何的OpenGL ES命令之前,需要 ...
- Uva 12889 One-Two-Three
Your little brother has just learnt to write one, two and three, in English. He has written a lot ...
- C# 7.0特性与vs2017
下面是关于在C#7.0语言中计划功能的说明.其中大部分功能在Visual Studio “15” Preview 4中能运行.现在是最好的试用时期,请记录下你们的想法. C#7.0语言增加了许多的新功 ...
- 预防Redis缓存穿透、缓存雪崩解决方案
最近面试中遇到redis缓存穿透.缓存雪崩等问题,特意了解下. redis缓存穿透: 缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有.这样就导致用户查询的时候,在缓存中找不到,每次都要去 ...
- Git_git的诞生
很多人都知道,Linus在1991年创建了开源的Linux,从此,Linux系统不断发展,已经成为最大的服务器系统软件了. Linus虽然创建了Linux,但Linux的壮大是靠全世界热心的志愿者参与 ...
- 力特ZE398C驱动光盘-USB转RS232-支持Windows 10/Mac
这个工具是USB1.1的,相对来说比较老,一开始做小白鼠不知道买了USB1.1的,所以我不建议买这个,还有其它的型号,支持USB2.0和USB3.0,不过价格也相对来说比较贵,这个才30块钱左右. 关 ...
- Redis在Windows+linux平台下的安装配置(转)
window平台Redis安装 下载地址: http://code.google.com/p/servicestack/wiki/RedisWindowsDownload Redis文件夹有以下几个文 ...
- web服务器boa的移植
1.下载官方网站 http://www.boa.org/ 我下载的是0.94.13版本 2.解压 tar -zxvf boa-0.94.13.tar.gz 3.进入src目录 ./configure ...
- MVC使用StructureMap实现依赖注入Dependency Injection
使用StructureMap也可以实现在MVC中的依赖注入,为此,我们不仅要使用StructureMap注册各种接口及其实现,还需要自定义控制器工厂,借助StructureMap来生成controll ...