【Android Developers Training】 76. 用Wi-Fi

系统 1852 0

注:本文翻译自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_STATE ACCESS_WIFI_STATE INTERNET 权限声明到你的清单文件中。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);

            }

            ...
      
    

【Android Developers Training】 76. 用Wi-Fi创建P2P连接


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论