最近的项目需要实现一个 Android 手机之间无网络传输文件的功能,就发现了 Wifi P2P(Wifi点对点)这么一个功能,最后也实现了通过 Wifi 隔空传输文件的功能,这里我也来整理下代码,分享给大家。
Wifi P2P 是在 Android 4.0 以及更高版本系统中加入的功能,通过 Wifi P2P 可以在不连接网络的情况下,直接与配对的设备进行数据交换。相对于蓝牙,Wifi P2P 的搜索速度和传输速度更快,传输距离更远
实现的效果如下所示:
一般而言,开发步骤分为以下几点:
在 AndroidManifest 中声明相关权限(网络和文件读写权限)
获取 WifiP2pManager ,注册相关广播监听Wifi直连的状态变化
指定某一台设备为服务器(用来接收文件),创建群组并作为群主存在,在指定端口监听客户端的连接请求,等待客户端发起连接请求以及文件传输请求
客户端(用来发送文件)主动搜索附近的设备,加入到服务器创建的群组,获取服务器的IP地址,向其发起文件传输请求
校验文件完整性
一、声明权限
Wifi P2P 技术并不会访问网络,但由于会使用到 Java socket,所以需要申请网络权限。此外,由于是要实现文件互传,所以也需要申请SD卡读写权限。
<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" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
二、注册广播
与 Wifi P2P 相关的广播有以下几个:
WIFI_P2P_STATE_CHANGED_ACTION( 用于指示 Wifi P2P 是否可用 )
WIFI_P2P_PEERS_CHANGED_ACTION( 对等节点列表发生了变化 )
WIFI_P2P_CONNECTION_CHANGED_ACTION( Wifi P2P 的连接状态发生了改变 )
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION( 本设备的设备信息发生了变化 )
当接收到这几个广播时,我们都需要到 WifiP2pManager (对等网络管理器)来进行相应的信息请求,此外还需要用到 Channel 对象作为请求参数
mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mWifiP2pManager.initialize(this, getMainLooper(), this);
当收到WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION 广播时,可以判断当前 Wifi P2P是否可用
int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
mDirectActionListener.wifiP2pEnabled(true);
} else {
mDirectActionListener.wifiP2pEnabled(false);
}
当收到WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION 广播时,意味设备周围的可用设备列表发生了变化,可以通过 requestPeers 方法得到可用的设备列表,之后就可以选择当中的某一个设备进行连接操作
mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() { @Override
public void onPeersAvailable(WifiP2pDeviceList peers) {
mDirectActionListener.onPeersAvailable(peers.getDeviceList());
}
});
当收到WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION 广播时,意味着 Wifi P2P 的连接状态发生了变化,可能是连接到了某设备,或者是与某设备断开了连接
NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);if (networkInfo.isConnected()) {
mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() { @Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
mDirectActionListener.onConnectionInfoAvailable(info);
}
});
Log.e(TAG, "已连接p2p设备");
} else {
mDirectActionListener.onDisconnection();
Log.e(TAG, "与p2p设备已断开连接");
}
如果是与某设备连接上了,则可以通过requestConnectionInfo 方法获取到连接信息
当收到WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION 广播时,则可以获取到本设备变化后的设备信息
(WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)
可以看出 Wifi P2P 的接口高度异步化,到现在已经用到了三个系统的回调函数,一个用于 WifiP2pManager 的初始化,两个用于在广播中异步请求数据,为了简化操作,此处统一使用一个自定义的回调函数,方法含义与系统的回调函数一致
public interface DirectActionListener extends WifiP2pManager.ChannelListener {
void wifiP2pEnabled(boolean enabled);
void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo);
void onDisconnection();
void