• Android---用Wi-Fi来建立对等连接


    本文译自:http://developer.android.com/training/connect-devices-wirelessly/wifi-direct.html

    WiFi对等API(P2P)不需要连接到网络或热点(Android的WiFi P2P框架符合WiFi编程指导规范),就允许应用程序连接到附近的设备。WiFiP2P允许应用程序快速的查找附近的设备,并与其交互。在连接范围上超过了蓝牙的能力。

    本文介绍如何使用WiFi P2P来查找和连接附近的设备。

    建立应用程序权限

    为了使用WiFi P2P,要在应用程序的清单文件中添加CHANGE_WIFI_STATEACCESS_WIFI_STATEINTERNET权限。WiFi P2P不要求互联网连接,但是它使用标准的Java套接字,它要求INTERNET权限。因此使用WiFi P2P需要下例权限。

    <manifestxmlns: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"/>
        ...

    建立广播接收器和对等管理器

    要使用WiFi P2P,就要监听广播意图,在确定事件发生时,告诉你的应用程序。在你的应用程序中,要实例化一个IntentFilter对象,并设置它来监听以下动作:

    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

    指示设备的配置明细已经发生改变。

    privatefinalIntentFilterintentFilter =newIntentFilter();
    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        //  Indicates achange in the Wi-Fi P2P status.
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);

        // Indicates a change inthe list of available peers.
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);

        // Indicates the state ofWi-Fi P2P connectivity has changed.
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);

        // Indicates this device'sdetails have changed.
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

        ...
    }

    onCreate()方法中,获取一个WifiP2pManager对象的实例,并调用它的initialize()方法。这个方法会返回一个WifiP2pManager.Channel对象,它会用于后续对WiFi P2P框架的连接。

    @Override

    Channel
    mChannel;

    public void onCreate(Bundle savedInstanceState) {
        ....
        mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        mChannel = mManager.initialize(this, getMainLooper(), null);
    }

     

    现在创建一个新的BroadcastReceiver类,用于监听系统的WiFi 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 somethingabout
                // that.

            } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {

                // Connection state changed!  We should probably do somethingabout
                // 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 BroadcastReceiverwith 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);
        }

    启动对等点发现功能

    要使用Wi-Fi P2P来搜索附近的设备,就要调用discoverPeers()方法,这个方法需要以下参数:

    WifiP2pManager.Channel:这个参数是在初始化对等管理器时获取,用于把应用程序连接到Wi-Fi的P2P框架中;

    WifiP2pManager.ActionListener接口实现:系统会在处理成功或失败时调用该接口中对应的方法。

    mManager.discoverPeers(mChannel,newWifiP2pManager.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.
            }
    });

    记住,这只是启动对等点发现功能。DiscoverPeers()方法启动发现处理,然后立即返回。系统会通过调用你传入的第二参数中的对应的接口方法,通知你对等点发现处理是否启动成功。此外,发现处理会一直保持到连接被启动或P2P组被组建。

    获取对等点的列表

    现在要编写获取和处理对等点列表的代码。首先实现WifiP2pManager.PeerListener接口,这个接口会提供有关已经发现的Wi-Fi的P2P对等点的信息。下列代码演示这个处理:

    privateList peers =newArrayList();
       
    ...

        private PeerListListenerpeerListListener = new PeerListListener() {
            @Override
            public void onPeersAvailable(WifiP2pDeviceListpeerList) {

                // 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 ofavailable
                // 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()方法,并把上面实现的监听器传递给requestPeers()方法。你可以把这个监听器作为广播接收器的构造器的参数来传递。

    publicvoid onReceive(Context context,Intent intent){
       
    ...
        else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {

            // Requestavailable peers from the wifi p2p manager. This is an
            //asynchronous call and the calling activity is notified with a
            // callbackon PeerListListener.onPeersAvailable()
            if (mManager != null) {
                mManager.requestPeers(mChannel,peerListListener);
            }
            Log.d(WiFiDirectActivity.TAG, "P2P peerschanged");
        }...
    }

    这样,带有WIFI-P2P_PEERS_CHANGED_ACTIONIntent操作就会触发更新对等点列表的请求。

    连接到对等点

    为了连接到对等点,要创建一个新的WifiP2pConfig对象,并从代表你要连接的设备的WifiP2pDevice对象中复制数据到这个WifiP2pConfig对象中。然后调用connect()方法。

    @Override
       
    public void connect() {
            // Pickingthe 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()回调方法在连接状态变化时通知你。当有多个设备连接一个设备时,其中一个设备将会被指定为“组管理者”。

    @Override
       
    public voidonConnectionInfoAvailable(final WifiP2pInfo info) {

            //InetAddress from WifiP2pInfo struct.
            InetAddress groupOwnerAddress =info.groupOwnerAddress.getHostAddress());

            // After thegroup 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_ACTIONIntent操作的监听。当收到这个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);
                }
                ...

  • 相关阅读:
    从0到1构建适配不同端(微信小程序、H5、React-Native 等)的taro + dva应用
    一个基于Ionic3.x cordova的移动APP demo
    基于 MUI 构建一个具有 90 +页面的APP应用
    风清杨之Oracle的安装与说明
    浅析C#中的“==”和Equals
    window.open()的使用
    动态生成级联下拉框和多选框
    生成二维码的两种方式
    登录添加验证码校验
    oracle11g的安装以及配置
  • 原文地址:https://www.cnblogs.com/pangblog/p/3364672.html
Copyright © 2020-2023  润新知