O SDK da rede Thread oferece funcionalidades semelhantes a um chaveiro digital, permitindo que seus apps Android compartilhem credenciais da rede Thread com o Google Play Services. Isso permite que seus apps configurem qualquer dispositivo Thread de qualquer ecossistema de casa inteligente, sem expor credenciais e dados do usuário diretamente.
Com apenas algumas chamadas de API, você pode:
- Solicitar credenciais de rede Thread preferenciais do Google Play Services.
- Configurar novos Thread Border Router (TBR)s e adicionar as credenciais da rede Thread ao Google Play Services.
- Se você já tiver TBRs em campo, poderá verificar se seus TBRs estão na rede preferencial e migrá-los, se necessário.
Há várias jornadas de usuários e desenvolvedores a serem consideradas. Vamos abordar a maioria delas neste guia, além de outros recursos importantes e uso recomendado.
Terminologia e conceitos principais da API
Antes de começar, é útil entender os seguintes termos:
Credenciais da rede Thread:blob binário de TLVs do Thread que codifica o nome da rede Thread, a chave de rede e outras propriedades necessárias para que um dispositivo Thread entre em uma determinada rede Thread.
Credenciais de rede Thread preferenciais:as credenciais de rede Thread selecionadas automaticamente que podem ser compartilhadas com apps de diferentes fornecedores usando a API
getPreferredCredentials.ID do agente de borda: um ID globalmente exclusivo de 16 bytes para um TBR dispositivo. Esse ID é criado e gerenciado por border router fornecedores.
App de configuração do TBR:é o app Android que configura novos dispositivos TBR e adiciona as credenciais da rede Thread ao Google Play Services. Seu app é o proprietário autorizado das credenciais adicionadas e tem acesso a elas.
Muitas das APIs da rede Thread retornam uma tarefa que é concluída de forma assíncrona. Você pode usar addOnSuccessListener e addOnFailureListener para registrar callbacks para receber o resultado. Para saber mais, consulte a documentação da tarefa.
Propriedade e manutenção de credenciais
O app que adiciona as credenciais da rede Thread se torna o proprietário delas e tem permissões completas para acessá-las. Se você tentar acessar credenciais adicionadas por outros apps, vai receber um erro PERMISSION_DENIED.
Como proprietário do app, é recomendável manter as credenciais armazenadas no Google Play Services atualizadas quando a rede TBR for atualizada. Isso significa adicionar credenciais quando necessário, atualizar as credenciais quando as credenciais da rede Thread do border router mudarem e remover credenciais quando o TBR for removido ou redefinido para a configuração de fábrica.
Descoberta de agentes de borda
As credenciais precisam ser salvas com um ID de agente de borda. É necessário garantir que seu TBR app de configuração possa determinar os IDs de agente de borda de seus TBRs.
TBRs precisam usar o mDNS para anunciar informações da rede Thread,
incluindo o nome da rede, o ID Pan estendido e o ID do agente de borda. Os valores txt correspondentes para esses atributos são nn, xp e id, respectivamente.
Para redes com Google Thread Border Router (gTBR)s, o Google Play Services recebe automaticamente as credenciais da rede do Google Thread para uso.
Integrar o SDK ao seu app Android
Para começar, siga estas etapas:
Siga as instruções fornecidas em Configurar o Google Play Services.
Adicione a dependência do Google Play Services ao arquivo
build.gradle:implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'Opcional: defina uma classe de dados
BorderAgentpara armazenar TBR informações. Vamos usar esses dados neste guia:data class BorderAgentInfo( // Network Name max 16 len val networkName: String = "", val extPanId: ByteArray = ByteArray(16), val borderAgentId: ByteArray = ByteArray(16), ... )
Em seguida, vamos analisar as etapas recomendadas para adicionar e gerenciar credenciais preferenciais.
Novas configurações de roteador de borda do Thread
Antes de criar uma nova rede para novos roteadores de borda, é importante tentar usar as credenciais de rede preferenciais primeiro. Isso garante que os dispositivos Thread estejam conectados a uma única rede Thread quando possível.
Uma chamada para getPreferredCredentials inicia uma atividade, solicitando que os usuários permitam a solicitação de rede. Se as credenciais de rede tiverem sido armazenadas no chaveiro digital do SDK do Thread, elas serão retornadas ao seu app.
Solicitar credenciais
Para solicitar as credenciais preferenciais ao usuário:
Declare um
ActivityLauncher:private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>Processe o resultado da atividade, retornado 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.") } }Se você estiver configurando um novo TBR, é recomendável que você chame
preferredCredentialse inicie a atividade. Essa chamada garante que o novo TBR use as mesmas credenciais já armazenadas como preferenciais no smartphone, promovendo a convergência de diferentes TBRs para a mesma rede.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}]") } }Se o caso de uso estiver relacionado à configuração de dispositivos que não são TBRs, como um novo dispositivo final Matter-over-Thread, é recomendável usar a API
allActiveCredentialspara buscar credenciais. Essa chamada vai procurar TBRs encontrados na rede local e, portanto, não vai retornar credenciais que não estão disponíveis por um TBR 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 }
Criar uma nova rede Thread
Se não houver credenciais de rede Thread preferenciais nem credenciais de thread ativas disponíveis na rede Thread de um usuário, você poderá usar a API addCredentials para adicionar credenciais ao Google Play Services. Para fazer isso, você precisará criar um ThreadBorderAgent e também fornecer um objeto ThreadNetworkCredentials.
Para criar uma rede aleatória, chame o newRandomizeBuilder:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder().build()
Para especificar o nome da rede Thread:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder()
.setNetworkName("ThreadNetworkSDK")
.build()
Adicionar credenciais
Para disponibilizar as credenciais da rede Thread para outros fornecedores do Thread, precisamos adicioná-las ao Google Play Services. Antes de adicionar as novas credenciais, também precisamos saber a qual dispositivo TBR essa rede Thread pertence.
Neste exemplo, vamos criar um ThreadBorderAgent de um ID de agente de borda e transmitir as novas credenciais de rede Thread que você acabou de criar:
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}]") }
}
Detectar e migrar border routers em campo
Se você tiver border routers em campo, poderá usar
isPreferredCredentials para determinar se os border routers pertencem
à rede preferencial. Essa API não solicita permissão ao
usuário e verifica as border router credenciais em relação ao
que está armazenado no Google Play Services.
isPreferredCredentials retorna 0 para não correspondente e 1 para correspondente, como um tipo de dados Int. Você pode usar IsPreferredCredentialsResult para verificar os resultados.
public @interface IsPreferredCredentialsResult {
int PREFERRED_CREDENTIALS_NOT_FOUND = -1;
int PREFERRED_CREDENTIALS_NOT_MATCHED = 0;
int PREFERRED_CREDENTIALS_MATCHED = 1;
}
Para usar isPreferredCredentials, primeiro você precisa criar um objeto ThreadNetworkCredentials. Há várias maneiras de instanciar ThreadNetworkCredentials. Nas próximas etapas, vamos analisar essas opções.
Credenciais de rede Thread por conjunto de dados operacional
Há casos em que o TBR já está configurado com uma
rede Thread, e você quer adicionar essa rede Thread ao Google Play Services
para compartilhá-la com outros fornecedores. Você pode criar uma instância ThreadNetworkCredential de uma lista de TLVs de conjunto de dados operacional ativo do Thread bruto:
Converta o conjunto de dados operacional em um
ByteArray. Exemplo:val activeDataset = "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()fun String.dsToByteArray(): ByteArray { return chunked(2).map { it.toInt(16).toByte() }.toByteArray() }Use
fromActiveOperationalDatasetpara criar oThreadNetworkCredentials. Quando bem-sucedido, você poderá acessar o nome da rede Thread, o canal e outras informações da rede. Para uma lista completa de propriedades, consulte ThreadNetworkCredentials.val threadNetworkCredentials = ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset) Log.d( "threadNetworkCredentials", threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)Chame a API
isPreferredCredentialse transmita oThreadNetworkCredentials.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}]") }
Credenciais de rede Thread por agente de borda
Um ID de agente de borda identifica exclusivamente um dispositivo TBR. Para usar a API getCredentialsByBorderAgent, primeiro você precisa criar um objeto ThreadBorderAgent e transmitir o ID do agente de borda.
Depois de criar o objeto ThreadBorderAgent, chame getCredentialsByBorderAgent. Se as credenciais tiverem sido salvas, verifique se elas são preferenciais.
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}]") }
}
Credenciais de rede Thread por ID Pan estendido
Semelhante a getPreferredCredentials, você também pode solicitar as credenciais do usuário de um TBR's ID Pan estendido. O getCredentialsByExtendedPanId retorna um IntentSender, e o resultado da atividade contém um objeto ThreadNetworkCredentials quando o usuário aprova.
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}]") }
}
Remover credenciais
Quando o dispositivo border router é removido da sua casa ou redefinido para a configuração de fábrica, é necessário remover a rede Thread do 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}]") }
}
Recursos
Para saber mais sobre o SDK da rede Thread, consulte a referência da API.