当前位置: 首页 > 工具软件 > Alliance P2P > 使用案例 >

Wifi P2P 翻译自developer.android.com——API Guides

董品
2023-12-01

WifiP2P允许Android4.0以及以上的设备,通过wifi直接和其他设备相连,而不需要中继网络(Android的wifi p2p框架使用了Wifi Alliance的认证的程序)。使用这些API,你可以发现和连接其他使用Wifi P2pd的设备,,并且通过一个高速的连接进行通信,它的速度远远高于蓝牙连接。这对于要分享数据给其他应用的app来说十分有用,比如说多玩家游戏,或者分享照片的应用。


Wifi p2p的API中包含下面的 主要部分:

-让你可以发现、请求、连接其他设备的的方法。在WifiP2pManger类当中。

- 可以让你在WifiP2PManager中的方法被调用成功或者失败进行通知的的Listener。

- 在Wifi P2P框架发生变化的时候通知的特定的Intent,比如说意外断开连接或者一个新的连接发现的时候。


你会经常一起使用这API的三个主要组件。例如,你可以提供一个WifiP2pManager.ActionListener对象,这样在调用discoverPeers()的时候可以通过ActionListener.onSuccess()和ActionListener.onFailure()来被通知。如果discoverPeers()方法发现配对列表发生变化时候,也会发出WIFI_P2P_PEERS_CHANGED_ACTION 的intent广播。


Method Description
initialize() Registers the application with the Wi-Fi framework. This must be called before calling any other Wi-Fi P2P method.
使用wifi框架注册应用。这个方法应该在所有的方法之前调用。
connect() Starts a peer-to-peer connection with a device with the specified configuration.
使用特定的配置,开始和一个设备进行点对点连接。
cancelConnect() Cancels any ongoing peer-to-peer group negotiation.
取消任何进行中的 点对点组协商。
requestConnectInfo() Requests a device's connection information.
获取设备的连接信息。
createGroup() Creates a peer-to-peer group with the current device as the group owner.
使用当前的设备作为group owner创建点对点连接。
removeGroup() Removes the current peer-to-peer group.
移除当前的点对点组。
requestGroupInfo() Requests peer-to-peer group information.
获取当前点对点小组的信息。
discoverPeers() Initiates peer discovery
初始化 配对发现。
requestPeers() Requests the current list of discovered peers.
获取当前的的发现配对的列表。

WifiP2pManager 方法可以让你传入一个listener,这样Wifi P2P框架可以通过其中的方法调用来通知的你的activity状态。

可以使用的listener以及使用这些listener的WifiP2pManager的方法在下面的表中描述。

Table 2. Wi-Fi P2P Listeners

Listener interface Associated actions相关的动作
WifiP2pManager.ActionListener connect()cancelConnect()createGroup()removeGroup(), anddiscoverPeers()
WifiP2pManager.ChannelListener initialize()
WifiP2pManager.ConnectionInfoListener requestConnectInfo()
WifiP2pManager.GroupInfoListener requestGroupInfo()
WifiP2pManager.PeerListListener requestPeers()
WiFi P2P API定义了在特定的wifi p2p 事件发生的时候广播的intent,比如新发现了一个配对设备,或者是一个设备wifi状态发生变化。你可以在你的app中通过注册对应的BroadcastReceiver来接受对应的intent。


Table 3. Wi-Fi P2P Intents

Intent Description
WIFI_P2P_CONNECTION_CHANGED_ACTION Broadcast when the state of the device's Wi-Fi connection changes.
当wifi连接变化的时候的广播。
WIFI_P2P_PEERS_CHANGED_ACTION Broadcast when you call discoverPeers(). You usually want to callrequestPeers() to get an updated list of peers if you handle this intent in your application.
当调用discoverPeers的时候发送的广播,你应该会在接受到广播时候调用requestPeers来更新配对的列表。
WIFI_P2P_STATE_CHANGED_ACTION Broadcast when Wi-Fi P2P is enabled or disabled on the device.
当本设备的wifi P2P 启用或者禁用的时候的广播。 
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION Broadcast when a device's details have changed, such as the device's name.
当一个设备的细节发生变化的时候的广播,比如说设备的名变化。
创建Wifi-P2P intent对应的广播接受器


广播接收器可以接受android系统当中的广播,这样你的app可以对他感兴趣的事情做出相应。

创建接受Wifi P2p的intent的广播接受器分为以下几个步骤:


1.创建一个BroadcastReceiver的子类。你需要在构造函数里面传入几个,一个是WifiP2pManager, 一个是WifiP2pManager.Channel,还有一个这个broadcast将会被注册到的activity。这样的话广播接收者就可以更新activity,并且可以根据需要访问wifi的硬件以及通信频道。

2.在receive方法中判断检查你关注的intent。基于接受到的不同的intent来发出不同的动作。例如,如果你接到了一个WIFI_P2P_PEERS_CHANGE_ACTION的intent ,你就可以调用requestPeers()方法,来获取现在发现的对等设备的列表。

下面的 代码想你展示了怎样创建一个典型的广播接受者。它接受一个WifiP2pManager对象以及一个activity作为参数,并且使用这两个类来发起接收广播以后的动作。

/**
 * A BroadcastReceiver that notifies of important Wi-Fi p2p events.
 */
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {

    private WifiP2pManager mManager;
    private Channel mChannel;
    private MyWiFiActivity mActivity;

    public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
            MyWifiActivity activity) {
        super();
        this.mManager = manager;
        this.mChannel = 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)) {
            // Check to see if Wi-Fi is enabled and notify appropriate activity 查看wifi是否可用,并通知合适的activity。
        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
            // Call WifiP2pManager.requestPeers() to get a list of current peers//调用WifiP2pManager.requestPeers(),来获取当前的对等列表
        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
            // Respond to new connection or disconnections//响应临街和断开连接
        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
            // Respond to this device's wifi state changing//响应wifi状态的变化。
        }
    }
}

创建一个wifi P2p应用

创建一个wifi p2p应用包含创建和注册一个你的app的广播接受者,发现对等设备,连接对等,向他们传输数据。下面具体描述步骤。

初始化步骤

在你使用WifiP2P API之前,你需要确保你的应用可以访问硬件,并且你的设备支持wifip2p协议。接下来实例化一个WifiP2pManager的对象,然后创建并注册广播接听者,然后开始使用wifi p2papi。

1.获取wifi硬件的访问权限,并且在manifest中声明正确的最小的sdk版本。

<uses-sdk android:minSdkVersion="14" />
<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.检查Wifi p2p是否装备并可用。恰当的检测的地方就是在广播接受者里面,当它接受到WIFI_P2P_STATE_CHANGED_ACTION intent的时候。想activity通知P2P状态的改变,并且恰当地做出反应。

@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方法中获取一个WifiP2pManager的实例,并使用Wifi P2p框架通过调用 initiallize来注册你的applicaiton。接着你要使用这个WifiP2pManager的对象,以及WifiP2pManager.Channel对象,以及你的Activity来创建一个广播接受者实例。这样的话广播接受者就可以接受你的activity感兴趣的广播了,并且做出对应的更新。同样这也可以让你在必要的时候维护设备的wifi状态。

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并添加你的广播接受者要检查的广播。

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()方法中注册这个广播接受者,并且在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);
}


当你获得了一个WifiP2pManager对象并建立一个广播接受者的时候,你的app就可以调用wifip2p的方法并接受相关的WifiP2p广播了。

现在你已经构造了一个拥有wifi p2p功能的app,并调用WifiP2pManager中的方法。下一节中将讲述发现对的设备和连接设备等的一些典型操作。


发现对等设备

可以调用diacoverPeers方法来探测范围内可以配对的设备。这个调用的方法是异步的,并且如果你创建了一个WifiP2pManager.ActionListener的对象,那么连接的成功与失败的结果将通过onSuccess()和onFailure方法通知你。onSuccess方法仅仅是通知你连接成功了,如果连接中有可能的设备的其他的信息,这个方法并不能提供这些信息。


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

    @Override
    public void onFailure(int reasonCode) {
        ...
    }
});
如果发现过程成功探测到了设备,系统就会发出广播,WIFI_P2P_PEERS_CHANGED_ACTION intent,你可以监听他们来获取对等设备的列表。当你的app接受到了WIFI_P2P_PEERS_CHANGED_ACTION intent的时候,你就可以通过requestPeers方法来获得对等设备的列表。下面就是这个设置过程了例子:


PeerListListener myPeerListListener;
...
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {

    // request available peers from the wifi p2p manager. This is an 从P2pManager里面获取可用的对等设备。这是一个异步的或者,调用的Activity将会通过PeerListListener.onPeersAvailabl方法被通知。
    // asynchronous call and the calling activity is notified with a
    // callback on PeerListListener.onPeersAvailable()
    if (mManager != null) {
        mManager.requestPeers(mChannel, myPeerListListener);
    }
}

requestPeers方法同样食欲不的,他通过调用WifiP2pManager中的PeerListListener接口中的onPeersAvailable方法来通知你的activity对等设备的列表。onPeersAvaivablable方法可以向你提供一个WifiP2pDeviceList对象,你可以通过遍历它来找到你要连接对等设备。


连接到对等设备

当你已经获得了可能连接设备的列表,并搞清楚要连接的设备的时候,你就可以通过调用connect方法来连接设备了。这个方法需要一个WifiP2pConfig对象,其中包含了要连接到的设备的信息。你可以通过调用WifiP2pManager.ActionListener中的方法来通知成功还是失败。下面代码展示了怎样与想要的设备创建一个连接。

//obtain a peer from the 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
    }
});


传输数据

一旦连接建立,你就可以通过socket在设备之间传输数据了。下面是传输数据的基本步骤:

1.创建一个ServerSocket。这个socket将会在一个特定的端口等待客户端的的消息,并且一直阻塞直到通信发生,所以要在一个工作线程中工作。
2.创建一个客户端socket。这个socket通过ip地址和端口号和serversocket进行通信。

3.从客户端向服务器发送数据。当客户端成功和服务器端连接的时候,你可以使用字节流从客户端向服务器端发消息。

4.server socket等待一个客户端的连接(使用accept方法)。这个调用会阻塞直到客户端连接,所以在另一个线程中调用这个方法。当连接发生的时候,server 设备就可以接受从客户端设备发来的数据。可以对这些数据进行一些操作,比如说存入到文件或者想用户呈现。


下面是一个例子,修改自Wifi P2P Demo,展示了怎样创建一个CS连接,并且从客户端向服务器传输一个JPEG图片。对于一个完成的例子,编译并运行这个例子。

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 {

            /**
             * Create a server socket and wait for client connections. This  //创建一个服务器server并等待连接,这个调用将会阻塞,直到接受到一个客户端连接。
             * call blocks until a connection is accepted from a client
             */
            ServerSocket serverSocket = new ServerSocket(8888);
            Socket client = serverSocket.accept();

            /**
             * If this code is reached, a client has connected and transferred data//如果代码执行到了这里证明客户端已经连接并传递数据。这时从输入流中获取数据并存储为一个JPEG文件。
             * Save the input stream from the client as a JPEG file
             */
            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;
        }
    }

    /**
     * Start activity that can handle the JPEG image  开启一个activity,来处理这个JPEG文件。
     */
    @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连接服务器并传输数据。这个例子传输了一个client的文件系统中的JPEG文件。

Context context = this.getApplicationContext();
String host;
int port;
int len;
Socket socket = new Socket();
byte buf[]  = new byte[1024];
...
try {
    /**
     * Create a client socket with the host,//创建一个客户端socket,设定ip主机,端口和超时信息。
     * port, and timeout information.
     */
    socket.bind(null);
    socket.connect((new InetSocketAddress(host, port)), 500);

    /**
     * Create a byte stream from a JPEG file and pipe it to the output stream//从JPEG文件创建一个字节流并输入到socket输出流中。这个数据将会被服务端设备获取。
     * of the socket. This data will be retrieved by the server device.
     */
    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
}

/**
 * Clean up any open sockets when done//当传输结束或者发生异常的时候都要关闭socket。
 * transferring or if an exception occurred.
 */
finally {
    if (socket != null) {
        if (socket.isConnected()) {
            try {
                socket.close();
            } catch (IOException e) {
                //catch logic
            }
        }
    }
}


















 类似资料: