SDK Thread Network pour Android

Le SDK Thread Network fournit des fonctionnalités semblables à celles d'un porte-clés numérique, ce qui permet à vos applications Android de partager les identifiants du réseau Thread avec les services Google Play. Vos applications peuvent ainsi configurer n'importe quel appareil Thread à partir de n'importe quel écosystème de maison connectée, sans exposer directement les identifiants et les données utilisateur.

En quelques appels d'API, vous pouvez :

  1. demander les identifiants de réseau Thread préférés aux services Google Play ;
  2. configurer de nouveaux Thread Border Router (TBR) et ajouter les identifiants de votre réseau Thread aux services Google Play ;
  3. si vous disposez déjà de TBR sur le terrain, vous pouvez vérifier si vos TBR se trouvent sur le réseau préféré et les migrer, si nécessaire.

Plusieurs parcours utilisateur et développeur sont à prendre en compte. Nous aborderons la plupart d'entre eux dans ce guide, ainsi que d'autres fonctionnalités clés et utilisations recommandées.

Terminologie clé et concepts d'API

Avant de commencer, il est utile de comprendre les termes suivants :

  • Identifiants du réseau Thread : blob binaire de TLV Thread qui encode le nom du réseau Thread, la clé réseau et d'autres propriétés requises par un appareil Thread pour rejoindre un réseau Thread donné.

  • Identifiants de réseau Thread préférés : identifiants de réseau Thread sélectionnés automatiquement qui peuvent être partagés avec des applications de différents fournisseurs à l'aide de l'API getPreferredCredentials.

  • ID d'agent de bordure : ID unique global de 16 octets pour un TBR appareil. Cet ID est créé et géré par les fournisseurs border router.

  • TBR application de configuration : application Android qui configure de nouveaux appareils TBR et ajoute les identifiants du réseau Thread aux services Google Play. Votre application est le propriétaire faisant autorité des identifiants ajoutés et y a accès.

De nombreuses API Thread Network renvoient une tâche qui s'exécute de manière asynchrone. Vous pouvez utiliser addOnSuccessListener et addOnFailureListener pour enregistrer des rappels afin de recevoir le résultat. Pour en savoir plus, consultez la documentation sur les tâches.

Propriété et maintenance des identifiants

L'application qui ajoute les identifiants du réseau Thread en devient le propriétaire et dispose de toutes les autorisations pour y accéder. Si vous tentez d'accéder à des identifiants ajoutés par d'autres applications, vous recevrez une erreur PERMISSION_DENIED.

En tant que propriétaire de l'application, il est recommandé de maintenir à jour les identifiants stockés dans les services Google Play lorsque le TBR réseau est mis à jour. Cela signifie ajouter des identifiants lorsque cela est nécessaire, les mettre à jour lorsque les border router identifiants du réseau Thread changent et supprimer les identifiants lorsque le TBR est supprimé ou réinitialisé aux paramètres d'usine.

Découverte de l'agent de bordure

Les identifiants doivent être enregistrés avec un ID d'agent de bordure. Vous devez vous assurer que votre TBR application de configuration est en mesure de déterminer les ID d'agent de bordure de vos TBRs.

TBRs doivent utiliser mDNS pour annoncer les informations du réseau Thread, y compris le nom du réseau, l'ID PAN étendu et l'ID d'agent de bordure. Les valeurs txt correspondantes pour ces attributs sont respectivement nn, xp et id.

Pour les réseaux avec des Google Thread Border Router (gTBR)s, les services Google Play obtiennent automatiquement les identifiants du réseau Thread Google à utiliser.

Intégrer le SDK à votre application Android

Pour commencer, procédez comme suit :

  1. Suivez les instructions fournies dans Configurer les services Google Play.

  2. Ajoutez la dépendance des services Google Play à votre fichier build.gradle :

    implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'
    
  3. Facultatif : Définissez une classe de données BorderAgent pour stocker TBR informations. Nous utiliserons ces données tout au long de ce guide :

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

Nous allons maintenant passer en revue les étapes recommandées pour ajouter et gérer les identifiants préférés.

Nouvelles configurations de routeur de bordure Thread

Avant de créer un réseau pour de nouveaux routeurs de bordure, il est important d'essayer d'abord d'utiliser les identifiants de réseau préférés. Cela permet de s'assurer que les appareils Thread sont connectés à un seul réseau Thread lorsque cela est possible.

Un appel à getPreferredCredentials lance une activité, invitant les utilisateurs à autoriser la requête réseau. Si des identifiants réseau ont été stockés dans le porte-clés numérique du SDK Thread, ils sont renvoyés à votre application.

Demander des identifiants

Pour inviter l'utilisateur à fournir des identifiants préférés :

  1. Déclarez un ActivityLauncher :

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. Gérez le résultat de l'activité, renvoyé sous la forme 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 vous configurez un nouveau TBR, il est conseillé d' appeler preferredCredentials et de lancer l'activité. Cet appel garantit que votre nouveau TBR utilisera les mêmes identifiants déjà stockés comme préférés dans le téléphone, ce qui favorisera la convergence de différents TBR vers le même réseau.

    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 votre cas d'utilisation concerne la configuration d'appareils non TBR, tels qu'un nouvel appareil final Matter-over-Thread, il est conseillé d'utiliser l'API allActiveCredentials pour récupérer les identifiants. Cet appel recherchera les TBR trouvés dans le réseau local et ne renverra donc pas les identifiants qui ne sont pas disponibles localement par un TBR existant.

    // 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
    }
    

Créer un réseau Thread

Si aucun identifiant de réseau Thread préféré ni aucun identifiant de thread actif n'est disponible dans le réseau Thread d'un utilisateur, vous pouvez utiliser l'API addCredentials pour ajouter des identifiants aux services Google Play. Pour ce faire, vous devez créer un ThreadBorderAgent et fournir un objet ThreadNetworkCredentials.

Pour créer un réseau aléatoire, appelez newRandomizeBuilder :

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

Pour spécifier le nom du réseau Thread :

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

Ajouter des identifiants

Pour que les identifiants de votre réseau Thread soient disponibles pour d'autres fournisseurs Thread, nous devons les ajouter aux services Google Play. Avant de pouvoir ajouter nos nouveaux identifiants, nous devons également savoir à quel TBR appareil appartient ce réseau Thread.

Dans cet exemple, nous allons créer un ThreadBorderAgent à partir d'un ID d'agent de bordure et transmettre les nouveaux identifiants de réseau Thread que vous venez de créer :

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

Détecter et migrer les border router sur le terrain

Si vous disposez de border routers sur le terrain, vous pouvez utiliser isPreferredCredentials pour déterminer si vos border routers appartiennent au réseau préféré. Cette API n'invite pas l'utilisateur à demander l'autorisation et vérifie border router les identifiants par rapport à ce qui est stocké dans les services Google Play.

isPreferredCredentials renvoie 0 en cas de non-correspondance et 1 en cas de correspondance, en tant que type de données Int. Vous pouvez utiliser IsPreferredCredentialsResult pour vérifier vos résultats.

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

Pour utiliser isPreferredCredentials, vous devez d'abord créer un objet ThreadNetworkCredentials. Il existe plusieurs façons d'instancier ThreadNetworkCredentials. Dans les étapes suivantes, nous allons passer en revue ces options.

Identifiants de réseau Thread par ensemble de données opérationnel

Dans certains cas, votre TBR est déjà configuré avec un réseau Thread, et vous souhaitez ajouter ce réseau Thread aux services Google Play pour le partager avec d'autres fournisseurs. Vous pouvez créer une instance ThreadNetworkCredential à partir d'une liste TLV d'ensemble de données opérationnel actif Thread brut :

  1. Convertissez l'ensemble de données opérationnel en ByteArray. Exemple :

    val activeDataset =
          "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
    
    fun String.dsToByteArray(): ByteArray {
      return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
    }
    
  2. Utilisez fromActiveOperationalDataset pour créer le ThreadNetworkCredentials. En cas de réussite, vous pourrez obtenir le nom du réseau Thread, le canal et d'autres informations sur le réseau. Pour obtenir la liste complète des propriétés, consultez ThreadNetworkCredentials.

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

Identifiants de réseau Thread par agent de bordure

Un ID d'agent de bordure identifie de manière unique un appareil TBR. Pour utiliser l'API getCredentialsByBorderAgent, vous devez d'abord créer un objet ThreadBorderAgent et transmettre l'ID d'agent de bordure.

Une fois l'objet ThreadBorderAgent créé, appelez getCredentialsByBorderAgent. Si les identifiants ont été enregistrés, vérifiez s'ils sont préférés.

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

Identifiants de réseau Thread par ID PAN étendu

Comme pour getPreferredCredentials, vous pouvez également inviter l'utilisateur à fournir des identifiants à partir de TBR's ID PAN étendu. getCredentialsByExtendedPanId renvoie un IntentSender, et le résultat de l'activité contient un objet ThreadNetworkCredentials lorsque l'utilisateur approuve.

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

Supprimer les identifiants

Lorsque votre appareil border router est retiré de votre domicile ou réinitialisé aux paramètres d'usine, vous devez supprimer son réseau Thread des services 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}]") }
}

Ressources

Pour en savoir plus sur le SDK Thread Network, consultez la documentation de référence de l'API.