Android WiFiDirect 学习(二)——Service Discovery

Service Discovery 简介

在Android WifiDirect学习(一 )中,简单介绍了如何使用WifiDirect进行搜索——连接——传输。

这样会有一个问题,那就是你会搜索到到附近所有处于WifiDirect搜索状态的网络设备,而这些设备中不一定都是你想进行连接的。

Android WifiDirect Api提供了一个仅搜索特定网络设备的搜索方式,叫做Service Discovery,它是Wi-Fi Direct API在Android 4.1中被增强以支持在WifiP2pManager中的预先关联服务发现。这允许在连接之前使用Wi-Fi Direct通过服务(Service)发现和筛选周围的设备。

常见Service:

Android已经提供了两种Service,一种是 Bonjour Service,一种是Upnp Service,开发者也可以自己设计一套Service,一般情况下,这两种Service已经足够用了。

Service基本使用方法

为了广播你的应用作为一个Wi-Fi上的服务,以便于其他设备能够发现并连接你的应用,需要调用addLocalService()方法并传输一个WifiP2pServiceInfo对象。这个对象描述了你的应用服务。

为了通过Wi-Fi开始发现附近的设备,首先你应当决定使用Bonjour Service还是Upnp Service实现通信。如果使用Bonjour,首先要用setDnsSdResponseListeners()设置好一些回调监听器。这个方法需要WifiP2pManager.DnsSdServiceResponseListenerDnsSdTxtRecordListener两个作参数。如果使用Upnp,则要调用setUpnpServiceResponseListener()。这个方法需要UpnpServiceResponseListener作为参数。

在你开始发现本地设备上的服务之前,你也需要调用addServiceRequest()方法。当你传递给这个方法的接口ActionListener收到一个成功的回调,接着你可以通过调用discoverServices()开始探索在本地设备上的服务。

当本地服务被发现,你会收到一个回调,来自WifiP2pManager.DnsSdServiceResponseListener或者WifiP2pManager.UpnpServiceResponseListener,这个取决于你注册使用的是Bonjour还是Upnp。收到的回调都会包含一个WifiP2pDevice对象,代表了对应的设备。

Service使用案例(以Bonjour Service为例)

设置Manifest

为了使用Wi-Fi P2P,要在你的androidmanifest中添加CHANGE_WIFI_STATEACCESS_WIFI_STATE、和INTERNET权限。即使Wi-FiP2P不要求互联网连接,但它要使用标准的Java socket,并且Android在使用这些套接字时要求申请这些权限,因此要在清单中申请INTERNET权限。

 1 <manifestxmlns:android="http://schemas.android.com/apk/res/android"
 2     package="com.example.android.nsdchat"
 3     ...
 4     <uses-permission
 5         android:required="true"
 6         android:name="android.permission.ACCESS_WIFI_STATE"/>
 7     <uses-permission
 8         android:required="true"
 9         android:name="android.permission.CHANGE_WIFI_STATE"/>
10     <uses-permission
11         android:required="true"
12         android:name="android.permission.INTERNET"/>
13     ...

添加Local Service

如果你要提供一个Local Service,那么就需要把这个服务注册为可发现的。本地服务被注册后,框架就会自动的响应来自对等点的服务发现请求。

以下是创建本地服务的步骤:

1. 创建一个WifiP2pServiceInfo对象;

2. 填入你的服务相关的信息;

3. 调用addLocalService()方法来注册本地服务,让其可发现。

 1 private void startRegistration(){
 2 // Create a string map containing information about your service.
 3         Map record = new HashMap();
 4         record.put("listenport", String.valueOf(SERVER_PORT));
 5         record.put("buddyname", "John Doe" + (int) (Math.random() * 1000));
 6         record.put("available", "visible");
 7         // Serviceinformation.  Pass it an instance name, service type
 8         //_protocol._transportlayer , and the map containing
 9         //information other devices will want once they connect to this one.
10         WifiP2pDnsSdServiceInfo serviceInfo =
11                 WifiP2pDnsSdServiceInfo.newInstance("_test", "_presence._tcp", record);
12         // Add thelocal service, sending the service info, network channel,
13         // andlistener that will be used to indicate success or failure of
14         // therequest.
15         mManager.addLocalService(channel, serviceInfo, new ActionListener() {
16             @Override
17             public void onSuccess() {
18                 // Command successful! Code isn‘t necessarily needed here,
19                 // Unless you want to update the UI or add logging statements.
20             }
21             @Override
22             public void onFailure(int arg0) {
23                 // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
24             }
25         });
26     } 

发现附近的服务

Android使用回调方法来通知你的应用程序可用的服务,因此首先要做的就是要建立回调方法。创建一个WifiP2pManager.DnsSdTxtRecordListener对象来监听传入的记录。这个记录可以是其他设备的任意广播。当一个记录进入时,你可以把设备地址和其他你想要的其他相关信息复制到当前方法外部的数据结构中,以便后续可以访问它。下面的例子假设记录中包含一个“buddyname”字段,它带有用户的标识。

 1 finalHashMap<String,String> buddies =newHashMap<String,String>();
 2 ...
 3 private void discoverService() {
 4     DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
 5         @Override
 6         /* Callbackincludes:
 7          * fullDomain: full domainname: e.g "printer._ipp._tcp.local."
 8          * record: TXT record dta as amap of key/value pairs.
 9          * device: The device runningthe advertised service.
10          */
11         public voidonDnsSdTxtRecordAvailable(
12                 String fullDomain, Map record, WifiP2pDevice device) {
13                 Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
14                 buddies.put(device.deviceAddress, record.get("buddyname"));
15             }
16         };
17     ...
18 }

实现一个WifiP2pManager.DnsSdServiceResponseListener接口,来获取服务信息。这个接口会接收实际的描述和连接信息。上面的代码中使用了Map对象把设备地址和用户标识组成一对。服务响应监听器使用这个接口把DNS记录和对应的服务信息连接到一起。实现上述两个监听器后,使用setDnsSdResponseListener()方法把它们添加给WifiP2pManager对象。

 1 private void discoverService(){
 2 ...
 3     DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
 4         @Override
 5         public voidonDnsSdServiceAvailable(String instanceName, String registrationType,
 6                 WifiP2pDevice resourceType) {
 7                 // Update the device name with the human-friendly version from
 8                 // the DnsTxtRecord, assuming one arrived.
 9                resourceType.deviceName = buddies
10                        .containsKey(resourceType.deviceAddress) ? buddies
11                        .get(resourceType.deviceAddress) : resourceType.deviceName;
12                 // Add to the custom adapter defined specifically for showing
13                 // wifi devices.
14                 WiFiDirectServicesList fragment = (WiFiDirectServicesList)getFragmentManager()
15                        .findFragmentById(R.id.frag_peerlist);
16                 WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter)fragment
17                        .getListAdapter());
18                 adapter.add(resourceType);
19                 adapter.notifyDataSetChanged();
20                 Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
21         }
22     };
23     mManager.setDnsSdResponseListeners(channel, servListener, txtListener);
24     ...
25 }

现在创建一个服务请求并调用addServiceRequest()方法,这个方法也需要一个监听器来包括成功或失败。

 1 serviceRequest =WifiP2pDnsSdServiceRequest.newInstance();
 2         mManager.addServiceRequest(channel,
 3                 serviceRequest,
 4                 new ActionListener() {
 5                    @Override
 6                    public void onSuccess() {
 7                        // Success!
 8                    }
 9                    @Override
10                    public void onFailure(int code) {
11                        // Command failed.  Check forP2P_UNSUPPORTED, ERROR, or BUSY
12                    }
13                 });

最后,调用的discoverServices()方法。

 1 mManager.discoverServices(channel,newActionListener(){
 2 @Override
 3             public void onSuccess() {
 4                 // Success!
 5             }
 6             @Override
 7             public void onFailure(int code) {
 8                 // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
 9                 if (code == WifiP2pManager.P2P_UNSUPPORTED) {
10                    Log.d(TAG, "P2P isn‘tsupported on this device.");
11                 else if(...)
12                    ...
13             }
14         });

如果一切顺利,恭喜你大功告成。如果遇到问题,前面异步调用的参数WifiP2pManager.ActionListener参数,它提供了指示成功或失败的回调方法。把调试断点设置在onFailure()方法中来诊断问题。这个方法提供了错误代码,以下是可能发生的错误:

P2P_UNSUPPORTED

运行app的设备上不支持Wi-Fi P2P

BUSY

系统忙于处理请求

ERROR

由于内部错误导致操作失败

时间: 2025-01-18 00:50:55

Android WiFiDirect 学习(二)——Service Discovery的相关文章

Android WifiDirect 学习(三) 一些基础知识和问题

P2P架构介绍 P2P架构中定义了三个组件,一个设备,两种角色.这三个组件分别是: P2P Device:它是P2P架构中角色的实体,读者可把它当做一个Wi-Fi设备. P2P Group Owner(GO):P2P网络建立时会产生一个Group. P2P Group Client(GC): 在组建P2P Group(即P2P Network)之前,智能终端都是一个一个的P2P Device. 当这些P2P Device设备之间完成P2P协商后,那么其中将有一个并且只能有一个Device来扮演G

Android 四大组件 (二) Service 使用

一. Service 介绍 Service属于android四大组件之一,在很多地方经常被用到.开启Service有两种不同的方式:startService和bindService.不同的开启方式,Service执行的生命周期方法也不同. 分 显示/隐示调用 ,但是官网推荐用显式的方式启动Service.下面 service使用 用的就是显示调用:注意事项用的就是隐示调用,在5.0系统上隐示调用会报错.所以这里只介绍使用显示调用. 不能再service里做耗时操作,否则ANR:需要开辟子线程进行

Android开发学习二:编写Helloworld

学习视频 [中文Android开发视频教学].01_03_say_hello_to_Android.mp4 参考网址: http://www.open-open.com/lib/view/open1386252535564.html

深入剖析Android四大组件(二)——Service服务之启动与绑定

如果说Activity通常都会提供一个用户界面UI的话,那么服务则不会提供任何用户界面,尽管如此,服务的作用仍然非常重要,它为我们提供了一种类似守护线程的手段来维持一些希望在退出以后仍然能持续运行的程序. 1.服务 既然服务的作用如此重要,本篇主要讲解如何使用服务和声明应用程序服务,下一节讲解怎么高效率的运用服务. ①何为服务 服务是一个应用程序组件,它在后台执行运行时间比较长的操作,不提供用户界面.它可以被其他应用程序组件启动或停止,并且当用户切换到另一个应用程序时,它仍然在后台持续的运行.另

Android WifiDirect学习(一)

WiFi Direct基本介绍 Wi-Fi Direct标准允许无线网络中的设备无需通过无线路由器即可相互连接.与蓝牙技术类似,这种标准允许无线设备以点对点形式互连,不过在传输速度与传输距离方面则比蓝牙有大幅提升. Wi-Fi Direct可以支持一对一直连,也可以实现多台设备同时连接   WiFiDirect  一对一 搜索/连接/传输基本流程 第一步:初始化WifiDirect模块,一般情况下,只要打开Wifi,WifiDirect就会处于激活状态 第二步:WifiDirect进行搜索状态,

Android ORM-GreenDao学习二之进阶篇

概述 本文讲述GreenDao对关系数据的支持.分别为 ToOne, ToMany. 双向关联 Tree Relations To-One 相当于外键关系. // The variables "user" and "picture" are just regular entities Property pictureIdProperty = user.addLongProperty("pictureId").getProperty(); user

Android的学习之路(二)项目中原生文件的使用场景和文件介绍

1.src文件:java源代码存放目录 2.gen 文件:自动生成所有由android开发工具自动生成的文件,目录中最重要的就是R.java文件,这个文件由android开 发工具自动产生的.android开发工具会自动根据你存放res目录的资源,同步更新修稿R.java文件,正因为 R.java文件是由开发工具自动生成的,所以我们应避免手工修改R.java.R.java文件在应用中起到了字典的作 用,它包含了各种资源的ID,通过R.java,应用可以很方便的找到对应资源, 2.1R.java 

Android Binder分析二:Natvie Service的注冊

这一章我们通过MediaPlayerService的注冊来说明怎样在Native层通过binder向ServiceManager注冊一个service,以及client怎样通过binder向ServiceManager获得一个service,并调用这个Service的方法. Native Service的注冊 这里以MediaPlayerService举例来说明怎样在Native层注冊Service,首先来看main_mediaservice.cpp的main方法: int main(int a

疯狂Android讲义 - 学习笔记(二)

Android应用的用户界面编程 Android推荐使用XML布局文件来定义用户界面 ViewGroup是一个抽象类,通常使用它的子类作为容器,ViewGroup控制其子组件的分布依赖于两个内部类: ViewGroup.LayoutParams 和 ViewGroup.MarginLayoutParams 疯狂Android讲义 - 学习笔记(二),布布扣,bubuko.com