Android官方开发文档Training系列课程中文版:连接无线设备之通过WIFI创建P2P连接

简介: 原文地址:http://android.xsoftlab.net/training/connect-devices-wirelessly/wifi-direct.html#permissionsWi-Fi peer-to-peer (P2P) APIs可以使程序与附近的设备进行直接通讯,Android的Wi-Fi P2P框架由Wi-Fi Direct™提供技术支持。

原文地址:http://android.xsoftlab.net/training/connect-devices-wirelessly/wifi-direct.html#permissions

Wi-Fi peer-to-peer (P2P) APIs可以使程序与附近的设备进行直接通讯,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 Socket通讯技术,所以需要使用INTERNET权限:

<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技术,需要监听广播意图,广播意图会通知程序某些事件的发生。所以在程序中需要添加IntentFilter,并设置其监听以下行为:

WIFI\_P2P\_STATE\_CHANGED\_ACTION

监听Wi-Fi P2P是否可用

WIFI\_P2P\_PEERS\_CHANGED\_ACTION

监听WI-FI P2P列表的变化

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暂停的时候注销这个广播接收器。放置这些代码的最佳位置就是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);
    }

初始化端点搜索

如果开始要使用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.
        }
});

要记住,这里只是初始化了端点搜索。discoverPeers()方法启动搜索进程后会立即返回。如果端点搜索进程成功初始化,那么系统会自动调用初始化时设置的回调方法。另外,端点搜索功能会一直保持在活动状态,直到连接初始化完成或者P2P组建立连接。

获取端点列表

接下来需要获得并处理端点列表。首先需要实现WifiP2pManager.PeerListListener接口,它提供了WI-FI P2P所搜索到的端点信息。下面的代码演示了这个过程:

    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\_STATE\_CHANGED\_ACTION行为时调用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\_STATE\_CHANGED\_ACTION的行为将会触发端点列表的更新。

连接到端点

为了可以连接到端点,需要创建一个新的WifiP2pConfig对象,然后将WifiP2pDevice中的数据拷贝进这个对象中。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()会在连接状态发生变化的时候回调。在多台设备连接一台设备的情况下(比如多人互动的游戏或者聊天类的APP),其中一台设备会被指定为”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的部分,当这个意图接收到时,调用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);
            }
            ...
目录
相关文章
|
5月前
|
Android开发 iOS开发 UED
探索未来:Android与iOS在智能穿戴设备上的较量
随着科技的飞速进步,智能穿戴设备已经成为我们日常生活中不可或缺的一部分。本文将深入探讨两大操作系统——Android和iOS——在智能穿戴领域的竞争与发展,分析它们各自的优势与挑战,并预测未来的发展趋势。通过比较两者在设计哲学、生态系统、用户体验及创新技术的应用等方面的差异,揭示这场较量对消费者选择和市场格局的影响。 【7月更文挑战第31天】
57 0
|
4月前
|
Shell Linux 开发工具
"开发者的救星:揭秘如何用adb神器征服Android设备,开启高效调试之旅!"
【8月更文挑战第20天】Android Debug Bridge (adb) 是 Android 开发者必备工具,用于实现计算机与 Android 设备间通讯,执行调试及命令操作。adb 提供了丰富的命令行接口,覆盖从基础设备管理到复杂系统操作的需求。本文详细介绍 adb 的安装配置流程,并列举实用命令示例,包括设备连接管理、应用安装调试、文件系统访问等基础功能,以及端口转发、日志查看等高级技巧。此外,还提供了常见问题的故障排除指南,帮助开发者快速解决问题。掌握 adb 将极大提升 Android 开发效率,助力项目顺利推进。
114 0
|
4月前
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
本文介绍了如何在基于Amlogic T972的Android 9.0系统上使用Platform平台驱动框架和设备树(DTS),实现设备与驱动的分离,并通过静态枚举在设备树中描述设备,自动触发驱动程序的加载和设备创建。
80 0
基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
|
4月前
|
Android开发 C语言
基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
这篇文章是关于如何在基于Amlogic T972的Android 9.0系统上,通过自动分配设备号和自动创建设备节点文件的方式,开发字符设备驱动程序的教程。
75 0
基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
|
4月前
|
自然语言处理 Shell Linux
基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
本文是关于在Amlogic安卓9.0平台上创建字符设备驱动的教程,详细介绍了驱动程序的编写、编译、部署和测试过程,并提供了完整的源码和应用层调用示例。
112 0
基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
|
4月前
|
传感器 Android开发 芯片
不写一行代码(三):实现安卓基于i2c bus的Slaver设备驱动
本文是系列文章的第三篇,展示了如何在Android系统中利用现有的i2c bus驱动,通过编写设备树节点和应用层的控制代码,实现对基于i2c bus的Slaver设备(如六轴陀螺仪模块QMI8658C)的控制,而无需编写设备驱动代码。
59 0
不写一行代码(三):实现安卓基于i2c bus的Slaver设备驱动
|
4月前
|
Android开发
不写一行代码(二):实现安卓基于PWM的LED设备驱动
本文介绍了在Android系统中不编写任何代码,通过设备树配置和内核支持的通用PWM LED驱动来实现基于PWM的LED设备驱动,并通过测试命令调整LED亮度级别。
63 0
不写一行代码(二):实现安卓基于PWM的LED设备驱动
|
4月前
|
Linux Android开发 C语言
不写一行代码(一):实现安卓基于GPIO的LED设备驱动
本文通过实践操作,展示了在Android系统中不编写任何代码,利用设备树(DTS)配置和内核支持的通用GPIO LED驱动来控制LED设备,并进一步通过C语言编写NDK测试APP来实现LED的闪烁效果。
198 0
不写一行代码(一):实现安卓基于GPIO的LED设备驱动
|
4月前
|
存储 Ubuntu API
如何使用Python创建服务器向Android设备发送GCM推送通知
如何使用Python创建服务器向Android设备发送GCM推送通知
34 0
|
5月前
|
Android开发 数据安全/隐私保护 iOS开发
探索未来:安卓与iOS在智能穿戴设备领域的较量
随着科技的飞速发展,智能穿戴设备已逐渐成为我们日常生活的一部分。从健康监测到通讯交流,它们正以惊人的速度改变着我们的生活方式。本文将深入探讨安卓和iOS这两大操作系统在智能穿戴领域的现状、竞争以及未来发展趋势,揭示它们如何通过创新技术满足用户需求,并预测未来可能的发展方向。
48 0