SDK Thread Network per Android

L'SDK Thread Network fornisce funzionalità simili a un portachiavi digitale, consentendo alle tue app per Android di condividere le credenziali della rete Thread con Google Play Services. In questo modo, le tue app possono configurare qualsiasi dispositivo Thread da qualsiasi ecosistema di smart home, senza esporre direttamente le credenziali e i dati utente.

Con poche chiamate API, puoi:

  1. Richiedi le credenziali di rete Thread preferite da Google Play Services.
  2. Configura nuovi Thread Border Router (TBR) e aggiungi le credenziali della tua rete Thread a Google Play Services.
  3. Se hai già TBR in campo, puoi verificare se i tuoi TBR si trovano nella rete preferita ed eseguire la migrazione, se necessario.

Esistono diversi percorsi utente e sviluppatore da considerare. In questa guida ne illustreremo la maggior parte, insieme ad altre funzionalità chiave e all'utilizzo consigliato.

Terminologia chiave e concetti relativi alle API

Prima di iniziare, è utile comprendere i seguenti termini:

  • Credenziali di rete Thread:blob binario di TLV Thread che codifica il nome della rete Thread, la chiave di rete e altre proprietà richieste da un dispositivo Thread per accedere a una determinata rete Thread.

  • Credenziali di rete Thread preferite:le credenziali di rete Thread selezionate automaticamente che possono essere condivise con app di diversi fornitori utilizzando l'API getPreferredCredentials.

  • ID Border Agent:un ID univoco a livello globale di 16 byte per un dispositivo TBR. Questo ID viene creato e gestito da border router fornitori.

  • App di configurazione TBR:si tratta della tua app per Android che configura i nuovi dispositivi TBR e aggiunge le credenziali della rete Thread a Google Play Services. La tua app è il proprietario autorizzato delle credenziali aggiunte e ha accesso a queste ultime.

Molte API Thread Network restituiscono un Task che viene completato in modo asincrono. Puoi utilizzare addOnSuccessListener e addOnFailureListener per registrare i callback per la ricezione del risultato. Per saperne di più, consulta la documentazione relativa alle attività.

Proprietà e manutenzione delle credenziali

L'app che aggiunge le credenziali della rete Thread diventa proprietaria delle credenziali e dispone di autorizzazioni complete per accedervi. Se provi ad accedere alle credenziali aggiunte da altre app, riceverai un errore PERMISSION_DENIED.

In qualità di proprietario dell'app, ti consigliamo di mantenere aggiornate le credenziali memorizzate in Google Play Services quando la rete TBR viene aggiornata. Ciò significa aggiungere le credenziali quando richiesto, aggiornarle quando cambiano le credenziali della rete Thread di border router e rimuoverle quando TBR viene rimosso o quando vengono ripristinati i dati di fabbrica.

Rilevamento degli agenti di confine

Le credenziali devono essere salvate con un ID Border Agent. Dovrai assicurarti che l'app di configurazione di TBR sia in grado di determinare gli ID Border Agent dei tuoi TBR.

I TBR devono utilizzare mDNS per annunciare le informazioni sulla rete Thread, tra cui il nome della rete, l'ID PAN esteso e l'ID Border Agent. I valori txt corrispondenti per questi attributi sono rispettivamente nn, xp e id.

Per le reti con Google Thread Border Router (gTBR), Google Play Services riceve automaticamente le credenziali della rete Google Thread da utilizzare.

Integra l'SDK nell'app per Android

Per iniziare, completa i seguenti passaggi:

  1. Segui le istruzioni fornite in Configura Google Play Services.

  2. Aggiungi la dipendenza di Google Play Services al file build.gradle:

    implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'
    
  3. (Facoltativo) Definisci una classe di dati BorderAgent per archiviare le informazioni di TBR. Utilizzeremo questi dati in tutta questa guida:

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

Successivamente, esamineremo i passaggi consigliati per aggiungere e gestire le credenziali preferite.

Nuove configurazioni di Thread border router

Prima di creare una nuova rete per i nuovi router di confine, è importante provare a utilizzare prima le credenziali della rete preferita. In questo modo, i dispositivi Thread vengono connessi a una singola rete Thread, se possibile.

Una chiamata a getPreferredCredentials avvia un'attività, chiedendo agli utenti di consentire la richiesta di rete. Se le credenziali di rete sono state memorizzate nel portachiavi digitale dell'SDK Thread, vengono restituite alla tua app.

Richiedi credenziali

Per chiedere all'utente le credenziali preferite:

  1. Dichiara un ActivityLauncher:

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. Gestisci il risultato dell'attività, restituito come 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. Se stai configurando un nuovo TBR, ti consigliamo di chiamare preferredCredentials e lanciare l'attività. Questa chiamata garantirà che il nuovo TBR utilizzi le stesse credenziali già memorizzate come preferite nello smartphone, promuovendo la convergenza di diversi TBR sulla stessa rete.

    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}]") }
    }
    
  4. Se il tuo caso d'uso riguarda la configurazione di dispositivi non TBR, ad esempio un nuovo dispositivo finale Matter-over-Thread, ti consigliamo di utilizzare l'API allActiveCredentials per recuperare le credenziali. Questa chiamata cercherà i TBR presenti nella rete locale e, di conseguenza, non restituirà le credenziali non disponibili localmente da un TBR esistente.

    // Creates the IntentSender result launcher for the getAllActiveCredentials API
    private val getAllActiveCredentialsLauncher =
      registerForActivityResult(
        StartIntentSenderForResult()
      ) { result: ActivityResult ->
        if (result.resultCode == RESULT_OK) {
          val activeCredentials: List<ThreadNetworkCredentials> =
            ThreadNetworkCredentials.parseListFromIntentSenderResultData(
              result.data!!
            )
          // Use the activeCredentials list
        } else {
          // The user denied to share!
        }
      }
    
    // Invokes the getAllActiveCredentials API and starts the dialog activity with the returned
    // IntentSender
    threadNetworkClient
    .getAllActiveCredentials()
    .addOnSuccessListener { intentSenderResult: IntentSenderResult ->
      val intentSender = intentSenderResult.intentSender
      if (intentSender != null) {
        getAllActiveCredentialsLauncher.launch(
          IntentSenderRequest.Builder(intentSender).build()
        )
      } else {
        // No active network credentials found!
      }
    }
    // Handles the failure
    .addOnFailureListener { e: Exception ->
      // Handle the exception
    }
    

Crea una nuova rete Thread

Se nella rete Thread di un utente non sono disponibili credenziali di rete Thread preferite né credenziali Thread attive, puoi utilizzare l'API addCredentials per aggiungere credenziali a Google Play Services. Per farlo, devi creare un ThreadBorderAgent e fornire anche un oggetto ThreadNetworkCredentials.

Per creare una rete casuale, chiama newRandomizeBuilder:

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

Per specificare il nome della rete Thread:

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

Aggiungi credenziali

Per rendere disponibili le credenziali della tua rete Thread per altri fornitori Thread, dobbiamo aggiungerle a Google Play Services. Prima di poter aggiungere le nuove credenziali, dobbiamo anche sapere a quale dispositivo TBR appartiene questa rete Thread.

In questo esempio, creeremo un ThreadBorderAgent da un ID Border Agent e passeremo le nuove credenziali della rete Thread appena create:

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}]") }
}

Rileva ed esegui la migrazione dei border router in campo

Se hai border router sul campo, puoi utilizzare isPreferredCredentials per determinare se i tuoi border router appartengono alla rete preferita. Questa API non richiede l'autorizzazione all'utente e controlla le credenziali border router rispetto a quelle memorizzate in Google Play Services.

isPreferredCredentials restituisce 0 per i valori non corrispondenti e 1 per i valori corrispondenti, come tipo di dati Int. Puoi utilizzare IsPreferredCredentialsResult per controllare i risultati.

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

Per utilizzare isPreferredCredentials, devi prima creare un oggetto ThreadNetworkCredentials. Esistono diversi modi per creare un'istanza di ThreadNetworkCredentials. Nei passaggi successivi, esamineremo queste opzioni.

Credenziali di rete Thread per set di dati operativi

In alcuni casi, TBR è già configurato con una rete Thread e vuoi aggiungere questa rete Thread a Google Play Services per condividerla con altri fornitori. Puoi creare un'istanza ThreadNetworkCredential da un elenco TLV di set di dati operativi attivi Thread non elaborato:

  1. Converti il set di dati operativo in un ByteArray. Ad esempio:

    val activeDataset =
          "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
    
    fun String.dsToByteArray(): ByteArray {
      return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
    }
    
  2. Utilizza fromActiveOperationalDataset per creare ThreadNetworkCredentials. Se l'operazione va a buon fine, potrai ottenere il nome della rete Thread, il canale e altre informazioni sulla rete. Per un elenco completo delle proprietà, consulta ThreadNetworkCredentials.

    val threadNetworkCredentials =
        ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset)
    Log.d(
        "threadNetworkCredentials",
        threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
    
  3. Chiama l'API isPreferredCredentials e trasmetti 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}]") }
    

Credenziali di rete Thread per Border Agent

Un ID Border Agent identifica in modo univoco un dispositivo TBR. Per utilizzare l'API getCredentialsByBorderAgent, devi prima creare un oggetto ThreadBorderAgent e passare l'ID Border Agent.

Dopo aver creato l'oggetto ThreadBorderAgent, chiama getCredentialsByBorderAgent. Se le credenziali sono state salvate, controlla se sono quelle preferite.

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}]") }
}

Credenziali di rete Thread per ID PAN esteso

Analogamente a getPreferredCredentials, puoi anche chiedere all'utente le credenziali da un ID PAN esteso di TBR. getCredentialsByExtendedPanId restituisce un IntentSender e il risultato dell'attività contiene un oggetto ThreadNetworkCredentials quando l'utente approva.

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}]") }
}

Rimuovi credenziali

Quando il dispositivo border router viene rimosso dalla casa o vengono ripristinati i dati di fabbrica, devi rimuovere la relativa rete Thread da Google Play Services.

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}]") }
}

Risorse

Per scoprire di più sull'SDK Thread Network, consulta il Riferimento API.