ネットワーク サービス ディスカバリを使用する

ネットワーク サービス ディスカバリ(NSD)を使用すると、アプリから他の ローカル ネットワーク上で提供できます。NSD に対応しているデバイスには、プリンタ、 ウェブカメラ、HTTPS サーバー、その他のモバイル デバイスに接続できます。

NSD は、DNS ベースのサービス ディスカバリ(DNS-SD)メカニズムを実装しています。 サービスの種類と名前を指定することで、アプリがサービスをリクエストできます。 必要なタイプのサービスを提供するデバイス インスタンスのインスタンスです。DNS-SD は Android と他のモバイル プラットフォームの両方でサポートされています。

アプリに NSD を追加すると、ユーザーは アプリがリクエストするサービスをサポートするローカル ネットワーク。これは ファイル共有やマルチプレーヤー型ゲームなどのさまざまなピアツーピア アプリケーション 可能です。Android の NSD API で実装に必要な労力を簡素化 制限します。

このレッスンでは、アプリをブロードキャストできるアプリの作成方法について説明します。 ローカル ネットワークに接続して情報をスキャンし、 パフォーマンスが向上します最後に 別のデバイスで実行されている同じアプリケーションに接続できます。

サービスをネットワークに登録する

注: この手順は省略可能です。条件 アプリのサービスをローカル ネットワーク経由でブロードキャストしなくても構いません。 スキップして 次のセクションのネットワーク上のサービスを検出するをご覧ください。

サービスをローカル ネットワークに登録するには、はじめに NsdServiceInfo オブジェクトを作成します。このオブジェクトは、Google Cloud Storage 接続するかどうかを決定する際に、ネットワーク上の他のデバイスが あります。

KotlinJava
fun registerService(port: Int) {
   
// Create the NsdServiceInfo object, and populate it.
   
val serviceInfo = NsdServiceInfo().apply {
       
// The name is subject to change based on conflicts
       
// with other services advertised on the same network.
        serviceName
= "NsdChat"
        serviceType
= "_nsdchat._tcp"
        setPort
(port)
       
...
   
}
}
public void registerService(int port) {
   
// Create the NsdServiceInfo object, and populate it.
   
NsdServiceInfo serviceInfo = new NsdServiceInfo();

   
// The name is subject to change based on conflicts
   
// with other services advertised on the same network.
    serviceInfo
.setServiceName("NsdChat");
    serviceInfo
.setServiceType("_nsdchat._tcp");
    serviceInfo
.setPort(port);
   
...
}

このコード スニペットでは、サービス名を「NsdChat」に設定しています。サービス名 インスタンス名です。ネットワーク上の他のデバイスに表示される名前です。 この名前は、NSD を使用して検索しているネットワーク上のすべてのデバイスに表示されます。 提供します。名前は、Compute Engine のどのサービスでも 競合の解決は自動的に処理されます。条件 ネットワーク上の 2 つのデバイスに、NsdChat アプリケーションがインストールされていること。 サービス名を「NsdChat」のような名前に (1)」をご覧ください。

2 番目のパラメータでは、サービスタイプを設定し、使用するプロトコルとトランスポート レイヤに配置されます。構文は次のとおりです。 "_<protocol>._<transportlayer>" として指定します。 このサービスは TCP 上で実行される HTTP プロトコルを使用します。アプリケーション プリンタ サービス(ネットワーク プリンタなど)を提供する場合、 「_ipp._tcp」に設定します。

注: The International Assigned Numbers(国際割り当て番号) Authority(IANA)は、一元化された NSD や Bonjour などのサービス ディスカバリ プロトコルで使用されるサービスタイプの信頼できるリスト。 このリストは、 サービス名とポート番号の IANA リスト。 新しいサービスタイプを使用する場合は、 IANA のポートとサービスの 登録フォームに記入します。

サービスのポートを設定するときは、次のようにハードコードしないでください。 他のアプリケーションと競合します。たとえば アプリケーションが常にポート 1337 を使用していると、 同じポートを使用する他のインストール済みアプリケーション代わりに、デバイスの ポートを指定します。この情報は サービス ブロードキャストにより、アプリケーションで使用するポートを コンパイル時に他のアプリが認識できる値を指定します。代わりに、アプリケーションは 接続の直前に、サービス ブロードキャストからこの情報が あります。

ソケットを扱っている場合、以下がソケットを任意のものに対して初期化する方法です。 ポートを 0 に設定するだけです。

KotlinJava
fun initializeServerSocket() {
   
// Initialize a server socket on the next available port.
    serverSocket
= ServerSocket(0).also { socket ->
       
// Store the chosen port.
        mLocalPort
= socket.localPort
       
...
   
}
}
public void initializeServerSocket() {
   
// Initialize a server socket on the next available port.
    serverSocket
= new ServerSocket(0);

   
// Store the chosen port.
    localPort
= serverSocket.getLocalPort();
   
...
}

NsdServiceInfo オブジェクトを定義したら、次は RegistrationListener インターフェースを実装する必要があります。この インターフェースには、Android がアプリに サービスの登録および登録解除の成功または失敗。

KotlinJava
private val registrationListener = object : NsdManager.RegistrationListener {

   
override fun onServiceRegistered(NsdServiceInfo: NsdServiceInfo) {
       
// Save the service name. Android may have changed it in order to
       
// resolve a conflict, so update the name you initially requested
       
// with the name Android actually used.
        mServiceName
= NsdServiceInfo.serviceName
   
}

   
override fun onRegistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
       
// Registration failed! Put debugging code here to determine why.
   
}

   
override fun onServiceUnregistered(arg0: NsdServiceInfo) {
       
// Service has been unregistered. This only happens when you call
       
// NsdManager.unregisterService() and pass in this listener.
   
}

   
override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
       
// Unregistration failed. Put debugging code here to determine why.
   
}
}
public void initializeRegistrationListener() {
    registrationListener
= new NsdManager.RegistrationListener() {

       
@Override
       
public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
           
// Save the service name. Android may have changed it in order to
           
// resolve a conflict, so update the name you initially requested
           
// with the name Android actually used.
            serviceName
= NsdServiceInfo.getServiceName();
       
}

       
@Override
       
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
           
// Registration failed! Put debugging code here to determine why.
       
}

       
@Override
       
public void onServiceUnregistered(NsdServiceInfo arg0) {
           
// Service has been unregistered. This only happens when you call
           
// NsdManager.unregisterService() and pass in this listener.
       
}

       
@Override
       
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
           
// Unregistration failed. Put debugging code here to determine why.
       
}
   
};
}

これで、サービスを登録する準備がすべて整いました。メソッドを呼び出す registerService()

このメソッドは非同期であるため、実行する必要があるコードは サービスの登録後は onServiceRegistered() メソッドに含める必要があります。

KotlinJava
fun registerService(port: Int) {
   
// Create the NsdServiceInfo object, and populate it.
   
val serviceInfo = NsdServiceInfo().apply {
       
// The name is subject to change based on conflicts
       
// with other services advertised on the same network.
        serviceName
= "NsdChat"
        serviceType
= "_nsdchat._tcp"
        setPort
(port)
   
}

    nsdManager
= (getSystemService(Context.NSD_SERVICE) as NsdManager).apply {
        registerService
(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener)
   
}
}
public void registerService(int port) {
   
NsdServiceInfo serviceInfo = new NsdServiceInfo();
    serviceInfo
.setServiceName("NsdChat");
    serviceInfo
.setServiceType("_http._tcp.");
    serviceInfo
.setPort(port);

    nsdManager
= Context.getSystemService(Context.NSD_SERVICE);

    nsdManager
.registerService(
            serviceInfo
, NsdManager.PROTOCOL_DNS_SD, registrationListener);
}

ネットワーク上のサービスを検出する

このネットワークは、猛烈なネットワーク プリンタから、 おとなしきネットワーク ウェブカメラ、近所の三目並べの残酷な戦いや、 できます。この活気に満ちたエコシステムを アプリケーションに サービス ディスカバリがあります。アプリケーションはサービス リクエストをリッスンする必要があります。 利用可能なサービスを確認して、フィルタで リソースを定義できます。

サービス登録と同様に、サービス ディスカバリには 2 つのステップがあります。 関連するコールバックを使用して検出リスナーを設定し、単一の非同期リクエストを discoverServices() に対する API 呼び出し。

はじめに、NsdManager.DiscoveryListener を実装する匿名クラスをインスタンス化します。次のスニペットは、 簡単な例で説明します。

KotlinJava
// Instantiate a new DiscoveryListener
private val discoveryListener = object : NsdManager.DiscoveryListener {

   
// Called as soon as service discovery begins.
   
override fun onDiscoveryStarted(regType: String) {
       
Log.d(TAG, "Service discovery started")
   
}

   
override fun onServiceFound(service: NsdServiceInfo) {
       
// A service was found! Do something with it.
       
Log.d(TAG, "Service discovery success$service")
       
when {
            service
.serviceType != SERVICE_TYPE -> // Service type is the string containing the protocol and
               
// transport layer for this service.
               
Log.d(TAG, "Unknown Service Type: ${service.serviceType}")
            service
.serviceName == mServiceName -> // The name of the service tells the user what they'd be
               
// connecting to. It could be "Bob's Chat App".
               
Log.d(TAG, "Same machine: $mServiceName")
            service
.serviceName.contains("NsdChat") -> nsdManager.resolveService(service, resolveListener)
       
}
   
}

   
override fun onServiceLost(service: NsdServiceInfo) {
       
// When the network service is no longer available.
       
// Internal bookkeeping code goes here.
       
Log.e(TAG, "service lost: $service")
   
}

   
override fun onDiscoveryStopped(serviceType: String) {
       
Log.i(TAG, "Discovery stopped: $serviceType")
   
}

   
override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
       
Log.e(TAG, "Discovery failed: Error code:$errorCode")
        nsdManager
.stopServiceDiscovery(this)
   
}

   
override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) {
       
Log.e(TAG, "Discovery failed: Error code:$errorCode")
        nsdManager
.stopServiceDiscovery(this)
   
}
}
public void initializeDiscoveryListener() {

   
// Instantiate a new DiscoveryListener
    discoveryListener
= new NsdManager.DiscoveryListener() {

       
// Called as soon as service discovery begins.
       
@Override
       
public void onDiscoveryStarted(String regType) {
           
Log.d(TAG, "Service discovery started");
       
}

       
@Override
       
public void onServiceFound(NsdServiceInfo service) {
           
// A service was found! Do something with it.
           
Log.d(TAG, "Service discovery success" + service);
           
if (!service.getServiceType().equals(SERVICE_TYPE)) {
               
// Service type is the string containing the protocol and
               
// transport layer for this service.
               
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
           
} else if (service.getServiceName().equals(serviceName)) {
               
// The name of the service tells the user what they'd be
               
// connecting to. It could be "Bob's Chat App".
               
Log.d(TAG, "Same machine: " + serviceName);
           
} else if (service.getServiceName().contains("NsdChat")){
                nsdManager
.resolveService(service, resolveListener);
           
}
       
}

       
@Override
       
public void onServiceLost(NsdServiceInfo service) {
           
// When the network service is no longer available.
           
// Internal bookkeeping code goes here.
           
Log.e(TAG, "service lost: " + service);
       
}

       
@Override
       
public void onDiscoveryStopped(String serviceType) {
           
Log.i(TAG, "Discovery stopped: " + serviceType);
       
}

       
@Override
       
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
           
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
            nsdManager
.stopServiceDiscovery(this);
       
}

       
@Override
       
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
           
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
            nsdManager
.stopServiceDiscovery(this);
       
}
   
};
}

NSD API はこのインターフェースのメソッドを使用して、検出時にアプリケーションに通知します。 サービスが発見および失われたとき(失われた状態とは、 は終了しています」)。このスニペットでは、いくつかのチェックが行われます。 サービスが発見されたときです。

  1. 検出されたサービスのサービス名は、そのサービス デバイスがローカル サービスの名前を使用して、デバイスが ブロードキャストします(これは有効です)。
  2. 対象のサービスのタイプを確認するために、 接続できるようになります。
  3. サービス名がチェックされ、正しいデバイスへの接続が 説明します。

サービス名の確認は必須ではありません。名前を確認する必要があるのは、 特定のアプリケーションに接続する必要は ありませんたとえば、アプリケーションで 他のデバイスで実行されている自身のインスタンスのみに接続する場合。ただし、 ネットワーク プリンタへの接続を求められた場合は、サービスのタイプ "_ipp._tcp" です。

リスナーを設定したら、discoverServices() を呼び出してサービスタイプを渡します。 使用する検出プロトコル、検出に使用するプロトコル、 追加します。

KotlinJava
nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)
nsdManager.discoverServices(
        SERVICE_TYPE
, NsdManager.PROTOCOL_DNS_SD, discoveryListener);

ネットワーク上のサービスに接続する

接続先のネットワーク上のサービスをアプリが検出すると、 まず、API キーを使用してそのサービスの接続情報を resolveService() メソッドを使用します。 これを渡す NsdManager.ResolveListener を実装します。 メソッドを実行し、これを使用してNsdServiceInfo 接続情報を記録します。

KotlinJava
private val resolveListener = object : NsdManager.ResolveListener {

   
override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
       
// Called when the resolve fails. Use the error code to debug.
       
Log.e(TAG, "Resolve failed: $errorCode")
   
}

   
override fun onServiceResolved(serviceInfo: NsdServiceInfo) {
       
Log.e(TAG, "Resolve Succeeded. $serviceInfo")

       
if (serviceInfo.serviceName == mServiceName) {
           
Log.d(TAG, "Same IP.")
           
return
       
}
        mService
= serviceInfo
       
val port: Int = serviceInfo.port
       
val host: InetAddress = serviceInfo.host
   
}
}
public void initializeResolveListener() {
    resolveListener
= new NsdManager.ResolveListener() {

       
@Override
       
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
           
// Called when the resolve fails. Use the error code to debug.
           
Log.e(TAG, "Resolve failed: " + errorCode);
       
}

       
@Override
       
public void onServiceResolved(NsdServiceInfo serviceInfo) {
           
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);

           
if (serviceInfo.getServiceName().equals(serviceName)) {
               
Log.d(TAG, "Same IP.");
               
return;
           
}
            mService
= serviceInfo;
           
int port = mService.getPort();
           
InetAddress host = mService.getHost();
       
}
   
};
}

サービスが解決すると、アプリケーションには サービス情報(IP アドレスやポート番号など)これがすべて サービスへの独自のネットワーク接続を作成する必要があります。

アプリの終了時にサービスを登録解除する

NSD の有効化と無効化が重要 アプリケーションの実行時に、必要に応じて 説明します。アプリの終了時にアプリの登録を解除すると、 接続を試行しなくても、アプリケーションやサービスが できます。また、サービス ディスカバリは負荷の高いオペレーションであるため、停止する必要があります。 親 Activity が一時停止され、その Activity が一時停止されると再度有効になります。 再開されました。メイン アクティビティのライフサイクル メソッドをオーバーライドしてコードを挿入する 必要に応じてサービス ブロードキャストと検出を開始および停止できます。

KotlinJava
    // In your application's Activity

   
override fun onPause() {
        nsdHelper
?.tearDown()
       
super.onPause()
   
}

   
override fun onResume() {
       
super.onResume()
        nsdHelper
?.apply {
            registerService
(connection.localPort)
            discoverServices
()
       
}
   
}

   
override fun onDestroy() {
        nsdHelper
?.tearDown()
        connection
.tearDown()
       
super.onDestroy()
   
}

   
// NsdHelper's tearDown method
   
fun tearDown() {
        nsdManager
.apply {
            unregisterService
(registrationListener)
            stopServiceDiscovery
(discoveryListener)
       
}
   
}

    // In your application's Activity

   
@Override
   
protected void onPause() {
       
if (nsdHelper != null) {
            nsdHelper
.tearDown();
       
}
       
super.onPause();
   
}

   
@Override
   
protected void onResume() {
       
super.onResume();
       
if (nsdHelper != null) {
            nsdHelper
.registerService(connection.getLocalPort());
            nsdHelper
.discoverServices();
       
}
   
}

   
@Override
   
protected void onDestroy() {
        nsdHelper
.tearDown();
        connection
.tearDown();
       
super.onDestroy();
   
}

   
// NsdHelper's tearDown method
   
public void tearDown() {
        nsdManager
.unregisterService(registrationListener);
        nsdManager
.stopServiceDiscovery(discoveryListener);
   
}