Thread Network SDK for Android

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

Thread Network SDK 提供與數位鑰匙圈相似的功能,讓 Android 應用程式與 Google Play 服務共用 Thread 網路憑證。這項功能可讓應用程式透過任何智慧住宅生態系統設定任何 Thread 裝置,而不必公開憑證和使用者資料。

只需幾個 API 呼叫,您就可以:

  1. 透過 Google Play 服務要求偏好的 Thread 網路憑證。
  2. 設定新的邊界路由器,並將 Thread 網路憑證新增至 Google Play 服務。
  3. 如果您已有現場邊界路由器,請檢查邊界路由器是否位於偏好的網路中,並視需要遷移。

要考慮幾個使用者和開發人員旅程。本指南將介紹大部分內容,以及其他重要功能和建議使用方法。

重要術語和 API 概念

在開始之前,建議您先瞭解下列字詞:

  • 執行緒網路憑證:執行緒 TLV 的二進位 blob,將執行緒網路名稱、網路金鑰和其他屬性編碼,藉此納入特定執行緒所需的網路。

  • 偏好的 Thread 網路憑證:自動選取的 Thread 網路憑證,可透過 getPreferredCredentials API 與不同供應商的應用程式共用。

  • 邊界代理程式 ID:用於 Thread Border 路由器裝置的 16 位元組全域 ID。這個 ID 是由邊界路由器供應商建立及管理。

  • Thread Border 路由器設定應用程式:這是指您的 Android 應用程式,會設定新的 Thread Border 路由器裝置,並將 Thread 網路憑證新增至 Google Play 服務。您的應用程式是新憑證的權威擁有者,且能免費存取憑證。

許多 Thread Network API 都會傳回以非同步方式完成的工作。您可以使用 addOnsuccessListeneraddOnFailureListener 註冊回呼,接收結果。詳情請參閱工作說明文件。

憑證擁有權與維護

新增 Thread 網路憑證的應用程式會成為憑證的擁有者,且具備憑證的完整權限。如果您嘗試存取其他應用程式新增的憑證,會收到 PERMISSION_DENIED 錯誤。

身為應用程式擁有者,建議您在 Thread Border 路由器網路更新時,將 Google Play 服務中儲存的憑證保持在最新狀態。這表示在需要時新增憑證,在邊界路由器和 #39; 執行緒網路憑證變更時更新憑證,並在移除執行緒邊界或恢復原廠設定時移除憑證。

邊界代理程式搜尋

憑證必須儲存在邊界代理程式 ID 中。您必須確保 Thread Border 路由器設定應用程式能夠判斷執行緒邊框路由器的邊界代理程式 ID。

執行緒邊界路由器必須使用 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-beta02'
    
  3. 選用:定義 BorderAgent 資料類別來儲存邊界路由器的資訊。我們會在本指南中使用這些資料:

    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 並啟用 Activity:

    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()

如何指定執行緒網路名稱:

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

新增憑證

若要讓其他 Thread 廠商使用 Thread 網路憑證,我們必須將這些憑證新增至 Google Play 服務。在新增憑證之前,我們還需要知道這個 Thread 網路所屬的邊界路由器裝置。

在這個範例中,我們會從邊界代理程式 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,如果是相符項目,則傳回 1,做為 Int 資料類型。您可以使用 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 邊界路由器已透過 Thread 網路進行設定,而您想將這個執行緒網路新增至 Google Play 服務,以便與其他供應商共用。您可以從原始的 Thread 作業資料集 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 代理程式的執行緒網路憑證

框線代理程式 ID 可識別邊界路由器裝置。如要使用 getCredentialsByBorderAgent API,您必須先建立 ThreadBorderAgent 物件並傳遞邊界代理程式 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}]") }
}

依據 Extended Pan ID 擴充的執行緒網路憑證

getPreferredCredentials 類似,您也可以提示使用者從邊界路由器和#39; Extended Pan ID 的憑證取得憑證。getCredentialsByExtendedPanId 會傳回 IntentSender,且當使用者核准時,活動結果包含 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 路由器裝置已從住家或恢復原廠設定的方式移除,您就必須從 Google Play 服務中移除 BThread 網路。

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 參考資料