本文译自: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_ACTION的Intent操作就会触发更新对等点列表的请求。

连接到对等点

为了连接到对等点,要创建一个新的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_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---用Wi-Fi来建立对等连接的更多相关文章

  1. java.io.IOException: 您的主机中的软件中止了一个已建立的连接解决办法

    问题现象和http://hi.baidu.com/cara_cloud/item/193a3ee327546d395a2d64be描述的一样,就是在eclipse的console栏中一直显示java. ...

  2. 【转】android蓝牙开发 蓝牙设备的查找和连接

    1.  首先,要操作蓝牙,先要在AndroidManifest.xml里加入权限 // 管理蓝牙设备的权限 <uses-permissionandroid:name="android. ...

  3. Android应用程序与SurfaceFlinger服务的连接过程分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/7857163 前文在描述Android应用程序和 ...

  4. Android实现推送方式解决方案 - 长连接+心跳机制(MQTT协议)

    本文介绍在Android中实现推送方式的基础知识及相关解决方案.推送功能在手机开发中应用的场景是越来起来了,不说别的,就我们手机上的新闻客户端就时不j时的推送过来新的消息,很方便的阅读最新的新闻信息. ...

  5. 通过UDP建立TCP连接

    解释 通过UDP广播查询服务器的IP地址,然后再建立TCP点对点连接. 应用场景 在服务器IP未知时,并且已知服务器与客户端明确在一个局域网或者允许组播的子网下. 通过UDP发现服务器地址然后再进行T ...

  6. 使用wireshark抓包分析浏览器无法建立WebSocket连接的问题(server为Alchemy WebSockets组件)

    工作时使用了Websocket技术,在使用的过程中发现,浏览器(Chrome)升级后可能会导致Websocket不可用,更换浏览器后可以正常使用. 近日偶尔一次在本地调试,发现使用相同版本的Chrom ...

  7. telnet建立http连接获取网页HTML内容

    利用telnet可以与服务器建立http连接,获取网页,实现浏览器的功能.它对于需要对http header进行观察和测试到时候非常方便.因为浏览器看不到http header. 步骤如下: 1. 运 ...

  8. HTTP协议用的TCP但是只建立单向连接

    作者:IronTech链接:https://www.zhihu.com/question/20085992/answer/71742030来源:知乎著作权归作者所有,转载请联系作者获得授权. 下面的解 ...

  9. System.getProperty()引起的悲剧--您的主机中的软件中止了一个已建立的连接

    我已无法形容此刻我的心情.. 本来是已经写好的netty5的demo程序,server和client之间创建tcp长连接的..然后随便传点数据的简单demo..然后今天试了一下tcp粘包的例子,用到了 ...

随机推荐

  1. PHP strip_tags() 函数

    定义和用法 strip_tags() 函数剥去 HTML.XML 以及 PHP 的标签. 语法 strip_tags(string,allow) 参数 描述 string 必需.规定要检查的字符串. ...

  2. 【NOIP 2012 国王游戏】 贪心+高精度

    题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍 ...

  3. NSMutableArray,NSMutableDictionary的内存管问题

    今天做项目遇到一个问题,在一个类中定义了一个可变数组,使用的是copy的内存管理策略 当往数组中添加包装好的基本数据的时候,程序直接崩溃了.解决方法:把copy换成strong就不会崩溃了; 后来做了 ...

  4. 使用phpexecel类库导出数据

    公司要求做一个功能:将数据库里的数据导出,并生成excel文件. 于是百度了下,集大牛之所长,加上自己之所长,做出了整理,并分享. 目标:使用phpexcel类库生成xml文件,并下载. 步骤一:下载 ...

  5. 万能脚本助Web执行底层Linux命令

    需求分析: 这里先要说明的是,这一篇不是QT系列的文章,而是关于Web的,之所以要写这篇,是因为以前做Web相关开发的时候,经常涉及到与linux底层命令打交道,比如说创建一个目录,删除一个目录,或者 ...

  6. int指令理解

    以下是王爽老师的<汇编语言>中第十五章中的一段程序代码,其功能是增加9号中断的功能,当按下Esc键时屏幕中显示的字母改变颜色 assume cs:codesg,ss:stack,ds:da ...

  7. Android handler 报错处理Can't create handler inside thread that has not called Looper.prepare()

    问题: 写了一个sdk给其他人用,提供一个回调函数,函数使用了handler处理消息 // handler监听网络请求,完成后操作回调函数 final Handler trigerGfHandler ...

  8. WIP_DISCRETE_JOBS.STATUS_TYPE

    WIP_DISCRETE_JOBS.STATUS_TYPE Value Meaning 7 Cancelled 8 Pending Bill Load 9 Failed Bill Load 10 Pe ...

  9. Hibernate级联操作

    cascade属性的可能值有 all: 所有情况下均进行关联操作,即save-update和delete. none: 所有情况下均不进行关联操作.这是默认值. save-update: 在执行sav ...

  10. 六月计划#2B(6.10-6.16)

    4/7 STL set 数学 快速傅立叶(FFT) 高斯消元 动态规划 斜率优化