Thread Network SDK for Android

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

Thread Network SDK は、デジタル キーチェーンに類似した機能を提供し、Android アプリが Thread ネットワーク認証情報を Google Play 開発者サービスと共有できるようにします。これにより、認証情報とユーザーデータを直接公開することなく、任意のスマートホーム エコシステムから任意の Thread デバイスを設定できます。

いくつかの API 呼び出しだけを行えます。

  1. Google Play 開発者サービスから優先 Thread ネットワーク認証情報をリクエストします。
  2. 新しいボーダー ルーターを設定し、Thread ネットワーク認証情報を Google Play 開発者サービスに追加します。
  3. フィールド内ボーダー ルーターがすでにある場合は、ボーダー ルーターが優先ネットワークに存在するかどうかを確認し、必要に応じて移行します。

ユーザーと開発者のために検討すべきことがいくつかあります。このガイドのほとんどの部分と他の主な機能、推奨される使用方法については、このガイドで説明します。

主な用語と API のコンセプト

始める前に、次の用語を理解しておくことをおすすめします。

  • Thread ネットワーク認証情報: Thread デバイスが特定の Thread ネットワークに接続するために必要な、Thread ネットワーク名、ネットワーク キー、およびその他のプロパティをエンコードする、スレッド TLV のバイナリ blob。

  • 優先スレッド ネットワーク認証情報: 自動的に選択された Thread ネットワーク認証情報。getPreferredCredentials API を使用して、さまざまなベンダーのアプリと共有できます。

  • ボーダー エージェント ID: スレッド ボーダー ルーター デバイスの 16 バイトのグローバルに一意の ID。この ID は、枠線ルーターのベンダーによって作成され、管理されます。

  • Thread Border Router セットアップ アプリ: 新しい Thread Border Router デバイスを設定し、Google Play 開発者サービスに Thread ネットワーク認証情報を追加する Android アプリです。アプリが、追加された認証情報の正式なオーナーであり、認証情報に自由にアクセスできる。

Thread Network API の多くは、非同期で実行されるタスクを返します。addOnSuccessListeneraddOnFailureListener を使用して、結果を受け取るコールバックを登録できます。詳細については、タスクのドキュメントをご覧ください。

認証情報の所有権とメンテナンス

Thread ネットワーク認証情報を追加するアプリが認証情報の所有者になり、認証情報にアクセスするための完全な権限が付与されます。他のアプリによって追加された認証情報にアクセスしようとすると、PERMISSION_DENIED エラーが発生します。

Thread Border Router ネットワークを更新する際は、アプリ所有者として Google Play 開発者サービスに保存されている認証情報を最新の状態に保つことをおすすめします。つまり、必要に応じて認証情報を追加し、ボーダー ルーターの Thread ネットワークの認証情報が変更されたときに認証情報を更新します。また、Thread ボーダー ルーターが削除または出荷時の設定にリセットされたときに認証情報を削除します。

Border Agent の調査

認証情報は Border Agent ID を付けて保存する必要があります。Thread Border Router セットアップ アプリが Thread 境界ルーターの Border Agent ID を判断できることを確認する必要があります。

Thread ボーダー ルーターは、mDNS を使用して Thread ネットワーク情報(ネットワーク名、拡張パン ID、境界エージェント ID など)をアドバタイズする必要があります。これらの属性に対応する txt 値は、それぞれ nnxpid です。

Google ボーダー ルーター ネットワークの場合、Google Play 開発者サービスは、使用する Google Thread ネットワーク認証情報を自動的に取得します。

SDK を Android アプリに統合する

使用を開始するには、以下のステップを実行してください。

  1. Google Play 開発者サービスの設定の手順を実施します。

  2. Google Play 開発者サービスの依存関係を build.gradle ファイルに追加します。

    implementation 'com.google.android.gms:play-services-threadnetwork:16.0.0-beta01'
    
  3. 省略可: BorderAgent の data class を定義して、境界ルーターの情報を保存します。このガイドでは以下のデータを使用します。

    data class BorderAgentInfo(
      // Network Name max 16 len
      val networkName: String = "",
      val extPanId: ByteArray = ByteArray(16),
      val borderAgentId: ByteArray = ByteArray(16),
      ...
    )
    

次に、推奨される認証情報を追加および管理するための推奨手順を説明します。

新しいボーダー ルーターの設定

新しい境界ルーター用に新しいネットワークを作成する前に、優先ネットワーク認証情報を使用してみることが重要です。これにより、可能であれば Thread デバイスが単一の Thread ネットワークに接続されるようになります。

getPreferredCredentials を呼び出すとアクティビティが起動され、ユーザーにネットワーク リクエストを許可するように促します。ネットワーク認証情報が Thread SDK デジタル キーチェーンに保存されている場合、認証情報はアプリに返されます。

認証情報をリクエスト

優先される認証情報をユーザーに尋ねるには:

  1. ActivityLauncher を宣言します。

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. アクティビティの結果(ThreadNetworkCredentials として返される)を処理します。

    preferredCredentialsLauncher =
     registerForActivityResult(
       StartIntentSenderForResult()
     ) { result: ActivityResult ->
       if (result.resultCode == RESULT_OK) {
         val threadNetworkCredentials = ThreadNetworkCredentials.fromIntentSenderResultData(result.data!!)
         Log.d("debug", threadNetworkCredentials.networkName)
       } else {
         Log.d("debug", "User denied request.")
       }
     }
    
  3. preferredCredentials を呼び出して、アクティビティを起動します。

    private fun getPreferredThreadNetworkCredentials() {
      ThreadNetwork.getClient(this)
        .preferredCredentials
      .addOnSuccessListener { intentSenderResult ->
        intentSenderResult.intentSender?.let {
          preferredCredentialsLauncher.launch(IntentSenderRequest.Builder(it).build())
          } ?: Log.d("debug", "No preferred credentials found.")
        }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
    }
    

新しい Thread ネットワークを作成する

ユーザーの Thread ネットワーク内に適切な Thread ネットワーク認証情報がない場合は、addCredentials API を使用して Google Play 開発者サービスに認証情報を追加できます。そのためには、ThreadBorderAgent を作成し、ThreadNetworkCredentials オブジェクトも指定する必要があります。

ランダムなネットワークを作成するには、newRandomizeBuilder を呼び出します。

val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder().build()

Thread ネットワーク名を指定するには:

val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder()
  .setNetworkName("ThreadNetworkSDK")
  .build()

認証情報を追加

他の Thread ベンダーが Thread ネットワークの認証情報を利用できるようにするには、それらを Google Play 開発者サービスに追加する必要があります。新しい認証情報を追加する前に、この Thread ネットワークが属する境界ルーター デバイスも把握する必要があります。

この例では、Border Agent ID から ThreadBorderAgent を作成し、先ほど作成した新しい Thread ネットワーク認証情報を渡します。

private fun addCredentials(borderAgentInfo: BorderAgentInfo, credentialsToBeAdded: ThreadNetworkCredentials) {

  val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentInfo.borderAgentId).build()
  Log.d("debug", "border router id:" + threadBorderAgent.id)

  ThreadNetwork.getClient(this)
    .addCredentials(threadBorderAgent, credentialsToBeAdded)
      .addOnSuccessListener {
        Log.d("debug", "Credentials added.")
      }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

フィールド内ボーダー ルーターの検出と移行

現在、フィールド ボーダー ルーターを使用している場合、isPreferredCredentials を使用して、ボーダー ルーターが優先ネットワークに属しているかどうかを判断できます。この API では、ユーザーに権限を求めるプロンプトは表示されず、境界ルーターの認証情報が Google Play 開発者サービスに保存されている内容と照合されます。

isPreferredCredentails は、一致しない場合は 0 を、一致しない場合は 1Int データ型として返します。IsPreferredCredentialsResult を使用して結果を確認できます。

public @interface IsPreferredCredentialsResult {
    int PREFERRED_CREDENTIALS_NOT_FOUND = -1;
    int PREFERRED_CREDENTIALS_NOT_MATCHED = 0;
    int PREFERRED_CREDENTIALS_MATCHED = 1;
}

isPreferredCredentials を使用するには、まず ThreadNetworkCredentials オブジェクトを作成する必要があります。ThreadNetworkCredentials をインスタンス化するにはいくつかの方法があります。次のステップでは、これらのオプションについて説明します。

運用データセット別のスレッド ネットワーク認証情報

Thread Border Router がすでに Thread ネットワークで設定されており、この Thread ネットワークを Google Play 開発者サービスに追加して、他のベンダーと共有したい場合があります。未加工のスレッドのアクティブ オペレーション データセット TLV リストから、ThreadNetworkCredential インスタンスを作成できます。

  1. オペレーション データセットを ByteArray に変換します。次に例を示します。

    val activeDataset =
          "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
    
    fun String.dsToByteArray(): ByteArray {
      return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
    }
    
  2. fromActiveOperationalDataset を使用して ThreadNetworkCredentials を作成します。成功すると、Thread ネットワーク名、チャンネル、その他のネットワーク情報を取得できます。プロパティの一覧については、ThreadNetworkCredentials をご覧ください。

    val threadNetworkCredentials =
        ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset)
    Log.d(
        "threadNetworkCredentials",
        threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
    
  3. isPreferredCredentials API を呼び出して、ThreadNetworkCredentials を渡します。

    ThreadNetwork.getClient(this)
    .isPreferredCredentials(threadNetworkCredentials)
    .addOnSuccessListener { result ->
      when (result) {
        IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_NOT_MATCHED ->
            Log.d("isPreferredCredentials", "Credentials not matched.")
        IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_MATCHED ->
            Log.d("isPreferredCredentials", "Credentials matched.")
      }
    }
    .addOnFailureListener { e: Exception -> Log.d("isPreferredCredentials", "ERROR: [${e}]") }
    

Border Agent によるスレッド ネットワーク認証情報

Border Agent ID は、ボーダー ルーター デバイスを一意に識別するものです。getCredentialsByBorderAgent API を使用するには、まず ThreadBorderAgent オブジェクトを作成して Border Agent ID を渡す必要があります。

ThreadBorderAgent オブジェクトを作成したら、getCredentialsByBorderAgent を呼び出します。認証情報が保存されている場合は、認証情報が優先されるかどうかを確認します。

private fun isPreferredThreadNetworkByBorderAgent(borderAgentInfo: BorderAgentInfo) {

  val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentInfo.borderAgentId).build()
  Log.d("debug", "border router id:" + threadBorderAgent.id)

  var isPreferred = IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_NOT_FOUND
  var borderAgentCredentials: ThreadNetworkCredentials?
  val taskByBorderAgent = ThreadNetwork.getClient(this)
  taskByBorderAgent
      .getCredentialsByBorderAgent(threadBorderAgent)
      .addOnSuccessListener { result: ThreadNetworkCredentialsResult ->
        borderAgentCredentials = result.credentials
        result.credentials?.let {
          taskByBorderAgent.isPreferredCredentials(it).addOnSuccessListener { result ->
            isPreferred = result
          }
        }
      }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

拡張パン ID によるスレッド ネットワーク認証情報

getPreferredCredentials と同様に、境界ルーターの拡張認証情報でユーザーに認証情報を求めることもできます。getCredentialsByExtendedPanIdIntentSender を返し、ユーザーが承認すると Activity の結果には ThreadNetworkCredentials オブジェクトが含まれます。

private fun getCredentialsByExtPanId(borderAgentInfo: BorderAgentInfo) {
  ThreadNetwork.getClient(this)
    .getCredentialsByExtendedPanId(borderAgentInfo.extPanId)
    .addOnSuccessListener { intentSenderResult ->
      intentSenderResult.intentSender?.let {
        preferredCredentialsLauncher.launch(IntentSenderRequest.Builder(it).build())
      }
        ?: Log.d("debug", "No credentials found.")
    }
    .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

認証情報を削除する

Border Router デバイスを家または出荷時設定へのリセットから削除した場合は、Google Play 開発者サービスから Thread ネットワークを削除する必要があります。

private fun removeCredentials(borderAgentInfo: BorderAgentInfo) {

  val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentInfo.borderAgentId).build()
  Log.d("debug", "border router id:" + threadBorderAgent.id)

  ThreadNetwork.getClient(this)
      .removeCredentials(threadBorderAgent)
      .addOnSuccessListener { Log.d("debug", "Credentials removed.") }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

リソース

Thread Network SDK について詳しくは、API リファレンスをご覧ください。