「Android」WiFiP2P入门
应用 WiFi 直连 (WiFiP2P) 技术,能够让具备相应硬件的 Android 4.0(API 级别 14)或更高版本设施在没有两头接入点的状况下,通过 WiFi 进行间接互联。应用这些 API,能够实现反对 WiFi P2P 的设施间互相发现和连贯,从而取得比蓝牙连贯更远距离的高速连贯通信成果。
为了实现一个根底的WiFiP2P,大抵分为如下局部:
- 权限申请
- 初始化WiFiP2P的相干对象
- 定义监听WiFiP2P的播送接收器
- 连贯设施
对于WiFiP2P中的群组,大抵分为如下局部:
- 创立群组
- 连贯群组
- 移除群组
权限申请
首先,在AndroidManifest.xml中,对WiFi相干权限进行动态申请:
<uses-sdk android:minSdkVersion="14" /> <!-- WiFi相干权限 --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <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" />
若后续还须要读写权限则增加:
<!-- 读写权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
而后,在 Android 6.0 及更高版本中,局部危险权限(Dangerous Permissions)权限须要在运行时申请用户批准(动静申请):
private void checkPermission() { String[] permissions = new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION }; for (String permission : permissions) { if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) { Log.i(TAG, permission + " granted."); } else { ActivityCompat.requestPermissions(this, permissions, 0); Log.w(TAG, permission + " not granted."); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == 0) { for (int result : grantResults) { if (result == PackageManager.PERMISSION_GRANTED) { continue; } else { Toast.makeText(this, "权限未获取", Toast.LENGTH_SHORT).show(); } } } super.onRequestPermissionsResult(requestCode, permissions, grantResults); }
初始化
首先,须要创立:
- WifiP2pManager 对象
- WifiP2pManager.Channel 对象
- WiFiDirectBroadcastReceiver 对象(稍后介绍该播送接收器的定义)
- IntentFilter 对象
private WifiP2pManager mManager; private WifiP2pManager.Channel mChannel; private WiFiDirectBroadcastReceiver mReceiver; private IntentFilter mIntentFilter; private void initWifip2pHelper() { // 创立 WifiP2pManager 对象 mManager = (WifiP2pManager) getSystemService(WIFI_P2P_SERVICE); // 创立 WifiP2pManager.Channel 对象 mChannel = mManager.initialize(this, Looper.getMainLooper(), new WifiP2pManager.ChannelListener() { @Override public void onChannelDisconnected() { Log.i(TAG, "onChannelDisconnected: "); } }); // 创立 WiFiDirectBroadcastReceiver 对象 mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this); // 创立 IntentFilter 对象 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); mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); }
其中, WiFiDirectBroadcastReceiver 对象想要监听的播送,与 IntentFilter 对象增加的action雷同。
而后,在 Activity 的onResume()办法中注册播送接收器,在 Activity 的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); }
定义监听WiFiP2P的播送接收器
监听WiFiP2P的播送接收器 WiFiDirectBroadcastReceiver 类具体定义如下:
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "WiFiDirectBroadcastReceiver"; private WifiP2pManager mManager; private WifiP2pManager.Channel mChannel; private Wifip2pActivity mActivity; private List<WifiP2pDevice> mWifiP2pDeviceList = new ArrayList<>(); WifiP2pManager.PeerListListener mPeerListListener = new WifiP2pManager.PeerListListener() { @Override public void onPeersAvailable(WifiP2pDeviceList wifiP2pDeviceList) { mWifiP2pDeviceList.clear(); mWifiP2pDeviceList.addAll(wifiP2pDeviceList.getDeviceList()); } }; /** * 构造方法 * * @param manager WifiP2pManager对象 * @param channel WifiP2pManager.Channel对象 * @param activity Wifip2pActivity 对象 */ public WiFiDirectBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, Wifip2pActivity activity) { super(); this.mManager = manager; this.mChannel = channel; this.mActivity = activity; } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); switch (action) { case WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION: // Check to see if Wi-Fi is enabled and notify appropriate activity Log.i(TAG, "onReceive: WIFI_P2P_STATE_CHANGED_ACTION"); int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) { // Wifi P2P is enabled Log.i(TAG, "onReceive: Wifi P2P is enabled"); mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.d(TAG, "onSuccess: "); } @Override public void onFailure(int i) { Log.d(TAG, "onFailure: "); } }); } else { // Wi-Fi P2P is not enabled Log.i(TAG, "onReceive: Wi-Fi P2P is not enabled"); } break; case WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION: // Call WifiP2pManager.requestPeers() to get a list of current peers Log.i(TAG, "onReceive: WIFI_P2P_PEERS_CHANGED_ACTION"); if (mManager == null) { return; } mManager.requestPeers(mChannel, mPeerListListener); break; case WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION: // Respond to new connection or disconnections Log.i(TAG, "onReceive: WIFI_P2P_CONNECTION_CHANGED_ACTION"); // NetworkInfo NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); // WifiP2pInfo WifiP2pInfo wifiP2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO); // WifiP2pGroup WifiP2pGroup wifiP2pGroup = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP); if (networkInfo.isConnected()) { if (wifiP2pInfo.isGroupOwner) { Toast.makeText(mActivity, "设施连贯,本设施为GO", Toast.LENGTH_LONG).show(); } else { Toast.makeText(mActivity, "设施连贯,本设施非GO", Toast.LENGTH_LONG).show(); } } else { Toast.makeText(mActivity, "设施断开", Toast.LENGTH_LONG).show(); } break; case WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: // Respond to this device's wifi state changing Log.i(TAG, "onReceive: WIFI_P2P_THIS_DEVICE_CHANGED_ACTION"); WifiP2pDevice device = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE); Log.d(TAG, "onReceive: " +device.deviceAddress); break; case WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION: Log.i(TAG, "onReceive: WIFI_P2P_DISCOVERY_CHANGED_ACTION"); break; } }}
上述播送接收器用于监听系统对于WiFiP2P相干的播送。通常在onReceive()办法中,通过intent.getAction()办法获取到action,并依据action去匹配不同的对于WiFiP2P相干的播送,别离为:
- WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION
- WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION
- WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION
- WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
- WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION
WIFI_P2P_STATE_CHANGED_ACTION:WiFiP2P状态产生扭转时的播送
WiFiP2P具体有两个状态:
- WifiP2pManager.WIFI_P2P_STATE_ENABLED:可用
- WifiP2pManager.WIFI_P2P_STATE_DISABLED:不可用
而该状态的获取是由:
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
当WiFiP2P状态为可用时,调用discoverPeers()办法开始搜寻左近WiFiP2P设施:
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.d(TAG, "onSuccess: "); } @Override public void onFailure(int i) { Log.d(TAG, "onFailure: "); } });
WIFI_P2P_PEERS_CHANGED_ACTION:发现左近WiFiP2P设施时的播送
当搜寻发现左近存在WiFiP2P设施时,调用requestPeers()办法开始获取左近WiFiP2P设施列表:
mManager.requestPeers(mChannel, mPeerListListener);
当胜利获取左近WiFiP2P设施列表后,会回调侦听器 WifiP2pManager.PeerListListener 中的onPeersAvailable()办法,并传递一个 WifiP2pDeviceList 对象作为参数,能够用一个 List<WifiP2pDevice> 对象接管并保留该参数:
WifiP2pManager.PeerListListener mPeerListListener = new WifiP2pManager.PeerListListener() { @Override public void onPeersAvailable(WifiP2pDeviceList wifiP2pDeviceList) { mWifiP2pDeviceList.clear(); mWifiP2pDeviceList.addAll(wifiP2pDeviceList.getDeviceList()); } };
WIFI_P2P_CONNECTION_CHANGED_ACTION:连贯状态产生扭转时的播送
当连贯状态产生扭转时(如连贯了一个设施,断开了一个设施),都会接管到该播送。当接管到该播送后,能够应用intent.getParcelableExtra()办法别离获取到 NetworkInfo , WifiP2pInfo , WifiP2pGroup 对象:
// 获取 NetworkInfo 对象 NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); // 获取 WifiP2pInfo 对象 WifiP2pInfo wifiP2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO); // 获取 WifiP2pGroup 对象 WifiP2pGroup wifiP2pGroup = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);
获取到上述对象后,能够应用networkInfo.isConnected()办法来判断连贯状态具体是“设施连贯”还是“设施断开”,还能够依据wifiP2pInfo.isGroupOwner的值来判断设施是否为GroupOwner:
if (networkInfo.isConnected()) { if (wifiP2pInfo.isGroupOwner) { Toast.makeText(mActivity, "设施连贯,本设施为GroupOwner", Toast.LENGTH_LONG).show(); } else { Toast.makeText(mActivity, "设施连贯,本设施非GroupOwner", Toast.LENGTH_LONG).show(); } } else { Toast.makeText(mActivity, "设施断开", Toast.LENGTH_LONG).show(); }
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:以后设施状态产生扭转时的播送
通常能够在这个播送中获取到以后设施的信息:
WifiP2pDevice device = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION:搜寻状态产生扭转时的播送
启动搜寻:
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.d(TAG, "onSuccess: "); } @Override public void onFailure(int i) { Log.d(TAG, "onFailure: "); } });
进行搜寻:
mManager.stopPeerDiscovery(mChannel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.d(TAG, "onSuccess: "); } @Override public void onFailure(int i) { Log.d(TAG, "onFailure: "); } });
连贯设施
首先,抉择一个须要连贯的设施,并获取到该设施的 WifiP2pDevice 对象。而后,判断该设施的状态,设施状态通常为三种:
- WifiP2pDevice.AVAILABLE:可连贯
- WifiP2pDevice.CONNECTED:已连贯
- WifiP2pDevice.INVITED:已申请连贯
依据不同的设施状态,进行不同的具体逻辑:
@Override public void onClick(View view) { // 获取到该设施的 WifiP2pDevice 对象 WifiP2pDevice wifiP2pDevice = mWifiP2pDeviceList.get(viewHolder.getAdapterPosition()); // 判断该设施的状态 switch (wifiP2pDevice.status) { case WifiP2pDevice.AVAILABLE: // 申请连贯 WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = wifiP2pDevice.deviceAddress; mManager.connect(mChannel, config, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.i(TAG, "connect success."); } @Override public void onFailure(int i) { Log.i(TAG, "connect failed."); } }); break; case WifiP2pDevice.CONNECTED: // 断开连接 mManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.i(TAG, "removeGroup success."); } @Override public void onFailure(int i) { Log.i(TAG, "removeGroup failed."); } }); break; case WifiP2pDevice.INVITED: // 敞开连贯申请 mManager.cancelConnect(mChannel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.i(TAG, "cancelConnect success."); } @Override public void onFailure(int i) { Log.i(TAG, "cancelConnect failed."); } }); break; } }
创立群组
GroupOwner创立Group:
private static final String NETWORKNAME_P60 = "DIRECT-HUAWEI-P60"; private static final String PASSPHRASE_P60 = "12345678"; private static void createWiFiP2PGroup(final Activity context, final WifiP2pManager manager, final WifiP2pManager.Channel channel) { WifiP2pConfig config = new WifiP2pConfig.Builder() .setGroupOperatingBand(WifiP2pConfig.GROUP_OWNER_BAND_AUTO) .setNetworkName(NETWORKNAME_P60) .setPassphrase(PASSPHRASE_P60) .build(); manager.createGroup(channel, config, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.i(TAG, "onSuccess: createGroup"); Toast.makeText(context, "onSuccess: createGroup", Toast.LENGTH_SHORT).show(); } @Override public void onFailure(int i) { Log.i(TAG, "onFailure: createGroup " + i); Toast.makeText(context, "onFailure: createGroup " + i, Toast.LENGTH_SHORT).show(); } }); }
连贯群组
Client连贯GroupOwner:
public static void connectWiFiP2P(final Activity context, final WifiP2pManager manager, final WifiP2pManager.Channel channel, final WifiP2pDevice wifiP2pDevice) { // 如果连贯对象为群组GroupOwner if (wifiP2pDevice.isGroupOwner()) { Log.d(TAG, "connectWiFiP2P: " + wifiP2pDevice.deviceName); WifiP2pConfig config; if (needPassphrase) { // 以PIN的形式连贯 config = new WifiP2pConfig.Builder() .setNetworkName(NETWORKNAME_iPhone) .setPassphrase(PASSPHRASE_iPhone) .build(); } else { // 以默认的形式连贯 config = new WifiP2pConfig(); config.deviceAddress = wifiP2pDevice.deviceAddress; } manager.connect(channel, config, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.i(TAG, "onSuccess: connect"); } @Override public void onFailure(int i) { Log.i(TAG, "onFailure: connect " + i); } }); } }
移除群组
GroupOwner移除Group:
manager.requestGroupInfo(channel, new WifiP2pManager.GroupInfoListener() { @Override public void onGroupInfoAvailable(WifiP2pGroup wifiP2pGroup) { if (wifiP2pGroup != null) { Log.i(TAG, "onGroupInfoAvailable: wifiP2pGroup != null"); manager.removeGroup(channel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { Log.i(TAG, "onSuccess: removeGroup"); } @Override public void onFailure(int i) { Log.i(TAG, "onFailure: removeGroup"); } }); } else { Log.i(TAG, "onGroupInfoAvailable: wifiP2pGroup == null"); } } });
参考文档
WLAN 直连(对等连贯或 P2P)概览
通过 Wi-Fi 直连创立点对点连贯
Android WiFi P2P开发实际笔记