zoukankan      html  css  js  c++  java
  • 【Android Developers Training】 76. 用Wi-Fi创建P2P连接

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。

    原文链接:http://developer.android.com/training/connect-devices-wirelessly/wifi-direct.html


    Wi-Fi的P2P API允许设备连接到附近的设备,而不需要连接到网络或热点(Android的Wi-Fi P2P框架使用Wi-Fi Direct™认证程序来编译)Wi-Fi P2P允许你的应用快速发现并连接到附近的设备,这一功能比起蓝牙来说更加强大。

    这节课将向你展示如何使用Wi-Fi P2P来发现并连接附近的设备。


    一). 设置应用权限声明

    为了使用Wi-Fi P2P,需要添加CHANGE_WIFI_STATEACCESS_WIFI_STATEINTERNET权限声明到你的清单文件中。Wi-Fi P2P不需要一个网络连接,但它使用了标准的Java套接字,而这需要INTERNET权限。所以你需要下列权限来使用Wi-Fi P2P。

    <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,你需要监听在某一事件发生时,用来告知你的应用的广播Intents。在你的应用中,实例化一个IntentFilter并设置它为监听下列事件:

    WIFI_P2P_STATE_CHANGED_ACTION

    指出Wi-Fi P2P已经启用

    WIFI_P2P_PEERS_CHANGED_ACTION

    指出可以获得的peer列表发生了变化

    WIFI_P2P_CONNECTION_CHANGED_ACTION

    指出Wi-Fi P2P连接的状态发生了变化

    WIFI_P2P_THIS_DEVICE_CHANGED_ACTION

    指出设备的配置细节发生了改变

    private final IntentFilter intentFilter = new IntentFilter();
    ...
    @Override
    public 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框架。

    @Override
    
    Channel 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处于活动状态时,注册intent过滤器和广播接收器,并在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);
        } 

    三). 初始化Peer搜索

    要使用Wi-Fi P2P来搜索附近的设备,调用discoverPeers()方法。这一方法接收如下参数:

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

    记住这仅仅是初始化了peer搜索。discoverPeers()方法启动搜索进程,然后迅速返回。系统会通知你搜索进程是否被监听器初始化成功。同时搜索会保持激活状态知道一个连接被初始化或者一个P2P组被构建完成。


    四). 获取Peers列表

    现在写下获取和处理Peers列表的代码。首先实现WifiP2pManager.PeerListListener接口,它提供了检测到的Wi-Fi P2P的peer信息。请看下面的代码:

        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_PEERS_CHANGED_ACTION的intent被接收时,来调用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_PEERS_CHANGED_ACTION的intent将会激活一个更新Peer列表的请求。


    五). 与一个Peer发起连接

    为了和一个Peer发起连接,创建一个新的WifiP2pConfig对象,然后从代表你想要连接的设备的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()回调函数将会在连接状态变化后向你发出通知。在一些情况下,许多设备会向一个设备发起连接(比如一个多人连接的游戏,或者一个聊天的应用),其中一个设备会被任命为一个“组所有者(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的intent的部分。当这个intent接收到了以后,调用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);
                }
                ...
  • 相关阅读:
    一、JQuery选择器
    二、HelloMaven-第一个Maven项目
    一、maven的简介和环境搭建
    Junit源码
    五、spring和Hibernate整合
    JS 冒泡排序从学到优化
    JS小案例(基础好烦恼少)----持续更新
    JS+PHP实现用户输入数字后取得最大的值并显示为第几个
    将博客搬至CSDN
    HTML表单相关
  • 原文地址:https://www.cnblogs.com/jdneo/p/3583831.html
Copyright © 2011-2022 走看看