Android Wifi Direct 安卓手机间wifi直连

本文介绍了如何在Android中利用Wi-Fi Direct实现设备间的直接连接。内容涵盖设置权限、创建广播接收器和对等网络管理器、初始化对等点搜索、获取对等点列表以及建立连接的详细步骤。Wi-Fi Direct提供了更远距离的通信,相比于蓝牙具有优势。
部署运行你感兴趣的模型镜像

         Wi-Fi Direct™的API允许应用程序不通过网络或热点,直接与周围的设备进行连接。应用程序可以迅速地查找附近的设备,交换信息。并且与蓝牙相比,Wi-Fi Direct的通讯范围更大。

        通过Wi-Fi Direct查找附近的设备,并与之连接一般包括如下几个步骤:

  • 设置应用程序权限
  • 创建一个广播接收器和对等网络管理器 
  • 初始化对等点的搜索
  • 获取对等点列表
  • 连接一个对等点


一、设置应用程序权限


        使用Wi-Fi Direct,需要向你的清单文件添加 CHANGE_WIFI_STATE,ACCESS_WIFI_STATEINTERNET 权限。Wi-Fi Direct不需要因特网连接,但需要使用标准Java套接字,而套接字需要INTERNET 权限,因此,你需要有以下的权限才可以使用Wi-Fi Direct。

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

注:

android.permission.ACCESS_WIFI_STATE       允许程序访问Wi-Fi网络状态信息(Allows applications to access information about Wi-Fi networks)
android.permission.CHANGE_WIFI_STATE      允许程序改变Wi-Fi连接状态(Allows applications to change Wi-Fi connectivity state)
android.permission.INTERNET                           当需要访问网络的时候,需要在AndroidManifest.xml里面添加访问网络的权限


二、创建一个广播接收器和对等网络管理器

        使用Wi-Fi Direct,你需要监听广播意图(Intents)来获知某个特定事件的发生。在你的应用程序中,初始化一个 IntentFilter,并让它监听以下动作:

WIFI_P2P_STATE_CHANGED_ACTION

  • * 表明Wi-Fi对等网络(P2P)是否已经启用

WIFI_P2P_PEERS_CHANGED_ACTION

  • * 表明可用的对等点的列表发生了改变

WIFI_P2P_CONNECTION_CHANGED_ACTION

  • * 表示Wi-Fi对等网络的连接状态发生了改变

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

    //表示Wi-Fi对等网络状态发生了改变
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);

    //表示可用的对等点的列表发生了改变
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);

    //表示Wi-Fi对等网络的连接状态发生了改变
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);

    //设备配置信息发生了改变
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

    ...
}

        在 onCreate() 方法的最后,获得了 WifiP2pManager 的一个实例,并调用了他的 initialize() 方法。这个方法返回一个 WifiP2pManager.Channel 对象。稍后会用它把你的应用程序连接到Wi-Fi Direct框架中。

@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)) {

            //确定Wi-Fi Direct模式是否已经启用,并提醒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)) {

    //对等点列表已经改变!我们可能需要对此做出处理。

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

    //连接状态已经改变!我们可能需要对此做出处理。

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

        }
    }

       最后,添加代码,在主活动激活时,注册意图过滤器(Intent Filter)和广播接收器;在主活动暂停时把它们注销。最好在 onResume()onPause() 方法中完成该操作。

/* 注册一个与意图(Intent)值匹配的广播接收器* /
    @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 Direct搜索附近的设备,需要调用 discoverPeers()方法。其参数如下:

          WifiP2pManager.Channel 是在你初始化对等网络的mManager时收到的。

          WifiP2pManager.ActionListener 的一个实例,实现了系统在查找成功或失败时会调用的方法。


mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {

        @Override
        public void onSuccess() {
        //查找初始化成功时的处理写在这里。

        //实际上并没有发现任何服务,所以该方法可以置空。
        //对等点搜索的代码在onReceive方法中,详见下文。
        }

        @Override
        public void onFailure(int reasonCode) {
        //查找初始化失败时的处理写在这里。
        //警告用户出错了。
        }
});



        此处只初始化了对等点的搜索。 discoverPeers() 方法启动了搜索线程,并立刻返回。系统通过调用给定的动作监听器的方法来进行初始化,并会在成功初始化对等点进程时通知你。同时,搜索也会持续进行,直到一个连接被初始化,或者一个P2P组形成。


四、获取对等点列表

        获取对等点的列表并进行处理,首先实现 WifiP2pManager.PeerListListener 接口,它提供了Wi-Fi Direct检测到的对等点信息。参见下面的代码片段。

       

private List peers = new ArrayList();
    ...

    private PeerListListener peerListListener = new PeerListListener() {
        @Override
        public void onPeersAvailable(WifiP2pDeviceList peerList) {

            //旧的不去,新的不来
            peers.clear();
            peers.addAll(peerList.getDeviceList());

            //如果AdapterView可以处理该数据,则把变更通知它。比如,如果你有可用对等点的ListView,那就发起一次更新。
            ((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)) {

        //从Wi-Fi P2P管理器中请求可用的对等点。
        //这是个异步的调用,
        //并且,调用行为是通过PeerListListener.onPeersAvailable()上的一个回调函数来通知的。
        if (mManager != null) {
            mManager.requestPeers(mChannel, peerListener);
        }
        Log.d(WiFiDirectActivity.TAG, "P2P peers changed");
    }...
}

至此,带有 WIFI_P2P_PEERS_CHANGED_ACTION 动作的意图(Intent)将会发起一个更新对等点列表的请求。

五、连接一个对等点

        为了连接一个对等点,需要先创建一个新的 WifiP2pConfig 对象,然后从代表你想连接的设备的 WifiP2pDevice 中拷贝数据进去。再调用 connect() 方法。

@Override
    public void connect() {

        //使用在网络上找到的第一个设备。
        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将会通知我们。现在可以先忽略。
            }

            @Override
            public void onFailure(int reason) {
                Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.",
                        Toast.LENGTH_SHORT).show();
            }
        });
    }

        在这个代码片段中实现的 WifiP2pManager.ActionListener 只会在初始化成功或失败时通知你。要监听连接状态的变更,需要实现 WifiP2pManager.ConnectionInfoListener 接口。其回调函数 onConnectionInfoAvailable()将会在连接状态改变时通知你。对于多个设备连接一个设备的情况(比如,多于3个玩家的游戏,或者聊天软件),其中一个设备将会被指定为“群主”。

       

@Override
    public void onConnectionInfoAvailable(final WifiP2pInfo info) {

        // InetAddress在WifiP2pInfo结构体中。
        InetAddress groupOwnerAddress = info.groupOwnerAddress.getHostAddress());

        //组群协商后,就可以确定群主。
        if (info.groupFormed && info.isGroupOwner) {
        //针对群主做某些任务。
        //一种常用的做法是,创建一个服务器线程并接收连接请求。
        } else if (info.groupFormed) {
        //其他设备都作为客户端。在这种情况下,你会希望创建一个客户端线程来连接群主。
        }
    }

        现在回到广播接收器的 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()) {

            //我们连上了其他的设备,请求连接信息,以找到群主的IP。
                mManager.requestConnectionInfo(mChannel, connectionListener);
            }
            ...

    



您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值