SDK de Thread Network para Android

El SDK de Thread Network proporciona una funcionalidad similar a un llavero digital, lo que permite que tus apps para Android compartan credenciales de red de Thread con los Servicios de Google Play. Esto permite que tus apps configuren cualquier dispositivo Thread desde cualquier ecosistema de casa inteligente, sin exponer credenciales ni datos del usuario directamente.

Con solo unas pocas llamadas a la API, puedes hacer lo siguiente:

  1. Solicita las credenciales preferidas de la red Thread a los Servicios de Google Play.
  2. Configura nuevos routers de borde y agrega las credenciales de tu red Thread a los servicios de Google Play.
  3. Si ya tienes routers de perímetro en el campo, puedes verificar si están en la red preferida y, si es necesario, migrarlos.

Hay varios recorridos de usuarios y desarrolladores que debes tener en cuenta. Abordaremos la mayoría de ellos en esta guía, junto con otras funciones clave y el uso recomendado.

Terminología clave y conceptos de la API

Antes de comenzar, es útil que entiendas los siguientes términos:

  • Credenciales de red de Thread: BLOB binario de TLV de Thread que codifica Thread Network Name, Network Key y otras propiedades requeridas por que un dispositivo Thread se una a una red de Thread determinada.

  • Credenciales de red Thread preferidas: Son las credenciales de red Thread seleccionadas automáticamente que se pueden compartir con apps de diferentes proveedores a través de la API de getPreferredCredentials.

  • ID del agente de frontera: Es un ID único global de 16 bytes para un router de borde de Thread. dispositivo. Los proveedores de routers de frontera crean y administran este ID.

  • App de configuración del router de borde Thread: Esta es tu app para Android que configura nuevos dispositivos de router de borde Thread y agrega las credenciales de la red Thread a los Servicios de Google Play. Tu app es el propietario autorizado de las credenciales agregadas y tiene acceso a ellas.

Muchas de las APIs de Thread Network muestran una Task que se completa de forma asíncrona. Puedes usar addOnSuccessListener y addOnFailureListener para registrar devoluciones de llamada para recibir el resultado. Para obtener más información, consulta la documentación de Task.

Propiedad y mantenimiento de las credenciales

La app que agrega las credenciales de red de Thread se convierte en la propietaria de la credenciales y tiene permisos completos para acceder a ellas. Si intentas para acceder a las credenciales que agregaron otras apps, recibirás una PERMISSION_DENIED .

Como propietario de la app, te recomendamos que mantengas actualizadas las credenciales almacenadas en los Servicios de Google Play cuando se actualice la red del router de borde de Thread. Esta significa agregar credenciales cuando sea necesario, actualizarlas cuando se establezca cuando las credenciales de red Thread del router cambian y se quitan Se quitó el router de borde Thread o se restableció su configuración de fábrica.

Descubrimiento del agente de frontera

Las credenciales se deben guardar con un ID de agente de frontera. Deberás asegurarte de que la app de configuración del router de borde Thread pueda determinar los IDs de los agentes de borde de tus routers de borde Thread.

Los routers de borde de Thread deben usar mDNS para anunciar la información de red de Thread. incluidos el nombre de la red, el ID de pano extendido y el ID del agente de frontera. Los valores txt correspondientes para estos atributos son nn, xp y id, respectivamente.

Para redes con routers de borde de Google, los Servicios de Google Play obtiene las credenciales de red de Thread de Google para usarlas.

Integra el SDK en tu app para Android

Para comenzar, completa los siguientes pasos:

  1. Sigue las instrucciones que se indican en Configura los Servicios de Google Play.

  2. Agrega la dependencia de los Servicios de Google Play a tu archivo build.gradle:

    implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'
    
  3. Opcional: Define una clase de datos BorderAgent para almacenar información del router de borde. Usaremos estos datos a lo largo de esta guía:

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

A continuación, veremos los pasos recomendados para agregar y administrar las credenciales preferidas.

Nuevas configuraciones de router de borde

Antes de crear una red nueva para routers de borde nuevos, es importante intenta usar primero las credenciales de red preferidas. Esto garantiza que Los dispositivos Thread se conectan a una sola red de Thread cuando es posible.

Una llamada a getPreferredCredentials inicia una actividad y les solicita a los usuarios que permitan la solicitud de red. Si las credenciales de red se almacenaron en el llavero digital del SDK de Thread, las credenciales se devuelven a tu app.

Solicita credenciales

Para solicitarle al usuario las credenciales preferidas, haz lo siguiente:

  1. Declara un ActivityLauncher:

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. Controla el resultado de la actividad, que se muestra como 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. Si configuras un nuevo router de borde de Thread, te recomendamos que llames a preferredCredentials y que inicies la actividad. Esta llamada garantizará que tu nuevo router de borde Thread usará las mismas credenciales ya almacenadas como preferido en la llamada telefónica, lo que promueve la convergencia de diferentes TBR a la misma red.

    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. Si tu caso de uso se relaciona con la configuración de dispositivos que no son TBR, como un nuevo Matter-over-Thread, te recomendamos que uses allActiveCredentials para recuperar credenciales. Esta llamada buscará TBR en la red local y, por lo tanto, no mostrará credenciales que no estén disponibles en un TBR existente de forma local.

    // 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 red de Thread nueva

Si no hay credenciales de red preferidas ni subprocesos activos credenciales disponibles en la cuenta Thread, puedes usar la API de addCredentials para agregar credenciales a Servicios de Google Play. Para ello, deberás crear un ThreadBorderAgent y, también, proporcionar un objeto ThreadNetworkCredentials.

Para crear una red aleatoria, llama a newRandomizeBuilder:

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

Sigue estos pasos para especificar el nombre de la red de Thread:

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

Agregar credenciales

Para que tus credenciales de red de Thread estén disponibles para otros proveedores de esta plataforma, sigue estos pasos: necesitamos agregarlas a los Servicios de Google Play. Antes de agregar nuestras credenciales nuevas, también debemos saber a qué dispositivo de router de borde pertenece esta red Thread.

En este ejemplo, crearemos un ThreadBorderAgent a partir de un ID de agente de frontera. pasa las nuevas credenciales de red de Thread que acabas de crear:

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

Detecta y migra routers de borde de campo

Si actualmente tienes routers de borde de campo, puedes usar isPreferredCredentials para determinar si pertenecen a la red preferida. Esta API no le solicita permiso al usuario y verifica las credenciales del router de borde con lo que se almacena en los Servicios de Google Play.

isPreferredCredentails muestra 0 para los campos no coincidentes y 1 para coincide, como un tipo de datos Int. Puedes usar IsPreferredCredentialsResult para verificar los resultados.

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

Para usar isPreferredCredentials, primero deberás crear un objeto ThreadNetworkCredentials. Hay varias formas de crear una instancia de ThreadNetworkCredentials. En los próximos pasos, analizaremos estas opciones.

Credenciales de red de subprocesos por conjunto de datos operativo

En algunos casos, es posible que tu router de borde Thread ya esté configurado con una red de Thread y que quieras agregarla a los Servicios de Google Play para compartirla con otros proveedores. Puedes crear una instancia de ThreadNetworkCredential a partir de una lista de TLV de conjunto de datos de operaciones activas de Thread sin procesar:

  1. Convierte el conjunto de datos operativo en una ByteArray. Por ejemplo:

    val activeDataset =
          "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
    
    fun String.dsToByteArray(): ByteArray {
      return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
    }
    
  2. Usa fromActiveOperationalDataset para crear el ThreadNetworkCredentials. Si se realiza correctamente, podrás obtener el nombre, el canal y otra información de la red Thread. Para obtener una lista completa de las propiedades, consulta ThreadNetworkCredentials.

    val threadNetworkCredentials =
        ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset)
    Log.d(
        "threadNetworkCredentials",
        threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
    
  3. Llama a la API de isPreferredCredentials y pasa el 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}]") }
    

Credenciales de red de Thread por agente de borde

El ID de agente de frontera identifica de forma exclusiva un dispositivo router de borde. Para usar la API de getCredentialsByBorderAgent, primero deberás crear un objeto ThreadBorderAgent y pasar el ID del agente de frontera.

Una vez que hayas creado el objeto ThreadBorderAgent, llama getCredentialsByBorderAgent Si se guardaron las credenciales, verifica si son las preferidas.

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

Credenciales de red de Thread por ID de barrido extendido

Al igual que con getPreferredCredentials, también puedes solicitarle al usuario credenciales del ID de Pan extendido de un router de borde. El getCredentialsByExtendedPanId muestra un IntentSender, y el resultado de la actividad contiene un objeto ThreadNetworkCredentials cuando el usuario lo aprueba.

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

Quitar credenciales

Cuando quitas el router de borde de tu casa o restableces la configuración de fábrica, puedes debes quitar su red Thread de los Servicios de 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}]") }
}

Recursos

Si quieres obtener más información sobre el SDK de Thread Network, consulta la referencia de la API.