O SDK da rede Thread oferece uma funcionalidade semelhante a um chaveiro digital, permitindo que seus apps Android compartilhem credenciais de rede Thread com o Google Play Services. Isso permite que seus apps configurem qualquer dispositivo Thread de qualquer ecossistema de casa inteligente, sem expor diretamente credenciais e dados do usuário.
Com apenas algumas chamadas de API, é possível:
- Solicite as credenciais de rede Thread preferenciais do Google Play Services.
- Configure novos Thread Border Router (TBR)s e adicione suas credenciais de rede Thread ao Google Play Services.
- Se você já tiver TBRs em campo, verifique se eles estão na rede preferencial e migre-os, se necessário.TBR
Há várias jornadas de usuários e desenvolvedores a serem consideradas. Vamos abordar a maioria deles neste guia, além de outros recursos importantes e o uso recomendado.
Terminologia principal e conceitos de API
Antes de começar, é útil entender os seguintes termos:
Credenciais de 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 exclusivo globalmente de 16 bytes para um dispositivo TBR. Esse ID é criado e gerenciado por fornecedores do border router.
App de configuração do TBR:é o app Android que configura novos dispositivos TBR e adiciona as credenciais de rede Thread ao Google Play Services. Seu app é o proprietário oficial das credenciais adicionadas e tem acesso a elas.
Muitas das APIs Thread Network retornam uma Task que é concluída de forma assíncrona. É possível usar addOnSuccessListener e addOnFailureListener para registrar callbacks para receber o resultado. Para saber mais, consulte a documentação de tarefas.
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 totais de acesso. Se você tentar
acessar credenciais adicionadas por outros apps, vai receber um erro
PERMISSION_DENIED.
Como proprietário do app, recomendamos que você mantenha o armazenamento de credenciais armazenado no Google Play Services atualizado quando a rede TBR for atualizada. Isso significa adicionar credenciais quando necessário, atualizar credenciais quando as credenciais de rede Thread do border router mudarem e remover credenciais quando o TBR for removido ou redefinido de fábrica.
Descoberta de agentes de borda
As credenciais precisam ser salvas com um ID de agente de borda. Verifique se o app de configuração do TBR consegue determinar os IDs de agente de borda dos seus TBRs.
Os TBRs precisam usar o mDNS para anunciar informações da rede Thread,
incluindo o nome da rede, o ID de 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 de rede do Google Thread para uso.
Integrar o SDK ao app Android
Para começar, siga estas etapas:
Siga as instruções 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 informações de TBR. Vamos usar estes dados ao longo deste 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 do roteador de borda do Thread
Antes de criar uma rede para novos roteadores de borda, é importante tentar usar as credenciais de rede preferenciais primeiro. Isso garante que os dispositivos Thread sejam 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 conjunto de chaves digital do SDK do Thread, elas
serão retornadas ao app.
Solicitar credenciais
Para solicitar as credenciais preferenciais do 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 chamar
preferredCredentialse iniciar 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 TBR, como um novo dispositivo final Matter-over-Thread, use a API
allActiveCredentialspara buscar credenciais. Essa chamada vai procurar TBRs encontrados na rede local e, portanto, não vai retornar credenciais que não estejam 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, use a API addCredentials para adicionar credenciais ao
Google Play Services. Para fazer isso, crie um ThreadBorderAgent
e forneça um objeto ThreadNetworkCredentials.
Para criar uma rede aleatória, chame newRandomizeBuilder:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder().build()
Para especificar o nome da rede Thread:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder()
.setNetworkName("ThreadNetworkSDK")
.build()
Adicionar credenciais
Para disponibilizar suas credenciais da rede Thread para outros fornecedores, 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 com base em 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, use
isPreferredCredentials para determinar se os border routers pertencem
à rede preferencial. Essa API não solicita permissão ao
usuário e compara as credenciais de border router com
o que está armazenado no Google Play Services.
isPreferredCredentials retorna 0 para não correspondente e 1 para correspondente, como um tipo de dados Int. Use 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 é necessário criar um objeto ThreadNetworkCredentials. Há várias maneiras de instanciar ThreadNetworkCredentials. Nas próximas etapas, vamos analisar essas opções.
Credenciais da rede Thread por conjunto de dados operacionais
Em alguns casos, o TBR já está configurado com uma
rede Thread, e você quer adicionar essa rede ao Google Play Services
para compartilhar com outros fornecedores. É possível criar uma instância ThreadNetworkCredential
com base em uma lista de TLV de conjunto de dados operacional ativo do Thread:
Converta o conjunto de dados operacionais 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. Se o processo for concluído, você poderá acessar o nome, o canal e outras informações da rede Thread. 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 da 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 foram salvas, verifique se
elas são as 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 da rede Thread por ID PAN estendido
Assim como em getPreferredCredentials, também é possível solicitar ao usuário as
credenciais de um ID PAN estendido de um TBR. 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 casa ou redefinido para a configuração original, é necessário remover a rede Thread dele 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 de rede Thread, consulte a referência da API.