Home | History | Annotate | Download | only in connect-devices-wirelessly
      1 page.title=Using Network Service Discovery
      2 parent.title=Connecting Devices Wirelessly
      3 parent.link=index.html
      4 
      5 trainingnavtop=true
      6 next.title=Connecting with Wi-Fi Direct
      7 next.link=wifi-direct.html
      8 
      9 @jd:body
     10 
     11 <div id="tb-wrapper">
     12 <div id="tb">
     13 
     14 <!-- table of contents -->
     15 <h2>This lesson teaches you how to</h2>
     16 <ol>
     17   <li><a href="#register">Register Your Service on the Network</a></li>
     18   <li><a href="#discover">Discover Services on the Network</a></li>
     19   <li><a href="#connect">Connect to Services on the Network</a></li>
     20   <li><a href="#teardown">Unregister Your Service on Application Close</a></li>
     21 </ol>
     22 
     23 <!--
     24 <h2>You should also read</h2>
     25     <ul>
     26     </ul>
     27 -->
     28 <h2>Try it out</h2>
     29 
     30 <div class="download-box">
     31   <a href="{@docRoot}shareables/training/NsdChat.zip" class="button">Download
     32     the sample app</a>
     33   <p class="filename">NsdChat.zip</p>
     34 </div>
     35 </p>
     36 
     37 </div>
     38 </div>
     39 
     40 <p>Adding Network Service Discovery (NSD) to your app allows your users to
     41 identify other devices on the local network that support the services your app
     42 requests. This is useful for a variety of peer-to-peer applications such as file
     43 sharing or multi-player gaming. Android's NSD APIs simplify the effort required
     44 for you to implement such features.</p>
     45 
     46 <p>This lesson shows you how to build an application that can broadcast its
     47 name and connection information to the local network and scan for information
     48 from other applications doing the same.  Finally, this lesson shows you how
     49 to connect to the same application running on another device.</p>
     50 
     51 <h2 id="register">Register Your Service on the Network</h2>
     52 
     53 <p class="note"><strong>Note: </strong>This step is optional.  If
     54 you don't care about broadcasting your app's services over the local network,
     55 you can skip forward to the
     56 next section, <a href="#discover">Discover Services on the Network</a>.</p>
     57 
     58 <p>To register your service on the local network, first create a {@link
     59 android.net.nsd.NsdServiceInfo} object.  This object provides the information
     60 that other devices on the network use when they're deciding whether to connect to your
     61 service. </p>
     62 
     63 <pre>
     64 public void registerService(int port) {
     65     // Create the NsdServiceInfo object, and populate it.
     66     NsdServiceInfo serviceInfo  = new NsdServiceInfo();
     67 
     68     // The name is subject to change based on conflicts
     69     // with other services advertised on the same network.
     70     serviceInfo.setServiceName("NsdChat");
     71     serviceInfo.setServiceType("_http._tcp.");
     72     serviceInfo.setPort(port);
     73     ....
     74 }
     75 </pre>
     76 
     77 <p>This code snippet sets the service name to "NsdChat".
     78 The name is visible to any device on the network that is using NSD to look for
     79 local services.  Keep in mind that the name must be unique for any service on the
     80 network, and Android automatically handles conflict resolution.  If
     81 two devices on the network both have the NsdChat application installed, one of
     82 them changes the service name automatically, to something like "NsdChat
     83 (1)".</p>
     84 
     85 <p>The second parameter sets the service type, specifies which protocol and transport
     86 layer the application uses.  The syntax is
     87 "_&lt;protocol&gt;._&lt;transportlayer&gt;".  In the
     88 code snippet, the service uses HTTP protocol running over TCP.  An application
     89 offering a printer service (for instance, a network printer) would set the
     90 service type to "_ipp._tcp".</p>
     91 
     92 <p class="note"><strong>Note: </strong> The International Assigned Numbers
     93 Authority (IANA) manages a centralized,
     94 authoritative list of service types used by service discovery protocols such as NSD and Bonjour.
     95 You can download the list from <a
     96   href="http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml">the
     97 IANA list of service names and port numbers</a>.
     98 If you intend to use a new service type, you should reserve it by filling out
     99 the  <a
    100   href="http://www.iana.org/form/ports-services">IANA Ports and Service
    101   registration form</a>.</p>
    102 
    103 <p>When setting the port for your service, avoid hardcoding it as this
    104 conflicts with other applications.  For instance, assuming
    105 that your application always uses port 1337 puts it in potential conflict with
    106 other installed applications that use the same port.  Instead, use the device's
    107 next available port.  Because this information is provided to other apps by a
    108 service broadcast, there's no need for the port your application uses to be
    109 known by other applications at compile-time.  Instead, the applications can get
    110 this information from your service broadcast, right before connecting to your
    111 service.</p>
    112 
    113 <p>If you're working with sockets, here's how you can initialize a socket to any
    114 available port simply by setting it to 0.</p>
    115 
    116 <pre>
    117 public void initializeServerSocket() {
    118     // Initialize a server socket on the next available port.
    119     mServerSocket = new ServerSocket(0);
    120 
    121     // Store the chosen port.
    122     mLocalPort =  mServerSocket.getLocalPort();
    123     ...
    124 }
    125 </pre>
    126 
    127 <p>Now that you've defined the {@link android.net.nsd.NsdServiceInfo
    128 NsdServiceInfo} object, you need to implement the {@link
    129 android.net.nsd.NsdManager.RegistrationListener RegistrationListener} interface.  This
    130 interface contains callbacks used by Android to alert your application of the
    131 success or failure of service registration and unregistration.
    132 </p>
    133 <pre>
    134 public void initializeRegistrationListener() {
    135     mRegistrationListener = new NsdManager.RegistrationListener() {
    136 
    137         &#64;Override
    138         public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
    139             // Save the service name.  Android may have changed it in order to
    140             // resolve a conflict, so update the name you initially requested
    141             // with the name Android actually used.
    142             mServiceName = NsdServiceInfo.getServiceName();
    143         }
    144 
    145         &#64;Override
    146         public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
    147             // Registration failed!  Put debugging code here to determine why.
    148         }
    149 
    150         &#64;Override
    151         public void onServiceUnregistered(NsdServiceInfo arg0) {
    152             // Service has been unregistered.  This only happens when you call
    153             // NsdManager.unregisterService() and pass in this listener.
    154         }
    155 
    156         &#64;Override
    157         public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
    158             // Unregistration failed.  Put debugging code here to determine why.
    159         }
    160     };
    161 }
    162 </pre>
    163 
    164 <p>Now you have all the pieces to register your service.  Call the method
    165 {@link android.net.nsd.NsdManager#registerService registerService()}.
    166 </p>
    167 
    168 <p>Note that this method is asynchronous, so any code that needs to run
    169 after the service has been registered must go in the {@link
    170 android.net.nsd.NsdManager.RegistrationListener#onServiceRegistered(NsdServiceInfo)
    171 onServiceRegistered()} method.</p>
    172 
    173 <pre>
    174 public void registerService(int port) {
    175     NsdServiceInfo serviceInfo  = new NsdServiceInfo();
    176     serviceInfo.setServiceName("NsdChat");
    177     serviceInfo.setServiceType("_http._tcp.");
    178     serviceInfo.setPort(port);
    179 
    180     mNsdManager = Context.getSystemService(Context.NSD_SERVICE);
    181 
    182     mNsdManager.registerService(
    183             serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
    184 }
    185 </pre>
    186 
    187 <h2 id="discover">Discover Services on the Network</h2>
    188 <p>The network is teeming with life, from the beastly network printers to the
    189 docile network webcams, to the brutal, fiery battles of nearby tic-tac-toe
    190 players.  The key to letting your application see this vibrant ecosystem of
    191 functionality is service discovery.  Your application needs to listen to service
    192 broadcasts on the network to see what services are available, and filter out
    193 anything the application can't work with.</p>
    194 
    195 <p>Service discovery, like service registration, has two steps:
    196  setting up a discovery listener with the relevant callbacks, and making a single asynchronous
    197 API call to {@link android.net.nsd.NsdManager#discoverServices(String
    198 , int , NsdManager.DiscoveryListener) discoverServices()}.</p>
    199 
    200 <p>First, instantiate an anonymous class that implements {@link
    201 android.net.nsd.NsdManager.DiscoveryListener}.  The following snippet shows a
    202 simple example:</p>
    203 
    204 <pre>
    205 public void initializeDiscoveryListener() {
    206 
    207     // Instantiate a new DiscoveryListener
    208     mDiscoveryListener = new NsdManager.DiscoveryListener() {
    209 
    210         //  Called as soon as service discovery begins.
    211         &#64;Override
    212         public void onDiscoveryStarted(String regType) {
    213             Log.d(TAG, "Service discovery started");
    214         }
    215 
    216         &#64;Override
    217         public void onServiceFound(NsdServiceInfo service) {
    218             // A service was found!  Do something with it.
    219             Log.d(TAG, "Service discovery success" + service);
    220             if (!service.getServiceType().equals(SERVICE_TYPE)) {
    221                 // Service type is the string containing the protocol and
    222                 // transport layer for this service.
    223                 Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
    224             } else if (service.getServiceName().equals(mServiceName)) {
    225                 // The name of the service tells the user what they'd be
    226                 // connecting to. It could be "Bob's Chat App".
    227                 Log.d(TAG, "Same machine: " + mServiceName);
    228             } else if (service.getServiceName().contains("NsdChat")){
    229                 mNsdManager.resolveService(service, mResolveListener);
    230             }
    231         }
    232 
    233         &#64;Override
    234         public void onServiceLost(NsdServiceInfo service) {
    235             // When the network service is no longer available.
    236             // Internal bookkeeping code goes here.
    237             Log.e(TAG, "service lost" + service);
    238         }
    239 
    240         &#64;Override
    241         public void onDiscoveryStopped(String serviceType) {
    242             Log.i(TAG, "Discovery stopped: " + serviceType);
    243         }
    244 
    245         &#64;Override
    246         public void onStartDiscoveryFailed(String serviceType, int errorCode) {
    247             Log.e(TAG, "Discovery failed: Error code:" + errorCode);
    248             mNsdManager.stopServiceDiscovery(this);
    249         }
    250 
    251         &#64;Override
    252         public void onStopDiscoveryFailed(String serviceType, int errorCode) {
    253             Log.e(TAG, "Discovery failed: Error code:" + errorCode);
    254             mNsdManager.stopServiceDiscovery(this);
    255         }
    256     };
    257 }
    258 </pre>
    259 
    260 <p>The NSD API uses the methods in this interface to inform your application when discovery
    261 is started, when it fails, and when services are found and lost (lost means "is
    262 no longer available").  Notice that this snippet does several checks
    263 when a service is found.</p>
    264 <ol>
    265   <li>The service name of the found service is compared to the service
    266 name of the local service to determine if the device just picked up its own
    267 broadcast (which is valid).</li>
    268 <li>The service type is checked, to verify it's a type of service your
    269 application can connect to.</li>
    270 <li>The service name is checked to verify connection to the correct
    271 application.</li>
    272 </ol>
    273 
    274 <p>Checking the service name isn't always necessary, and is only relevant if you
    275 want to connect to a specific application.  For instance, the application might
    276 only want to connect to instances of itself running on other devices.  However, if the
    277 application wants to connect to a network printer, it's enough to see that the service type
    278 is "_ipp._tcp".</p>
    279 
    280 <p>After setting up the listener, call {@link android.net.nsd.NsdManager#discoverServices(String, int,
    281 NsdManager.DiscoveryListener) discoverServices()}, passing in the service type
    282 your application should look for, the discovery protocol to use, and the
    283 listener you just created.</p>
    284 
    285 <pre>
    286     mNsdManager.discoverServices(
    287         SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
    288 </pre>
    289 
    290 
    291 <h2 id="connect">Connect to Services on the Network</h2>
    292 <p>When your application finds a service on the network to connect to, it
    293 must first determine the connection information for that service, using the
    294 {@link android.net.nsd.NsdManager#resolveService resolveService()} method.
    295 Implement a {@link android.net.nsd.NsdManager.ResolveListener} to pass into this
    296 method, and use it to get a {@link android.net.nsd.NsdServiceInfo} containing
    297 the connection information.</p>
    298 
    299 <pre>
    300 public void initializeResolveListener() {
    301     mResolveListener = new NsdManager.ResolveListener() {
    302 
    303         &#64;Override
    304         public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
    305             // Called when the resolve fails.  Use the error code to debug.
    306             Log.e(TAG, "Resolve failed" + errorCode);
    307         }
    308 
    309         &#64;Override
    310         public void onServiceResolved(NsdServiceInfo serviceInfo) {
    311             Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
    312 
    313             if (serviceInfo.getServiceName().equals(mServiceName)) {
    314                 Log.d(TAG, "Same IP.");
    315                 return;
    316             }
    317             mService = serviceInfo;
    318             int port = mService.getPort();
    319             InetAddress host = mService.getHost();
    320         }
    321     };
    322 }
    323 </pre>
    324 
    325 <p>Once the service is resolved, your application receives detailed
    326 service information including an IP address and port number.  This is  everything
    327 you need to create your own network connection to the service.</p>
    328 
    329 
    330 <h2 id="teardown">Unregister Your Service on Application Close</h2>
    331 <p>It's important to enable and disable NSD
    332 functionality as appropriate during the application's
    333 lifecycle.  Unregistering your application when it closes down helps prevent
    334 other applications from thinking it's still active and attempting to connect to
    335 it.  Also, service discovery is an expensive operation, and should be stopped
    336 when the parent Activity is paused, and re-enabled when the Activity is
    337 resumed.  Override the lifecycle methods of your main Activity and insert code
    338 to start and stop service broadcast and discovery as appropriate.</p>
    339 
    340 <pre>
    341 //In your application's Activity
    342 
    343     &#64;Override
    344     protected void onPause() {
    345         if (mNsdHelper != null) {
    346             mNsdHelper.tearDown();
    347         }
    348         super.onPause();
    349     }
    350 
    351     &#64;Override
    352     protected void onResume() {
    353         super.onResume();
    354         if (mNsdHelper != null) {
    355             mNsdHelper.registerService(mConnection.getLocalPort());
    356             mNsdHelper.discoverServices();
    357         }
    358     }
    359 
    360     &#64;Override
    361     protected void onDestroy() {
    362         mNsdHelper.tearDown();
    363         mConnection.tearDown();
    364         super.onDestroy();
    365     }
    366 
    367     // NsdHelper's tearDown method
    368         public void tearDown() {
    369         mNsdManager.unregisterService(mRegistrationListener);
    370         mNsdManager.stopServiceDiscovery(mDiscoveryListener);
    371     }
    372 </pre>
    373 
    374