SDK Thread Network for Android

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

Con poche chiamate API puoi:

  1. Richiedere le credenziali di rete preferite per Thread da Google Play Services.
  2. Configurare nuovi router di confine e aggiungere le credenziali di rete Thread a Google Play Services.
  3. Se hai già router di confine sul campo, puoi controllare se i tuoi router di confine si trovano nella rete preferita ed eseguirne la migrazione, se necessario.

Esistono diversi percorsi che gli utenti e gli sviluppatori possono prendere in considerazione. Li tratteremo in questa guida, insieme ad altre funzionalità chiave e al loro utilizzo consigliato.

Terminologia e concetti chiave delle API

Prima di iniziare, è utile comprendere i seguenti termini:

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

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

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

  • App Route Border Router: si tratta dell'app per Android che configura i nuovi dispositivi Thread Border Router e aggiunge le credenziali di rete Thread ai servizi Google Play. L'app è la proprietaria autorevole delle credenziali aggiunte e vi ha accesso.

Molte API di rete Thread restituiscono un'attività che viene completata in modo asincrono. Puoi utilizzare addOnSuccessSuccess e addOnFailureAscolta per registrare i callback per la ricezione del risultato. Per scoprire di più, consulta la documentazione di Task.

Proprietà e manutenzione delle credenziali

L'app che aggiunge le credenziali di rete Thread diventa il proprietario delle credenziali e dispone di autorizzazioni complete per accedervi. Se tenti di 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 archiviate in Google Play Services quando la rete del router di confine Thread viene aggiornata. Ciò significa aggiungere credenziali quando richiesto, aggiornarle quando cambiano le credenziali di rete Thread del router di confine e rimuovere le credenziali quando il router di confine Thread viene rimosso o vengono ripristinati i dati di fabbrica.

Rilevamento dell'agente di confine

Le credenziali devono essere salvate con un ID agente di frontiera. Devi assicurarti che l'app Configurazione del router di confine Thread sia in grado di determinare gli ID degli agenti di confine dei tuoi router di confine Thread.

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

Per le reti con router di confine Google, Google Play Services riceve automaticamente le credenziali di rete Google Thread per l'utilizzo.

Integra l'SDK nella tua app Android

Per iniziare, procedi come indicato di seguito:

  1. Segui le istruzioni fornite nella pagina Configurare Google Play Services.

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

    implementation 'com.google.android.gms:play-services-threadnetwork:16.0.0'
    
  3. Facoltativo: definisci una classe dati BorderAgent per archiviare le informazioni del router di confine. In questa guida, utilizzeremo i seguenti dati:

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

Quindi, vedremo i passaggi consigliati per aggiungere e gestire le credenziali preferite.

Configurazioni del nuovo router di confine

Prima di creare una nuova rete per i nuovi router di confine, è importante provare a utilizzare prima le credenziali di rete preferite. Ciò garantisce che, quando possibile, i dispositivi Thread siano connessi a una singola rete Thread.

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

Richiedi credenziali

Per chiedere all'utente le credenziali preferite:

  1. Dichiarare un ActivityLauncher:

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. Gestire il risultato 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. Chiama preferredCredentials e avvia l'attività:

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

Crea una nuova rete Thread

Se nella rete Thread dell'utente non sono disponibili le credenziali di rete Thread preferite, puoi utilizzare l'API addCredentials per aggiungere credenziali a Google Play Services. A questo scopo, 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 tue credenziali di rete Thread per altri fornitori di Thread, dovremo aggiungerle a Google Play Services. Prima di poter aggiungere le nostre nuove credenziali, dobbiamo sapere a quale dispositivo di router di confine appartiene questa rete Thread.

In questo esempio creeremo un ThreadBorderAgent da un ID agente di confine e passeremo 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}]") }
}

Rileva ed esegui la migrazione dei router di confine sul campo

Se al momento sono presenti router di confine sul campo, puoi utilizzare isPreferredCredentials per determinare se i router di confine appartengono alla rete preferita. Questa API non richiede all'utente l'autorizzazione e verifica che le credenziali del router di confine non siano archiviate in Google Play Services.

isPreferredCredentails restituisce 0 per i valori senza corrispondenza e 1 per i tipi di dati Int con corrispondenza. 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, vedremo queste opzioni.

Thread credenziali di rete per set di dati operativo

In alcuni casi, il router di confine Thread è già configurato con una rete Thread e vuoi aggiungerlo a Google Play Services per condividerlo con altri fornitori. Puoi creare un'istanza ThreadNetworkCredential da un elenco TLV di set di dati operativi Thread non elaborati:

  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 ha esito positivo, potrai recuperare il nome, il canale e altre informazioni di rete di Thread. 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 supera l'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}]") }
    

Eseguire il thread delle credenziali di rete in base all'agente di confine

Un ID agente di confine identifica in modo univoco un dispositivo router di confine. Per utilizzare l'API getCredentialsByBorderAgent, devi prima creare un oggetto ThreadBorderAgent e passare 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}]") }
}

Thread credenziali di rete per ID panoramica estesa

Analogamente a getPreferredCredentials, puoi richiedere all'utente le credenziali dall'ID Pan esteso del 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}]") }
}

Rimuovi credenziali

Quando il router di confine viene rimosso da casa tua o dal ripristino dei dati di fabbrica, devi rimuovere la 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 di rete Thread, consulta la pagina Riferimento API.