Android Wi-Fi Direct 开发
来源:互联网 发布:淘宝代购能退货吗 编辑:程序博客网 时间:2024/05/06 11:29
一、Wi-Fi Direct 简介
Wi-Fi Direct标准是指允许无线网络中的设备无需通过无线路由器即可相互连接。与蓝牙技术类似,这种标准允许无线设备以点对点形式互连,而且在传输速度与传输距离方面则比蓝牙有大幅提升。按照定义,Wi-Fi Direct设备是支持对等连接的设备,这种设备既支持基础设施网络,也支持P2P连接。Wi-Fi Direct设备能够作为典型的站点(STA)加入基础设施网络,而且必须支持Wi-Fi Protected Setup加入者功能。Wi-Fi Direct设备通过组建小组(以一对一或一对多的拓扑形式)来建立连接,小组的工作形式与基础设施BSS类似。由一部Wi-Fi Direct设备负责整个小组,包括控制哪部设备加入、小组何时启动和终止等。这种设备对于传统客户设备而言就是一部接入点,能够提供基础设施接入点所提供的部分服务。
详见百度百科
二、Android中的Wi-Fi Direct
从Android4.0(API level 14)开始,开始支持Wi-Fi Direct,它可以在没有热点(hotspot)和网络连接(Internet)的情况下,实现点对点(P2P)的连接。Android的Framework提供了一组API,允许你发现和连接其它支持Wi-Fi Direct的设备。这种连接比蓝牙速度更快,通信距离更远。
三、部分代码及分析
下面通过分析一部分代码来介绍API的使用方法。其中//...代表一些省略掉的代码未显示。
首先使用Wi-Fi Direct,需要向你的清单文件添加 CHANGE_WIFI_STATE, ACCESS_WIFI_STATE 和 INTERNET 权限。
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" />
获取WifiP2pManager和Channel。WifiP2pManager是API中的主类,可以通过系统服务获取。Channel是app和Framework连接的通道,在WifiP2pManager调用initialize()方法初始化后返回一个Channel。
public class MainActivity extends Activity implements OnClickListener, PeerListListener, OnItemClickListener, ConnectionInfoListener { //... private WifiP2pManager manager; private Channel channel; @Override protected void onCreate(Bundle savedInstanceState) { //... manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); channel = manager.initialize(MainActivity.this, getMainLooper(), null); //... } //...}
接下来要要注册一个广播,用来接收Wi-Fi P2P连接时发出的广播。有以下几种广播:
WIFI_P2P_STATE_CHANGED_ACTION 表明Wi-Fi对等网络(P2P)是否已经启用
WIFI_P2P_PEERS_CHANGED_ACTION 表明可用的对等点的列表发生了改变
WIFI_P2P_CONNECTION_CHANGED_ACTION 表示Wi-Fi对等网络的连接状态发生了改变
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION 表示该设备的配置信息发生了改变
public class WiFiP2PReceiver extends BroadcastReceiver { private final String TAG = "WiFiP2PReceiver"; private Channel channel; private WifiP2pManager manager; private MainActivity activity; public WiFiP2PReceiver(Channel channel, WifiP2pManager manager, MainActivity activity) { super(); this.channel = channel; this.manager = manager; this.activity = activity; } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) { // 确定Wi-Fi Direct模式是否已经启用 int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) { // ... } else { // ... } } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { // 对等点设备列表改变 if (manager != null) { manager.requestPeers(channel, (PeerListListener) activity); } else { // ... } } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION .equals(action)) { // 连接状态改变 if (manager != null) { NetworkInfo networkInfo = (NetworkInfo) intent .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); if (networkInfo.isConnected()) { manager.requestConnectionInfo(channel, (ConnectionInfoListener) activity); } else { // ... } } else { // ... } } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION .equals(action)) { //连接设备信息改变 // ... } }}
在MainActivity的onResume()方法中注册,在onPause()方法中注销。
public class MainActivity extends Activity implements OnClickListener, PeerListListener, OnItemClickListener, ConnectionInfoListener { //... private final IntentFilter intentFilter = new IntentFilter(); private WiFiP2PReceiver mReceiver; //... @Override protected void onCreate(Bundle savedInstanceState) { //... // 表示Wi-Fi对等网络状态发生了改变 intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); // 表示可用的对等点的列表发生了改变 intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); // 表示Wi-Fi对等网络的连接状态发生了改变 intentFilter .addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); // 设备配置信息发生了改变 intentFilter .addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); //... } //... @Override protected void onResume() { super.onResume(); mReceiver = new WiFiP2PReceiver(channel, manager, this); registerReceiver(mReceiver, intentFilter); } @Override protected void onPause() { unregisterReceiver(mReceiver); super.onPause(); } //...}
使用WifiP2pManager的discoverPeers()方法搜索对等设备。ActionListener是一个监听接口,其方法在操作成功或失败时自动调用。失败时,带有失败原因reasonCode,其值含义如下:
WifiP2pManager.BUSY 表示Framework正忙,不能响应你的请求
WifiP2pManager.ERROR 表示内部错误
WifiP2pManager.P2P_UNSUPPORTED 表示你的设备不支持Wi-Fi P2P功能
manager.discoverPeers(channel,new WifiP2pManager.ActionListener() { @Override public void onSuccess() { //... } @Override public void onFailure(int reasonCode) { //... } });
当搜索到对等设备时,我们写好的BroadcastReceiver会收到一个带有 WIFI_P2P_PEERS_CHANGED_ACTION 动作的意图(Intent),此时调用 requestPeers()方法请求获取设备列表。这个方法需要一个PeerListListener接口。
public void onReceive(Context context, Intent intent) { String action = intent.getAction(); //... if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { // 对等点设备列表改变 if (manager != null) { manager.requestPeers(channel, (PeerListListener) activity); } else { //... } } //... }
在本例中,直接用MainActivity继承了此接口。当设备列表发生改变时,就会自动调用该接口中的onPeersAvailable()方法,设备列表在参数中获取。
public class MainActivity extends Activity implements OnClickListener, PeerListListener, OnItemClickListener, ConnectionInfoListener { //... @Override public void onPeersAvailable(WifiP2pDeviceList peers) { Collection<WifiP2pDevice> collection = peers.getDeviceList(); if (collection == null || collection.size() == 0) { //... } else { //更新显示列表 //... } //... } //...}
获取到设备列表后,我们就可以连接了。调用WifiP2pManager的connect()方法进行连接。 第二个参数是WifiP2pConfig对象,用来配置连接信息。其中device是要连接的设备,是一个WifiP2pDevice对象,deviceAddress是设备网卡MAC地址。WPS是Wi-Fi保护设置,这里把他设置成PBC(Push button configuration),和我们连接无线路由器时按下路由器上的wps按键功能类似。
WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = device.deviceAddress; config.wps.setup = WpsInfo.PBC; manager.connect(channel,config, new ActionListener() { @Override public void onSuccess() { // ... } @Override public void onFailure(int reason) { // ... } });
当连接成功时,我们写好的BroadcastReceiver会收到一个带有 WIFI_P2P_CONNECTION_CHANGED_ACTION 动作的意图,此时调用 requestConnectionInfo()方法请求获取设备列表。这个方法需要一个ConnectionInfoListener接口。
public void onReceive(Context context, Intent intent) { String action = intent.getAction(); //... if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION .equals(action)) { // 连接状态改变 // ... if (manager != null) { NetworkInfo networkInfo = (NetworkInfo) intent .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); if (networkInfo.isConnected()) { // ... manager.requestConnectionInfo(channel, (ConnectionInfoListener) activity); } else { // ... } } else { // ... } } // ... }
在本例中,直接用MainActivity继承了此接口。当设备列表发生改变时,就会自动调用该接口中的onConnectionInfoAvailable()方法,设备列表在参数中获取。
public class MainActivity extends Activity implements OnClickListener, PeerListListener, OnItemClickListener, ConnectionInfoListener { //... @Override public void onConnectionInfoAvailable(WifiP2pInfo info) { // ... } // ...}
在连接成功后,我们就可以发送和接收数据了,本例中传送的是图片。
首先来看发送数据,本例定义了一个传送图片的IntentService,利用IntentService的好处是可以在后台服务中自动另开线程完成任务,比Service更方便。发送数据用Socket,所需的目标设备地址、端口号、图片位置都通过Intent传过来。
public class FileTransferService extends IntentService { private static final String TAG = "FileTransferService"; private static final int SOCKET_TIMEOUT = 5000; public static final String ACTION_SEND_FILE = "com.ising99.wifidirecttest.SEND_FILE"; // ... @Override protected void onHandleIntent(Intent intent) { if (intent.getAction().equals(ACTION_SEND_FILE)) {// send file String uri = intent.getExtras().getString("uri"); String host = intent.getExtras().getString("host"); int port = intent.getExtras().getInt("port"); Socket socket = new Socket(); try { socket.bind(null); socket.connect(new InetSocketAddress(host, port), SOCKET_TIMEOUT); ContentResolver cr = getApplicationContext() .getContentResolver(); OutputStream os = socket.getOutputStream(); InputStream is = cr.openInputStream(Uri.parse(uri)); copyFile(is, os); } catch (Exception e) { Log.e(TAG, e.toString()); } finally { if (socket != null && socket.isConnected()) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } // ... } public static boolean copyFile(InputStream inputStream, OutputStream out) { byte buf[] = new byte[1024]; int len; try { while ((len = inputStream.read(buf)) != -1) { out.write(buf, 0, len); } out.close(); inputStream.close(); } catch (IOException e) { Log.d(TAG, e.toString()); return false; } return true; }}
在MainAcitiviy里,我们点击按钮打开图库选择图片。选定好图片后,启动定义好的IntentService发送图片。其中,connectedInfo是前面我们提到的,连接成功时保存的连接信息。
public class MainActivity extends Activity implements OnClickListener, PeerListListener, OnItemClickListener, ConnectionInfoListener { // ... @Override public void onClick(View v) { switch (v.getId()) { // ... case R.id.btn_send_image: Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivityForResult(intent, 20); break; //... } } //... @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 20) { Intent serviceIntent = new Intent(MainActivity.this, FileTransferService.class); Uri uri = data.getData(); serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE); serviceIntent.putExtra("uri", uri.toString()); serviceIntent.putExtra("host", connectedInfo.groupOwnerAddress.getHostAddress()); serviceIntent.putExtra("port", SOCKET_PORT); startService(serviceIntent); } } //...}
再来看接收数据,同样利用IntentService。接收数据用ServerSocket。接收的图片保存到本地。接收成功后自动打开图片。
public class FileTransferService extends IntentService { // ... public static final String ACTION_RECEIVE_FILE = "com.ising99.wifidirecttest.RECEIVE_FILE"; //... @Override protected void onHandleIntent(Intent intent) { //... if (intent.getAction().equals(ACTION_RECEIVE_FILE)) {//接收数据 try { int port = intent.getExtras().getInt("port"); ServerSocket serverSocket = new ServerSocket(port); Socket client = serverSocket.accept(); final File f = new File( Environment.getExternalStorageDirectory() + "/iSing99/WifiDirectShared_" + System.currentTimeMillis() + ".jpg"); Log.d("FileServerAsyncTask", f.getAbsolutePath()); File dirs = new File(f.getParent()); if (!dirs.exists()) { dirs.mkdirs(); } f.createNewFile(); InputStream inputstream = client.getInputStream(); copyFile(inputstream, new FileOutputStream( f)); serverSocket.close(); Toast.makeText(getApplicationContext(), "文件接收完成!", Toast.LENGTH_SHORT).show(); //打开图片 Intent viewIntent = new Intent(); viewIntent.setAction(android.content.Intent.ACTION_VIEW); viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); viewIntent.setDataAndType( Uri.parse("file://" + f.getAbsolutePath()), "image/*"); startActivity(viewIntent); } catch (IOException e) { Log.e("FileServerAsyncTask", e.toString()); } } } // ...}
在MainAcitivity的onConnectionInfoAvailable()方法中,若本机是群主,作为接收端,启动接收数据的IntentService。
@Override public void onConnectionInfoAvailable(WifiP2pInfo info) { connectedInfo = info; if (info.groupFormed && info.isGroupOwner) { // 我是群主,作为接收端接收信息 Intent serviceIntent = new Intent(MainActivity.this, FileTransferService.class); serviceIntent.setAction(FileTransferService.ACTION_RECEIVE_FILE); serviceIntent.putExtra("port", SOCKET_PORT); startService(serviceIntent); // ... } else { // ... } }
0 0
- Android Wi-Fi Direct 开发
- 【android】Android Wi-Fi Direct 开发指南
- Android Wi-Fi Direct 开发指南
- Android Wi-Fi Direct 开发指南
- Android Wi-Fi Direct 开发指南
- Wi-Fi Direct
- Wi-Fi Direct
- Wi-Fi Direct
- Wi-Fi Direct技术
- Wi-Fi Direct(Wi-Fi P2P)
- 全面检视Wi-Fi Direct
- Connecting with Wi-Fi Direct
- Wi-Fi Direct 亲身体验
- Connecting with Wi-Fi Direct
- Wi-Fi Direct协议详解
- Connecting with Wi-Fi Direct
- Connecting with Wi-Fi Direct 与Wi-Fi直接连接
- Wi-Fi Direct插手产品应用
- 编程之美:高效率地安排见面会
- PHP采集类 Snoopy.class.php
- ios中http 和https 协议的访问
- Android中半透明Activity效果另法
- 转载_TCP协议三次握手过程分析
- Android Wi-Fi Direct 开发
- 初始化与清理(构造函数初始化,可变参数列表,enum)
- PB 中用带参数的 SQL 语句字符串检索数据并动态生成Datawindow
- 无题
- 怎样激发创造力[转]
- 转贴:背单词最科学的方法
- C/C++中的日期和时间 time_t与struct tm转换[转]
- CAD图转化为ArcGIS的shapefile图
- 部分ARCGIS菜单翻译——初练