Android 適用的 Thread Network SDK

Thread Network SDK 提供與 金鑰鏈,允許 Android 應用程式共用 Thread 網路憑證 Google Play 服務。這樣一來,應用程式就能在以下位置設定任何 Thread 裝置: 任何智慧型住宅生態系統,而不必直接揭露憑證和使用者資料。

只要支付幾個 API 呼叫,您就可以:

  1. 向 Google Play 服務要求偏好的 Thread 網路憑證。
  2. 設定新的邊界路由器,並將 Thread 網路憑證新增至 Google Play 服務。
  3. 如果已有內邊界路由器,可以按照下列步驟查看邊界 且路由器位於偏好的網路中,並視需要遷移。

這裡有幾個使用者和開發人員歷程需要列入考量。這部影片將介紹 。

重要術語和 API 概念

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

  • Thread Network Credentials:編碼的 Thread TLV 二進位檔 blob 執行緒網路名稱、網路金鑰和其他屬性 用來加入指定 Thread 網路的 Thread 裝置。

  • 偏好的 Thread 網路憑證:自動選取的 Thread 網路 憑證能分享給不同供應商的應用程式 getPreferredCredentials API。

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

  • Thread 邊界路由器設定應用程式:這是要設定 新的 Thread 邊界路由器裝置,並將 Thread 網路憑證新增至 Google Play 服務。您的應用程式是新增下列項目的權威擁有者: 憑證並可存取

許多 Thread 網路 API 都會傳回 工作 非同步作業別擔心!您可以使用 addOnSuccessListeneraddOnFailureListener 註冊回呼以接收結果。詳情請參閱 工作 說明文件。

憑證擁有權和維護

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

如果您是應用程式擁有者,建議將憑證儲存在 Google Thread 邊界路由器網路更新時,Google Play 服務是最新版本。這個 也就是在需要時新增憑證,在邊框更新時更新憑證 路由器的 Thread 網路憑證變更,並在 Thread 邊界路由器已移除或恢復原廠設定。

探索邊界代理程式

憑證必須以邊框代理商 ID 儲存。請先確認 Thread 邊界路由器設定應用程式能夠判斷邊界代理程式 ID 以及 Thread 邊界路由器

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'
    
  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. 處理 Activity 結果,並以 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()

如何指定 Thread 網路名稱:

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 網路,且您想將這個 Thread 網路新增至 Google Play 服務 以便與其他供應商分享您可以建立ThreadNetworkCredential 執行個體,來自原始執行緒運作中的作業資料集 TLV 清單:

  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 分組網路憑證

邊界代理程式 ID 專門用來識別邊界路由器裝置。使用條件 getCredentialsByBorderAgent API,您必須先建立 ThreadBorderAgent 物件並傳遞邊框代理程式 ID。

建立 ThreadBorderAgent 物件後,請呼叫 getCredentialsByBorderAgent。如果憑證已儲存,請檢查 在 Kubernetes 中

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 類似,您也可以提示使用者 來自邊界路由器的擴充平移 ID getCredentialsByExtendedPanId 會傳回 IntentSender,而 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}]") }
}

移除憑證

從住家中移除邊界路由器或恢復原廠設定後, ,以便將 Thread 網路從 Google Play 服務中移除。

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