Android官方开发文档Training系列课程中文版:连接无线设备之通过WIFI创建P2P连接
原文地址:http://android.xsoftlab.net/training/connect-devices-wirelessly/wifi-direct.html#permissions
Wi-Fi peer-to-peer (P2P) APIs可以使程序与附近的设备进行直接通讯,Android的Wi-Fi P2P框架由Wi-Fi Direct™提供技术支持。WI-FI P2P技术可以使程序快速的检索附近的设备并与之建立连接。其覆盖范围超过蓝牙的覆盖范围。
这节课会学习如何通过WI-FI P2P技术搜索附近的设备并与之建立连接。
设置应用权限
如果要使用WI-FI P2P技术,需要在程序的清单文件中添加CHANGE\_WIFI\_STATE, ACCESS\_WIFI\_STATE, INTERNET三项权限。Wi-Fi P2P并不需要互联网连接,但是它需要使用标准的Java Socket通讯技术,所以需要使用INTERNET权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.nsdchat" ... <uses-permission android:required="true" android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:required="true" android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:required="true" android:name="android.permission.INTERNET"/> ...
设置广播接收器及P2P管理员
使用WI-FI P2P技术,需要监听广播意图,广播意图会通知程序某些事件的发生。所以在程序中需要添加IntentFilter,并设置其监听以下行为:
WIFI\_P2P\_STATE\_CHANGED\_ACTION
监听Wi-Fi P2P是否可用
WIFI\_P2P\_PEERS\_CHANGED\_ACTION
监听WI-FI P2P列表的变化
WIFI\_P2P\_CONNECTION\_CHANGED\_ACTION
监听Wi-Fi P2P的连接状态
WIFI\_P2P\_THIS\_DEVICE\_CHANGED\_ACTION
监听设备的配置变化
private final IntentFilter intentFilter = new IntentFilter();...@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Indicates a change in the Wi-Fi P2P status. intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); // Indicates a change in the list of available peers. intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); // Indicates the state of Wi-Fi P2P connectivity has changed. intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); // Indicates this device's details have changed. intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); ...}
在onCreate()方法的末尾,需要获取WifiP2pManager的实例,然后调用它的initialize()方法。这个方法会返回一个WifiP2pManager.Channel的对象,它用于使程序应用层与Wi-Fi P2P框架建立连接。
@OverrideChannel mChannel;public void onCreate(Bundle savedInstanceState) { .... mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); mChannel = mManager.initialize(this, getMainLooper(), null);}
接下来创建一个新的BroadcastReceiver类,它用于监听系统的Wi-Fi P2P的状态变化,在onReceive()方法中,需要添加一些基本的判断条件来处理每种P2P的状态并处理:
@Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) { // Determine if Wifi P2P mode is enabled or not, alert // the Activity. int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) { activity.setIsWifiP2pEnabled(true); } else { activity.setIsWifiP2pEnabled(false); } } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { // The peer list has changed! We should probably do something about // that. } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { // Connection state changed! We should probably do something about // that. } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) { DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager() .findFragmentById(R.id.frag_list); fragment.updateThisDevice((WifiP2pDevice) intent.getParcelableExtra( WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)); } }
最后,将广播接收器与意图过滤器添加到上下文中,并需要在Activity暂停的时候注销这个广播接收器。放置这些代码的最佳位置就是onResume()方法与onPause()方法。
/** register the BroadcastReceiver with the intent values to be matched */ @Override public void onResume() { super.onResume(); receiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this); registerReceiver(receiver, intentFilter); } @Override public void onPause() { super.onPause(); unregisterReceiver(receiver); }
初始化端点搜索
如果开始要使用Wi-Fi P2P来搜索附近的设备,需要调用discoverPeers()方法。这个方法要求传入以下参数:
- 在初始化P2P管理员时获得的WifiP2pManager.Channel对象。
- WifiP2pManager.ActionListener的实现,它用于监听搜索的成功与否。
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { // Code for when the discovery initiation is successful goes here. // No services have actually been discovered yet, so this method // can often be left blank. Code for peer discovery goes in the // onReceive method, detailed below. } @Override public void onFailure(int reasonCode) { // Code for when the discovery initiation fails goes here. // Alert the user that something went wrong. }});
要记住,这里只是初始化了端点搜索。discoverPeers()方法启动搜索进程后会立即返回。如果端点搜索进程成功初始化,那么系统会自动调用初始化时设置的回调方法。另外,端点搜索功能会一直保持在活动状态,直到连接初始化完成或者P2P组建立连接。
获取端点列表
接下来需要获得并处理端点列表。首先需要实现WifiP2pManager.PeerListListener接口,它提供了WI-FI P2P所搜索到的端点信息。下面的代码演示了这个过程:
private List peers = new ArrayList(); ... private PeerListListener peerListListener = new PeerListListener() { @Override public void onPeersAvailable(WifiP2pDeviceList peerList) { // Out with the old, in with the new. peers.clear(); peers.addAll(peerList.getDeviceList()); // If an AdapterView is backed by this data, notify it // of the change. For instance, if you have a ListView of available // peers, trigger an update. ((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged(); if (peers.size() == 0) { Log.d(WiFiDirectActivity.TAG, "No devices found"); return; } } }
现在需要修改广播接收器的onReceive()方法,在收到WIFI\_P2P\_STATE\_CHANGED\_ACTION行为时调用requestPeers()方法。在这之前需要将监听器的实例传入到广播接收器中,常规的方式是在广播接收器的构造方法中将这个监听器传进来。、
public void onReceive(Context context, Intent intent) { ... else 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 (mManager != null) { mManager.requestPeers(mChannel, peerListListener); } Log.d(WiFiDirectActivity.TAG, "P2P peers changed"); }...}
现在,WIFI\_P2P\_STATE\_CHANGED\_ACTION的行为将会触发端点列表的更新。
连接到端点
为了可以连接到端点,需要创建一个新的WifiP2pConfig对象,然后将WifiP2pDevice中的数据拷贝进这个对象中。WifiP2pDevice代表的将要连接的设备。然后调用connect()方法。
@Override public void connect() { // Picking the first device found on the network. WifiP2pDevice device = peers.get(0); WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = device.deviceAddress; config.wps.setup = WpsInfo.PBC; mManager.connect(mChannel, config, new ActionListener() { @Override public void onSuccess() { // WiFiDirectBroadcastReceiver will notify us. Ignore for now. } @Override public void onFailure(int reason) { Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.", Toast.LENGTH_SHORT).show(); } }); }
上述代码中的WifiP2pManager.ActionListener接口只有在初始化成功或者失败的情况下才会调用。如果要监听连接状态的变化,需要实现WifiP2pManager.ConnectionInfoListener接口,它的方法onConnectionInfoAvailable()会在连接状态发生变化的时候回调。在多台设备连接一台设备的情况下(比如多人互动的游戏或者聊天类的APP),其中一台设备会被指定为”group owner”。
@Override public void onConnectionInfoAvailable(final WifiP2pInfo info) { // InetAddress from WifiP2pInfo struct. InetAddress groupOwnerAddress = info.groupOwnerAddress.getHostAddress()); // After the group negotiation, we can determine the group owner. if (info.groupFormed && info.isGroupOwner) { // Do whatever tasks are specific to the group owner. // One common case is creating a server thread and accepting // incoming connections. } else if (info.groupFormed) { // The other device acts as the client. In this case, // you'll want to create a client thread that connects to the group // owner. } }
现在回到广播接收器的onReceive()方法,修改监听WIFI\_P2P\_CONNECTION\_CHANGED\_ACTION的部分,当这个意图接收到时,调用requestConnectionInfo()方法。这是一个异步方法,所以结果会通过参数:连接信息监听器回调回来。
... } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { if (mManager == null) { return; } NetworkInfo networkInfo = (NetworkInfo) intent .getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); if (networkInfo.isConnected()) { // We are connected with the other device, request connection // info to find group owner IP mManager.requestConnectionInfo(mChannel, connectionListener); } ...
更多相关文章
- Android编译本地C++程序方法
- Android开发者网站打不开的解决方法
- android sdk manager 无法更新解决方法
- Android下app生成coredump方法
- Android使用webview调用js方法传参,参数无法传入的问题
- android6.0源码分析之Runtime的初始化
- Android中bindService基本使用方法概述
- Unity 编辑器环境下不能正确加载Android Assetbundle 中的 Shade