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权限。

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

添加Local Service

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

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

1. 创建一个WifiP2pServiceInfo对象;

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

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

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

发现附近的服务

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

 finalHashMap<String,String> buddies =newHashMap<String,String>();
...
private void discoverService() {
DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
@Override
/* Callbackincludes:
* fullDomain: full domainname: e.g "printer._ipp._tcp.local."
* record: TXT record dta as amap of key/value pairs.
* device: The device runningthe advertised service.
*/
public voidonDnsSdTxtRecordAvailable(
String fullDomain, Map record, WifiP2pDevice device) {
Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
buddies.put(device.deviceAddress, record.get("buddyname"));
}
};
...
}

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

 private void discoverService(){
...
DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
@Override
public voidonDnsSdServiceAvailable(String instanceName, String registrationType,
WifiP2pDevice resourceType) {
// Update the device name with the human-friendly version from
// the DnsTxtRecord, assuming one arrived.
resourceType.deviceName = buddies
.containsKey(resourceType.deviceAddress) ? buddies
.get(resourceType.deviceAddress) : resourceType.deviceName;
// Add to the custom adapter defined specifically for showing
// wifi devices.
WiFiDirectServicesList fragment = (WiFiDirectServicesList)getFragmentManager()
.findFragmentById(R.id.frag_peerlist);
WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter)fragment
.getListAdapter());
adapter.add(resourceType);
adapter.notifyDataSetChanged();
Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
}
};
mManager.setDnsSdResponseListeners(channel, servListener, txtListener);
...
}

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

 serviceRequest =WifiP2pDnsSdServiceRequest.newInstance();
mManager.addServiceRequest(channel,
serviceRequest,
new ActionListener() {
@Override
public void onSuccess() {
// Success!
}
@Override
public void onFailure(int code) {
// Command failed. Check forP2P_UNSUPPORTED, ERROR, or BUSY
}
});

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

 mManager.discoverServices(channel,newActionListener(){
@Override
public void onSuccess() {
// Success!
}
@Override
public void onFailure(int code) {
// Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
if (code == WifiP2pManager.P2P_UNSUPPORTED) {
Log.d(TAG, "P2P isn'tsupported on this device.");
else if(...)
...
}
});

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

P2P_UNSUPPORTED

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

BUSY

系统忙于处理请求

ERROR

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

参考文章

Android 4.1 API中文详解-Android 4.1 APIs  http://wiki.eoeandroid.com/Android_4.1_APIs

http://developer.android.com/

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

  1. Android JNI学习(二)——实战JNI之“hello world”

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

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

    P2P架构介绍 P2P架构中定义了三个组件,一个设备,两种角色.这三个组件分别是: P2P Device:它是P2P架构中角色的实体,读者可把它当做一个Wi-Fi设备. P2P Group Owner ...

  3. Android动画学习(二)——Tween Animation

    前两天写过一篇Android动画学习的概述,大致的划分了下Android Animation的主要分类,没有看过的同学请移步:Android动画学习(一)——Android动画系统框架简介.今天接着来 ...

  4. Android WifiDirect学习(一)

    WiFi Direct基本介绍 Wi-Fi Direct标准允许无线网络中的设备无需通过无线路由器即可相互连接.与蓝牙技术类似,这种标准允许无线设备以点对点形式互连,不过在传输速度与传输距离方面则比蓝 ...

  5. Android JNI 学习(二):JNI 设计机制

    本章我们重点说明以下JNI设计的问题,本章中提到的大多数设计问题都与native方法有关.至于调用相关的API的设计,我们会在后面进行介绍. 一.JNI接口函数和指针 native 代码通过调用JNI ...

  6. Android JNI学习(五)——Demo演示

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  7. Android JNI学习(四)——JNI的常用方法的中文API

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  8. Android JNI学习(三)——Java与Native相互调用

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  9. Android学习总结(二)——Service基本概念和生命周期

    好了,前面我们已经学习了Activity的知识,相信大家也有一定的理解,但是还是不能放松,Android四大组件,我们才学习了一个而已,接下我们继续学习Service.计划总结如下内容: 一.Serv ...

随机推荐

  1. 多线程09-Lock和Condition

    1.概念 Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 2. ...

  2. 关于laravel框架的Auth::attempt验证失败

    按照官方文档进行认证 发现不管怎么样都是失败 if (Auth::attempt(array('email' => $email, 'password' => $password), tr ...

  3. Win7下Solr4.10.1和TomCat8的安装

    1.系统为win7 64位系统,安装有wamp的环境,我的所有网站放在 d:\webserver下,域名指向该目录下的子目录: 2.安装TomCat8到 D:\Tomcat 8.0: 3.在 d:\w ...

  4. pip安装第三方库以及版本

    这篇blog只是写给自己看看的. 今天突然遇到sqlalchemy映射到数据库时,一个字段类型是datetime(6),我这边死活访问不上,之前一直没有问题,最后查明原因,原来是第三方库的版本问题,真 ...

  5. C程序设计语言练习题1-21

    练习1-21 编写程序entab,将空格串替换为最少数量的制表符和空格,但要保持单词之间的间隔不变.假设制表符终止的位置与练习1-20的detab程序的情况相同.当使用一个制表符或者一个空格都可以打到 ...

  6. [翻译]localStorage性能的好坏

    原文地址:Is localStorage performance a problem? 如果说2012年对于web开发世界来说有什么值得记住的事的话,关于localStorage性能的争论一定高居榜首 ...

  7. 子句判断、启动强度和去模糊化--AForge.NET框架的使用(三)

    原文:子句判断.启动强度和去模糊化--AForge.NET框架的使用(三) 使用AForge.NET进行模糊运算 上一篇说来一些模糊运算的数学问题,用AForge.NET做相关运算就很简单了. 1.联 ...

  8. 【HDOJ】1513 Palindrome

    DP,MLE后改为滚动数组AC. #include <cstdio> #include <cstring> #include <cstdlib> #define M ...

  9. COJ 0036 数数happy有多少个?

    数数happy有多少个? 难度级别:B: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 图图是个爱动脑子.观察能力很强的好学生.近期他正学英语 ...

  10. HDU_1426——数独问题,DFS

    Problem Description 自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视. 据说,在2008北京奥运会上,会将数独列为一个单独的项目进行 ...