SDK Thread Network per Android

L'SDK Thread Network fornisce funzionalità simili a quelle di un portachiavi digitale, consentendo alle tue app per Android di condividere le credenziali di rete Thread con Google Play Services. In questo modo le tue app possono configurare qualsiasi dispositivo Thread da in qualsiasi ecosistema per la 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 router di confine e aggiungi le credenziali della tua rete Thread a Google Play Services.
  3. Se disponi già di router di confine sul campo, puoi controllare se i router si trovano nella rete preferita ed eseguine la migrazione, se necessario.

Ci sono diversi percorsi utente e sviluppatore da prendere in considerazione. Ne illustreremo la maggior parte in questa guida, insieme ad altre funzionalità chiave e all'utilizzo consigliato.

Terminologia chiave e concetti delle API

Prima di iniziare, è utile comprendere i seguenti termini:

  • Credenziali di rete Thread: BLOB binario di TLV Thread che codificano Nome rete Thread, chiave di rete e altre proprietà richieste dal un dispositivo Thread per accedere a una determinata rete Thread.

  • Credenziali di rete Thread preferite:la rete Thread selezionata automaticamente. e credenziali che possono essere condivise con app di diversi fornitori utilizzando API getPreferredCredentials.

  • ID agente di confine:un ID univoco globale da 16 byte per un router di confine Thread dispositivo. Questo ID viene creato e gestito dai fornitori di router di confine.

  • App di configurazione del router di confine Thread: è la tua app per Android che configura i nuovi dispositivi router di confine Thread e aggiunge le credenziali di rete Thread a Google Play Services. La tua app è il proprietario autorevole dei contenuti aggiunti credenziali e che vi abbia accesso.

Molte delle API di rete Thread restituiscono un Attività che viene completata in modo asincrono. Puoi utilizzare addOnSuccessListener e addOnFailureListener per registrare i callback al fine di ricevere il risultato. Per saperne di più, consulta la documentazione di Task.

Proprietà e manutenzione delle credenziali

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

In qualità di proprietario dell'app, ti consigliamo di mantenere aggiornate le credenziali memorizzate in Google Play Services quando la rete del router di confine Thread viene aggiornata. Questo significa aggiungere credenziali quando sono necessarie, aggiornare le credenziali quando il confine le credenziali di rete Thread del router cambiano e rimuovono le credenziali quando Il router di confine Thread è stato rimosso o è stato ripristinato i dati di fabbrica.

Scoperta agente di frontiera

Le credenziali devono essere salvate con un ID agente di frontiera. Dovrai assicurarti l'app di configurazione del router di confine Thread è in grado di determinare gli ID agente di confine dei tuoi router di confine Thread.

i router di confine Thread devono utilizzare mDNS per pubblicizzare le informazioni di rete Thread, tra cui nome di rete, ID pan esteso e ID agente di confine. I valori txt corrispondenti per questi attributi sono nn, xp e id, rispettivamente.

Per le reti con router di confine Google, Google Play Services automaticamente ottiene le credenziali di rete Thread di Google da utilizzare.

Integrare l'SDK nell'app per Android

Per iniziare, completa i seguenti passaggi:

  1. Segui le istruzioni fornite all'indirizzo 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 sul router di confine. Utilizzeremo questi dati in tutta la guida:

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

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

Nuove configurazioni del router di confine

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

Viene avviata una chiamata al numero getPreferredCredentials un'attività, che chiede agli utenti di consentire la richiesta di rete. Se la rete sono state archiviate nel portachiavi digitale dell'SDK Thread, le credenziali vengono restituiti 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 router di confine Thread, ti consigliamo di chiamarepreferredCredentials e avviare l'attività. Questa chiamata garantisce che il nuovo router di confine Thread utilizzi le stesse credenziali già memorizzate come preferite nello smartphone, promuovendo la convergenza di diversi router di confine Thread alla 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 la allActiveCredentials per recuperare le credenziali. Questa chiamata cercherà i TBR trovati 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
    }
    

Creare una nuova rete Thread

Se non sono presenti credenziali di rete Thread preferite né thread attivo disponibili nella console Thread, quindi puoi usare l'API addCredentials per aggiungere le credenziali Google Play Services. Per farlo, dovrai creare un ThreadBorderAgent, e fornisce anche un oggetto ThreadNetworkCredentials.

Per creare una rete casuale, richiama 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 il nostro nuovo credenziali, dobbiamo anche sapere a quale router di confine è presente questo Thread a cui appartiene ogni singola rete.

In questo esempio, creeremo un ThreadBorderAgent da un ID agente di confine e imposteremo le nuove credenziali di rete Thread che hai appena creato:

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

Rilevare ed eseguire la migrazione dei router di confine sul campo

Se al momento disponi di router di confine sul campo, puoi usare isPreferredCredentials per determinare se i tuoi router di confine appartengono alla rete preferita. Questa API non richiede all'utente per richiedere l'autorizzazione e controlla le credenziali del router di confine in base a quanto archiviato in Google Play Services.

isPreferredCredentails restituisce 0 per le corrispondenze mancanti e 1 per quelle corrispondenti come tipo di dati Int. Puoi usare 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 prossimi passaggi, esamineremo queste opzioni.

Credenziali di rete Thread per set di dati operativo

In alcuni casi il router di confine Thread è già configurato con un Rete Thread e vuoi aggiungerla a Google Play Services per condividerlo con altri fornitori. Puoi creare un ThreadNetworkCredential istanza da un elenco non elaborato di set di dati operativo Thread attivo:

  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. Usa fromActiveOperationalDataset per creare ThreadNetworkCredentials. Se l'operazione ha esito positivo, potrai ottenere il nome, il canale e altre informazioni di 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 passa il valore 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 di Border Agent

Un ID agente di confine identifica in modo univoco un dispositivo router di confine. Per utilizzare l'API getCredentialsByBorderAgent, per prima cosa dovrai creare ThreadBorderAgent e passa l'ID agente di confine.

Dopo aver creato l'oggetto ThreadBorderAgent, chiama getCredentialsByBorderAgent. Se le credenziali sono state salvate, controlla se sono 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

Come per getPreferredCredentials, puoi anche chiedere all'utente di le credenziali dell'ID pan esteso di un router di confine. 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}]") }
}

Rimuovere le credenziali

Quando il router di confine viene rimosso da casa o hai ripristinato i dati di fabbrica, deve 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 all'API.