android官方文档之路--Wi-Fi Peer-to-Peer

本文介绍如何利用Wi-Fi P2P技术实现安卓设备间的直接连接与数据传输,包括创建BroadcastReceiver接收系统广播、发现并连接节点以及通过socket进行数据交换的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Wi-Fi peer-to-peer (P2P) 允许安卓4.0或更高的设备与适当的硬件连接直接通过Wi-Fi无线网络连接,而没有一个中间接入点。使用这些APIs,当设备都支持Wi-Fi时,可以发现并连接到这些设备上。然后建立一个快速连接,该连接距离比蓝牙连接远。可以实现用户之间的数据共享,如多人游戏或照片共享应用程序。

WiFi API 包含以下主要的方面:

  1. WifiP2pManager类中包含了一些方法允许去发现,请求和连接节点。
  2. WifiP2pManager方法调用成功还是失败,可以通过listeners获得通知。当调用WifiP2pManager方法,每个方法可以接受一个特定的listener作为一个参数。
  3. Intent会通知你由WI-FI P2P框架检测的特定事件。例如,断开一个连接或者发现一个新的节点。

这是经常使用到的API三个主要组件。例如,提供一个WifiP2pManager.ActionListener去调用discoverPeers()。因此可以获得ActionListenr.onSuccess()和ActionListener.onFailure()方法的通知。如果discoverPeers()方法发现节点列表发生改变,一个包含WIFI_P2P_PEERS_CHANGED_ACTION的intent将被广播出去。

API Overview

WifiPpManager类提供一些方法去允许你设备上的wifi硬件去做类似于发现和连接节点的事。
这里写图片描述
这里写图片描述
这里写图片描述

Creating a Broadcast Receiver for Wi-Fi P2P Intents

一个broadcast receiver允许去接受intents broadcast,因此应用程序可以回应你感兴趣的事件。创建一个广播接收机处理Wi-Fi P2P意图的基本步骤如下:

  1. 创建一个继承BroadcastReceiver的类。在该类的构造函数中,需要有WifiP2pManager,WifiP2pManager.Channel,和broadcast receiver将注册的activity。这允许broadcast receiver给activity发送更新,如果需要,可以访问wifi硬件和通信信道。
  2. 在broadcast receiver中,在onReceive()中检查你感兴趣的intents。完成任何必要的actions都依赖于接受到的Intent。例如,如果broadcast receiver接受一个包含WIFI_P2P_PEERS_CHANGED_ACTION的intent,你可以调用requestPeers()方法获取一系列当前被发现的节点。

下面的代码显示了怎样去创建一个典型的broadcast receiver。

public class WiFiDirectBroadcastReceiver extends BroadcastReceiver{
   private WifiP2pManager mManager;
   private WifiP2pManager.Channel mCannel;
   private WiFiDirectActivity mActivity;

   public WiFiDirectBroadcastReceiver(WifiP2pManager manager,WifiP2pManager.Channel channel,WiFiDirectActivity activity)
   {
      super();
      this.mManager=manager;
      this.mCannel=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,并通知适当的活动
      } 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状态改变时
      }
   }
}

Creating a Wi-Fi P2P Application

创建一个Wi-Fi P2P应用涉及到为应用创建和注册一个broadcast receiver,discovering peers, connecting to a peer, and transferring data to a peer。

Initial setup

在使用Wi-Fi P2P APIs,必须确保你的应用程序访问硬件并且该设备支持Wi-Fi P2P协议。如果支持Wi-Fi P2P,可以获得一个WifiP2pManager的实例,创建和注册你的broadcast receiver,同时使用Wi-Fi P2P APIs。

1.在Android manifest中添加Wi-Fi硬件的权限并声明正确的最小的SDK版本。

<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" />

2.检查Wi-Fi P2P是否被支持。检查的地方是当broadcast receiver接受到WIFI_P2P_STATE_CHANGED_ACTION intent。通知你的Wi-Fi网络状态的活动,并作出相应的反应:

@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 is enabled
        } else {
            // Wi-Fi P2P is not enabled
        }
    }
    ...
}

3.在activity的onCreate()方法,获得一个WifiPpManager实例并且通过initialize()方法使用Wi-Fi P2P框架注册你的应用程序。该方法返回一个wifiP2pManager.Channel,用来将你的应用程序与Wi-Fi P2P框架的连接。

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);
    ...
}

4.创建一个Intent filter并且添加一些broadcast receiver需要的intents。

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);
    ...
}

5.在你的activity的onResume()方法中注册你的broadcast receiver在onPause()方法中注销

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(mReceiver, mIntentFilter);
}
@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(mReceiver);
}

当你获得一个WiFiP2pManager.Channel同时配置一个broadcast receiver,你的应用程序可以调用Wi-Fi P2P方法并且接受Wi-Fi P2P intents。

Discovering peers

为了发现可连接的节点,调用discoverPeers()去检测范围内可用的节点。该功能的实现是异步的,并且如果你创建了WifiP2pManager.ActionListener,将通过onSuccess()和onFailure()方法将success或failure信息返回给你的应用程序。

mManager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
    @Override
    public void onSuccess() {
        ...
    }

    @Override
    public void onFailure(int reasonCode) {
        ...
    }
});

如果发现过程成功并检测到节点,系统将会广播WIFI_P2P_PEERS_CHANGED_ACTION intent,你可以通过监听broadcast receiver获得一系列节点。当你的应用程序接收到WIFI_P2P_PEERS_CHANGED_ACTION intent,你可以通过requestPeers()获得一系列发现的节点。

PeerListListener myPeerListListener;
...
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
    if (mManager != null) {

        mManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
    @Override
    public void onPeersAvailable(WifiP2pDeviceList peers) {
            //peers为wifiP2pDevice的集合,保存了寻找到的所有设备的信息
        }
        });
    }
}

requestPeers()方法也是异步,当一系列节点可用时,onPeersAvailable()方法会通知你的activity,onPeersAvailable()定义在WifiP2pManager.PeerListListener接口中。该方法将提供一个WifiP2pDeviceList,你可以通过遍历WifiP2pDeviceList找到你想要连接的节点。

Connecting to peers

当你找到你想连接的设备,调用connect()方法去连接设备。该方法会返回一个WifiP2pConfig对象,该对象包含了连接的目标设备的信息。

//从WifiP2pDeviceList中获得一个节点
WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();
//设置连接地址
config.deviceAddress = device.deviceAddress;
mManager.connect(mChannel, config, new ActionListener() {

    @Override
    public void onSuccess() {
        //success logic
    }

    @Override
    public void onFailure(int reason) {
        //failure logic
    }
});

Transferring data

当连接建立,你可以通过socket在设备之间传递数据。传递数据的基本步骤如下:
1.创建一个ServerSocket。该socket在指定的端口等待来自client的连接,运行在后台线程中。
2.创建一个客户端socket。该客户端使用server socket的端口和IP地址去连接服务设备。
3.从客户端中发送数据给服务端。当客户端socket成功与server socket连接,客户端以字节流的方式将数据发送给服务端。
4.Server socket等待来自客户端的连接(通过accept()方法)。该方法会阻塞直到客户端连接,因此在线程中调用。当连接发生,服务端可以获得来自客户端的数据。

下面的实例代码来自Wi-Fi P2P Demo,显示怎么创建一个client-server
socket连接,将JPEG图片通过service从client端传递给server。

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 {

            /**
             * 创建一个server socket同时等待client的连接
             */
            ServerSocket serverSocket = new ServerSocket(8888);
            Socket client = serverSocket.accept();

            /**
             *获得来自client的连接,将来自client的inputStream保
             *存到对应的文件中
             */
            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;
        }
    }
    @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);
        }
    }
}

在客户端,通过一个socket与server socket相连,并传输数据

Context context = this.getApplicationContext();
String host;
int port;
int len;
Socket socket = new Socket();
byte buf[]  = new byte[1024];
...
try {
    /**
     * 创建一个client socket,设置需连接的服务端的IP地址,端口号和
     * 超时时间
     */
    socket.bind(null);
    socket.connect((new InetSocketAddress(host, port)), 500);

    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
            }
        }
    }
}

总结

使用Wi-Fi P2P的大致流程:

  1. 实现一个BroadcastReceiver,用于接收系统广播的intent。
  2. 通过discoverPeers方法查找可用的节点。
  3. 通过connect方法连接选择的节点。
  4. 通过client-server socket 实现数据的传递。
    一个简单的例子:android手机之间通过Wifi传递图片示例
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值