SDK Thread Network предоставляет функциональность, аналогичную цифровой связке ключей, позволяя вашим приложениям Android обмениваться учетными данными сети Thread со службами Google Play. Это позволяет вашим приложениям настраивать любое устройство Thread из любой экосистемы умного дома, не раскрывая учетные данные и пользовательские данные напрямую.
С помощью всего лишь нескольких вызовов API вы можете:
- Запросите предпочтительные учетные данные сети Thread в сервисах Google Play.
- Настройте новые пограничные маршрутизаторы и добавьте учетные данные сети Thread в сервисы Google Play.
- Если у вас уже есть пограничные маршрутизаторы в полевых условиях, вы можете проверить, находятся ли ваши пограничные маршрутизаторы в предпочтительной сети, и при необходимости перенести их.
Необходимо рассмотреть несколько путей развития пользователей и разработчиков. В этом руководстве мы рассмотрим большинство из них, а также другие ключевые функции и рекомендации по использованию.
Основная терминология и концепции API
Прежде чем приступить к работе, полезно понять следующие термины:
Учетные данные сети потока: двоичный объект TLV потока, который кодирует имя сети потока, ключ сети и другие свойства, необходимые устройству потока для присоединения к данной сети потока.
Предпочитаемые сетевые учетные данные потоков: автоматически выбираемые сетевые учетные данные потоков, которые можно использовать совместно с приложениями разных поставщиков с помощью API
getPreferredCredentials
.Идентификатор пограничного агента: 16-байтовый глобальный уникальный идентификатор устройства Thread Border Router. Этот идентификатор создается и управляется поставщиками пограничных маршрутизаторов.
Приложение настройки Thread Border Router: это ваше приложение для Android, которое настраивает новые устройства Thread Border Router и добавляет сетевые учетные данные Thread в сервисы Google Play. Ваше приложение является полноправным владельцем добавленных учетных данных и имеет к ним доступ.
Многие API-интерфейсы Thread Network возвращают задачу , которая выполняется асинхронно. Вы можете использовать addOnSuccessListener и addOnFailureListener для регистрации обратных вызовов для получения результата. Чтобы узнать больше, обратитесь к документации задачи .
Владение и обслуживание учетных данных
Приложение, которое добавляет сетевые учетные данные Thread, становится владельцем учетных данных и имеет полные разрешения на доступ к учетным данным. Если вы попытаетесь получить доступ к учетным данным, добавленным другими приложениями, вы получите ошибку PERMISSION_DENIED
.
Как владельцу приложения рекомендуется обновлять учетные данные, хранящиеся в службах Google Play, при обновлении сети Thread Border Router. Это означает добавление учетных данных при необходимости, обновление учетных данных при изменении учетных данных сети Thread пограничного маршрутизатора и удаление учетных данных при удалении пограничного маршрутизатора Thread или сбросе настроек до заводских.
Обнаружение пограничного агента
Учетные данные должны быть сохранены с идентификатором пограничного агента. Вам необходимо убедиться, что ваше приложение настройки пограничного маршрутизатора Thread может определить идентификаторы пограничного агента ваших пограничных маршрутизаторов Thread.
Граничные маршрутизаторы потоков должны использовать mDNS для объявления информации о сети потоков, включая имя сети, расширенный идентификатор Pan и идентификатор пограничного агента. Соответствующие значения txt
для этих атрибутов — nn
, xp
и id
соответственно.
В сетях с пограничными маршрутизаторами Google сервисы Google Play автоматически получают для использования сетевые учетные данные Google Thread.
Интегрируйте SDK в свое приложение для Android.
Для начала выполните следующие шаги:
Следуйте инструкциям в разделе «Настройка сервисов Google Play» .
Добавьте зависимость сервисов Google Play в файл
build.gradle
:implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'
Необязательно: Определите класс данных
BorderAgent
для хранения информации о пограничном маршрутизаторе. Мы будем использовать эти данные в этом руководстве:data class BorderAgentInfo( // Network Name max 16 len val networkName: String = "", val extPanId: ByteArray = ByteArray(16), val borderAgentId: ByteArray = ByteArray(16), ... )
Далее мы рассмотрим рекомендуемые шаги по добавлению предпочтительных учетных данных и управлению ими.
Новые настройки пограничного маршрутизатора
Прежде чем создавать новую сеть для новых пограничных маршрутизаторов, важно сначала попробовать использовать предпочтительные сетевые учетные данные. Это гарантирует, что устройства Thread будут подключены к одной сети Thread, когда это возможно.
Вызов getPreferredCredentials
запускает действие, предлагающее пользователям разрешить сетевой запрос. Если сетевые учетные данные сохранены в цифровой цепочке ключей Thread SDK, они возвращаются в ваше приложение.
Запросить учетные данные
Чтобы запросить у пользователя предпочтительные учетные данные:
Объявите
ActivityLauncher
:private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
Обработайте результат действия, возвращенный как
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.") } }
Если вы настраиваете новый пограничный маршрутизатор потоков, рекомендуется вызвать
preferredCredentials
и запустить Activity. Этот вызов гарантирует, что ваш новый пограничный маршрутизатор потоков будет использовать те же учетные данные, которые уже сохранены в телефоне, что способствует объединению различных TBR в одну и ту же сеть.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}]") } }
Если ваш вариант использования связан с настройкой устройств, не поддерживающих TBR, например нового конечного устройства Matter-over-Thread, рекомендуется использовать API
allActiveCredentials
для получения учетных данных. Этот вызов будет сканировать TBR, найденные в локальной сети, и, таким образом, не будет возвращать учетные данные, которые недоступны для существующего TBR локально.// 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 }
Создайте новую сеть потоков
Если в сети Thread нет ни предпочитаемых учетных данных сети Thread, ни учетных данных активного потока, вы можете использовать API addCredentials
для добавления учетных данных в Службы Google Play. Для этого вам потребуется создать ThreadBorderAgent
, а также предоставить объект ThreadNetworkCredentials
.
Чтобы создать случайную сеть, вызовите newRandomizeBuilder
:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder().build()
Чтобы указать имя сети потока:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder()
.setNetworkName("ThreadNetworkSDK")
.build()
Добавить учетные данные
Чтобы сделать ваши сетевые учетные данные Thread доступными для других поставщиков Thread, нам необходимо добавить их в службы Google Play. Прежде чем мы сможем добавить наши новые учетные данные, нам также необходимо знать, какому устройству пограничного маршрутизатора принадлежит эта сеть потоков.
В этом примере мы создадим ThreadBorderAgent
на основе идентификатора пограничного агента и передадим новые учетные данные сети Thread, которые вы только что создали:
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}]") }
}
Обнаружение и миграция пограничных маршрутизаторов в полевых условиях
Если у вас в настоящее время есть пограничные маршрутизаторы, вы можете использовать isPreferredCredentials
, чтобы определить, принадлежат ли ваши пограничные маршрутизаторы к предпочтительной сети. Этот API не запрашивает у пользователя разрешение и проверяет учетные данные пограничного маршрутизатора на соответствие данным, хранящимся в сервисах Google Play.
isPreferredCredentails
возвращает 0
для несоответствия и 1
для совпадения в качестве типа данных Int
. Вы можете использовать IsPreferredCredentialsResult
для проверки результатов.
public @interface IsPreferredCredentialsResult {
int PREFERRED_CREDENTIALS_NOT_FOUND = -1;
int PREFERRED_CREDENTIALS_NOT_MATCHED = 0;
int PREFERRED_CREDENTIALS_MATCHED = 1;
}
Чтобы использовать isPreferredCredentials
, вам необходимо сначала создать объект ThreadNetworkCredentials
. Существует несколько способов создания экземпляра ThreadNetworkCredentials
. На следующих шагах мы рассмотрим эти варианты.
Учетные данные сети потоков по набору операционных данных
Бывают случаи, когда ваш пограничный маршрутизатор Thread уже настроен с сетью Thread, и вы хотите добавить эту сеть Thread в службы Google Play, чтобы поделиться ею с другими поставщиками. Вы можете создать экземпляр ThreadNetworkCredential
из необработанного списка TLV набора активных рабочих данных потока:
Преобразуйте набор операционных данных в
ByteArray
. Например:val activeDataset = "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
fun String.dsToByteArray(): ByteArray { return chunked(2).map { it.toInt(16).toByte() }.toByteArray() }
Используйте
fromActiveOperationalDataset
для созданияThreadNetworkCredentials
. В случае успеха вы сможете получить имя сети потока, канал и другую сетевую информацию. Полный список свойств см. в ThreadNetworkCredentials .val threadNetworkCredentials = ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset) Log.d( "threadNetworkCredentials", threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
Вызовите API
isPreferredCredentials
и передайте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}]") }
Сетевые учетные данные потока от Border Agent
Идентификатор пограничного агента однозначно идентифицирует устройство пограничного маршрутизатора. Чтобы использовать API getCredentialsByBorderAgent
, сначала вам необходимо создать объект ThreadBorderAgent
и передать идентификатор пограничного агента.
После создания объекта ThreadBorderAgent
вызовите getCredentialsByBorderAgent
. Если учетные данные были сохранены, проверьте, являются ли они предпочтительными.
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}]") }
}
Сетевые учетные данные потока по расширенному идентификатору Pan
Подобно getPreferredCredentials
, вы также можете запросить у пользователя учетные данные из расширенного идентификатора Pan пограничного маршрутизатора. getCredentialsByExtendedPanId
возвращает IntentSender
, а результат действия содержит объект ThreadNetworkCredentials
, когда пользователь одобряет.
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}]") }
}
Удалить учетные данные
Когда ваше устройство Border Router удалено из вашего дома или выполнено восстановление заводских настроек, вам необходимо удалить его сеть Thread из сервисов 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}]") }
}
Ресурсы
Дополнительные сведения о пакете SDK Thread Network см. в справочнике по API .
,SDK Thread Network предоставляет функциональность, аналогичную цифровой связке ключей, позволяя вашим приложениям Android обмениваться учетными данными сети Thread со службами Google Play. Это позволяет вашим приложениям настраивать любое устройство Thread из любой экосистемы умного дома, не раскрывая учетные данные и пользовательские данные напрямую.
С помощью всего лишь нескольких вызовов API вы можете:
- Запросите предпочтительные учетные данные сети Thread в сервисах Google Play.
- Настройте новые пограничные маршрутизаторы и добавьте учетные данные сети Thread в сервисы Google Play.
- Если у вас уже есть пограничные маршрутизаторы в полевых условиях, вы можете проверить, находятся ли ваши пограничные маршрутизаторы в предпочтительной сети, и при необходимости перенести их.
Необходимо рассмотреть несколько путей развития пользователей и разработчиков. В этом руководстве мы рассмотрим большинство из них, а также другие ключевые функции и рекомендации по использованию.
Основная терминология и концепции API
Прежде чем приступить к работе, полезно понять следующие термины:
Учетные данные сети потока: двоичный объект TLV потока, который кодирует имя сети потока, ключ сети и другие свойства, необходимые устройству потока для присоединения к данной сети потока.
Предпочитаемые сетевые учетные данные потоков: автоматически выбираемые сетевые учетные данные потоков, которые можно использовать совместно с приложениями разных поставщиков с помощью API
getPreferredCredentials
.Идентификатор пограничного агента: 16-байтовый глобальный уникальный идентификатор устройства Thread Border Router. Этот идентификатор создается и управляется поставщиками пограничных маршрутизаторов.
Приложение настройки Thread Border Router: это ваше приложение для Android, которое настраивает новые устройства Thread Border Router и добавляет сетевые учетные данные Thread в сервисы Google Play. Ваше приложение является полноправным владельцем добавленных учетных данных и имеет к ним доступ.
Многие API-интерфейсы Thread Network возвращают задачу , которая выполняется асинхронно. Вы можете использовать addOnSuccessListener и addOnFailureListener для регистрации обратных вызовов для получения результата. Чтобы узнать больше, обратитесь к документации задачи .
Владение и обслуживание учетных данных
Приложение, которое добавляет сетевые учетные данные Thread, становится владельцем учетных данных и имеет полные разрешения на доступ к учетным данным. Если вы попытаетесь получить доступ к учетным данным, добавленным другими приложениями, вы получите ошибку PERMISSION_DENIED
.
Как владельцу приложения рекомендуется обновлять учетные данные, хранящиеся в службах Google Play, при обновлении сети Thread Border Router. Это означает добавление учетных данных при необходимости, обновление учетных данных при изменении сетевых учетных данных Thread пограничного маршрутизатора и удаление учетных данных при удалении пограничного маршрутизатора Thread или сбросе настроек до заводских.
Обнаружение пограничного агента
Учетные данные должны быть сохранены с идентификатором пограничного агента. Вам необходимо убедиться, что ваше приложение настройки пограничного маршрутизатора Thread может определить идентификаторы пограничного агента ваших пограничных маршрутизаторов Thread.
Граничные маршрутизаторы потоков должны использовать mDNS для объявления информации о сети потоков, включая имя сети, расширенный идентификатор Pan и идентификатор пограничного агента. Соответствующие значения txt
для этих атрибутов — nn
, xp
и id
соответственно.
В сетях с пограничными маршрутизаторами Google сервисы Google Play автоматически получают для использования сетевые учетные данные Google Thread.
Интегрируйте SDK в свое приложение для Android.
Для начала выполните следующие шаги:
Следуйте инструкциям в разделе «Настройка сервисов Google Play» .
Добавьте зависимость сервисов Google Play в файл
build.gradle
:implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'
Необязательно: Определите класс данных
BorderAgent
для хранения информации о пограничном маршрутизаторе. Мы будем использовать эти данные в этом руководстве:data class BorderAgentInfo( // Network Name max 16 len val networkName: String = "", val extPanId: ByteArray = ByteArray(16), val borderAgentId: ByteArray = ByteArray(16), ... )
Далее мы рассмотрим рекомендуемые шаги по добавлению предпочтительных учетных данных и управлению ими.
Новые настройки пограничного маршрутизатора
Прежде чем создавать новую сеть для новых пограничных маршрутизаторов, важно сначала попробовать использовать предпочтительные сетевые учетные данные. Это гарантирует, что устройства Thread будут подключены к одной сети Thread, когда это возможно.
Вызов getPreferredCredentials
запускает действие, предлагающее пользователям разрешить сетевой запрос. Если сетевые учетные данные сохранены в цифровой цепочке ключей Thread SDK, они возвращаются в ваше приложение.
Запросить учетные данные
Чтобы запросить у пользователя предпочтительные учетные данные:
Объявите
ActivityLauncher
:private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
Обработайте результат действия, возвращенный как
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.") } }
Если вы настраиваете новый пограничный маршрутизатор потоков, рекомендуется вызвать
preferredCredentials
и запустить Activity. Этот вызов гарантирует, что ваш новый пограничный маршрутизатор потоков будет использовать те же учетные данные, которые уже сохранены в телефоне, что способствует объединению различных TBR в одну и ту же сеть.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}]") } }
Если ваш вариант использования связан с настройкой устройств, не поддерживающих TBR, например нового конечного устройства Matter-over-Thread, рекомендуется использовать API
allActiveCredentials
для получения учетных данных. Этот вызов будет сканировать TBR, найденные в локальной сети, и, таким образом, не будет возвращать учетные данные, которые недоступны для существующего TBR локально.// 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 }
Создайте новую сеть потоков
Если в сети Thread нет ни предпочитаемых учетных данных сети Thread, ни учетных данных активного потока, вы можете использовать API addCredentials
для добавления учетных данных в Службы Google Play. Для этого вам потребуется создать ThreadBorderAgent
, а также предоставить объект ThreadNetworkCredentials
.
Чтобы создать случайную сеть, вызовите newRandomizeBuilder
:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder().build()
Чтобы указать имя сети потока:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder()
.setNetworkName("ThreadNetworkSDK")
.build()
Добавить учетные данные
Чтобы сделать ваши сетевые учетные данные Thread доступными для других поставщиков Thread, нам необходимо добавить их в службы Google Play. Прежде чем мы сможем добавить наши новые учетные данные, нам также необходимо знать, какому устройству пограничного маршрутизатора принадлежит эта сеть потоков.
В этом примере мы создадим ThreadBorderAgent
на основе идентификатора пограничного агента и передадим новые учетные данные сети Thread, которые вы только что создали:
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}]") }
}
Обнаружение и миграция пограничных маршрутизаторов в полевых условиях
Если у вас в настоящее время есть пограничные маршрутизаторы, вы можете использовать isPreferredCredentials
, чтобы определить, принадлежат ли ваши пограничные маршрутизаторы к предпочтительной сети. Этот API не запрашивает у пользователя разрешение и проверяет учетные данные пограничного маршрутизатора на соответствие данным, хранящимся в сервисах Google Play.
isPreferredCredentails
возвращает 0
для несоответствия и 1
для совпадения в качестве типа данных Int
. Вы можете использовать IsPreferredCredentialsResult
для проверки результатов.
public @interface IsPreferredCredentialsResult {
int PREFERRED_CREDENTIALS_NOT_FOUND = -1;
int PREFERRED_CREDENTIALS_NOT_MATCHED = 0;
int PREFERRED_CREDENTIALS_MATCHED = 1;
}
Чтобы использовать isPreferredCredentials
, вам необходимо сначала создать объект ThreadNetworkCredentials
. Существует несколько способов создания экземпляра ThreadNetworkCredentials
. На следующих шагах мы рассмотрим эти варианты.
Учетные данные сети потоков по набору операционных данных
Бывают случаи, когда ваш пограничный маршрутизатор Thread уже настроен с сетью Thread, и вы хотите добавить эту сеть Thread в службы Google Play, чтобы поделиться ею с другими поставщиками. Вы можете создать экземпляр ThreadNetworkCredential
из необработанного списка TLV набора активных рабочих данных потока:
Преобразуйте набор операционных данных в
ByteArray
. Например:val activeDataset = "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
fun String.dsToByteArray(): ByteArray { return chunked(2).map { it.toInt(16).toByte() }.toByteArray() }
Используйте
fromActiveOperationalDataset
для созданияThreadNetworkCredentials
. В случае успеха вы сможете получить имя сети потока, канал и другую сетевую информацию. Полный список свойств см. в ThreadNetworkCredentials .val threadNetworkCredentials = ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset) Log.d( "threadNetworkCredentials", threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
Вызовите API
isPreferredCredentials
и передайте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}]") }
Сетевые учетные данные потока от Border Agent
Идентификатор пограничного агента однозначно идентифицирует устройство пограничного маршрутизатора. Чтобы использовать API getCredentialsByBorderAgent
, сначала вам необходимо создать объект ThreadBorderAgent
и передать идентификатор пограничного агента.
После создания объекта ThreadBorderAgent
вызовите getCredentialsByBorderAgent
. Если учетные данные были сохранены, проверьте, являются ли они предпочтительными.
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}]") }
}
Сетевые учетные данные потока по расширенному идентификатору Pan
Подобно getPreferredCredentials
, вы также можете запросить у пользователя учетные данные из расширенного идентификатора Pan пограничного маршрутизатора. getCredentialsByExtendedPanId
возвращает IntentSender
, а результат действия содержит объект ThreadNetworkCredentials
, когда пользователь одобряет.
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}]") }
}
Удалить учетные данные
Когда ваше устройство Border Router удалено из вашего дома или выполнено восстановление заводских настроек, вам необходимо удалить его сеть Thread из сервисов 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}]") }
}
Ресурсы
Дополнительные сведения о пакете SDK Thread Network см. в справочнике по API .
,SDK Thread Network предоставляет функциональность, аналогичную цифровой связке ключей, позволяя вашим приложениям Android обмениваться учетными данными сети Thread со службами Google Play. Это позволяет вашим приложениям настраивать любое устройство Thread из любой экосистемы умного дома, не раскрывая учетные данные и пользовательские данные напрямую.
С помощью всего лишь нескольких вызовов API вы можете:
- Запросите предпочтительные учетные данные сети Thread в сервисах Google Play.
- Настройте новые пограничные маршрутизаторы и добавьте учетные данные сети Thread в сервисы Google Play.
- Если у вас уже есть пограничные маршрутизаторы в полевых условиях, вы можете проверить, находятся ли ваши пограничные маршрутизаторы в предпочтительной сети, и при необходимости перенести их.
Необходимо рассмотреть несколько путей развития пользователей и разработчиков. В этом руководстве мы рассмотрим большинство из них, а также другие ключевые функции и рекомендации по использованию.
Основная терминология и концепции API
Прежде чем приступить к работе, полезно понять следующие термины:
Учетные данные сети потоков: двоичный объект TLV потоков, который кодирует имя сети потоков, ключ сети и другие свойства, необходимые устройству потоков для присоединения к данной сети потоков.
Предпочитаемые сетевые учетные данные потока: автоматически выбираемые сетевые учетные данные потока, которые можно использовать совместно с приложениями разных поставщиков с помощью API
getPreferredCredentials
.Идентификатор пограничного агента: 16-байтовый глобальный уникальный идентификатор устройства Thread Border Router. Этот идентификатор создается и управляется поставщиками пограничных маршрутизаторов.
Приложение настройки Thread Border Router: это ваше приложение для Android, которое настраивает новые устройства Thread Border Router и добавляет сетевые учетные данные Thread в сервисы Google Play. Ваше приложение является полноправным владельцем добавленных учетных данных и имеет к ним доступ.
Многие API-интерфейсы Thread Network возвращают задачу , которая выполняется асинхронно. Вы можете использовать addOnSuccessListener и addOnFailureListener для регистрации обратных вызовов для получения результата. Чтобы узнать больше, обратитесь к документации задачи .
Владение и обслуживание учетных данных
Приложение, которое добавляет сетевые учетные данные Thread, становится владельцем учетных данных и имеет полные разрешения на доступ к учетным данным. Если вы попытаетесь получить доступ к учетным данным, добавленным другими приложениями, вы получите ошибку PERMISSION_DENIED
.
Как владельцу приложения рекомендуется обновлять учетные данные, хранящиеся в службах Google Play, при обновлении сети Thread Border Router. Это означает добавление учетных данных при необходимости, обновление учетных данных при изменении сетевых учетных данных Thread пограничного маршрутизатора и удаление учетных данных при удалении пограничного маршрутизатора Thread или сбросе настроек до заводских.
Обнаружение пограничного агента
Учетные данные должны быть сохранены с идентификатором пограничного агента. Вам необходимо убедиться, что ваше приложение настройки пограничного маршрутизатора Thread может определить идентификаторы пограничного агента ваших пограничных маршрутизаторов Thread.
Граничные маршрутизаторы потоков должны использовать mDNS для объявления информации о сети потоков, включая имя сети, расширенный идентификатор Pan и идентификатор пограничного агента. Соответствующие значения txt
для этих атрибутов — nn
, xp
и id
соответственно.
В сетях с пограничными маршрутизаторами Google сервисы Google Play автоматически получают для использования сетевые учетные данные Google Thread.
Интегрируйте SDK в свое приложение для Android.
Для начала выполните следующие шаги:
Следуйте инструкциям в разделе «Настройка сервисов Google Play» .
Добавьте зависимость сервисов Google Play в файл
build.gradle
:implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'
Необязательно: Определите класс данных
BorderAgent
для хранения информации о пограничном маршрутизаторе. Мы будем использовать эти данные в этом руководстве:data class BorderAgentInfo( // Network Name max 16 len val networkName: String = "", val extPanId: ByteArray = ByteArray(16), val borderAgentId: ByteArray = ByteArray(16), ... )
Далее мы рассмотрим рекомендуемые шаги по добавлению предпочтительных учетных данных и управлению ими.
Новые настройки пограничного маршрутизатора
Прежде чем создавать новую сеть для новых пограничных маршрутизаторов, важно сначала попробовать использовать предпочтительные сетевые учетные данные. Это гарантирует, что устройства Thread будут подключены к одной сети Thread, когда это возможно.
Вызов getPreferredCredentials
запускает действие, предлагающее пользователям разрешить сетевой запрос. Если сетевые учетные данные сохранены в цифровой цепочке ключей Thread SDK, они возвращаются в ваше приложение.
Запросить учетные данные
Чтобы запросить у пользователя предпочтительные учетные данные:
Объявите
ActivityLauncher
:private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
Обработайте результат действия, возвращенный как
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.") } }
Если вы настраиваете новый пограничный маршрутизатор потоков, рекомендуется вызвать
preferredCredentials
и запустить Activity. Этот вызов гарантирует, что ваш новый пограничный маршрутизатор потоков будет использовать те же учетные данные, которые уже сохранены в телефоне, что способствует объединению различных TBR в одну и ту же сеть.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}]") } }
Если ваш вариант использования связан с настройкой устройств, не поддерживающих TBR, например нового конечного устройства Matter-over-Thread, рекомендуется использовать API
allActiveCredentials
для получения учетных данных. Этот вызов будет сканировать TBR, найденные в локальной сети, и, таким образом, не будет возвращать учетные данные, которые недоступны для существующего TBR локально.// 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 }
Создайте новую сеть потоков
Если в сети Thread нет ни предпочитаемых учетных данных сети Thread, ни учетных данных активного потока, вы можете использовать API addCredentials
для добавления учетных данных в Службы Google Play. Для этого вам потребуется создать ThreadBorderAgent
, а также предоставить объект ThreadNetworkCredentials
.
Чтобы создать случайную сеть, вызовите newRandomizeBuilder
:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder().build()
Чтобы указать имя сети потока:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder()
.setNetworkName("ThreadNetworkSDK")
.build()
Добавить учетные данные
Чтобы сделать ваши сетевые учетные данные Thread доступными для других поставщиков Thread, нам необходимо добавить их в службы Google Play. Прежде чем мы сможем добавить наши новые учетные данные, нам также необходимо знать, какому устройству пограничного маршрутизатора принадлежит эта сеть потоков.
В этом примере мы создадим ThreadBorderAgent
на основе идентификатора пограничного агента и передадим новые учетные данные сети Thread, которые вы только что создали:
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}]") }
}
Обнаружение и миграция пограничных маршрутизаторов в полевых условиях
Если у вас в настоящее время есть пограничные маршрутизаторы, вы можете использовать isPreferredCredentials
, чтобы определить, принадлежат ли ваши пограничные маршрутизаторы к предпочтительной сети. Этот API не запрашивает у пользователя разрешение и проверяет учетные данные пограничного маршрутизатора на соответствие данным, хранящимся в сервисах Google Play.
isPreferredCredentails
возвращает 0
для несоответствия и 1
для совпадения в качестве типа данных Int
. Вы можете использовать IsPreferredCredentialsResult
для проверки результатов.
public @interface IsPreferredCredentialsResult {
int PREFERRED_CREDENTIALS_NOT_FOUND = -1;
int PREFERRED_CREDENTIALS_NOT_MATCHED = 0;
int PREFERRED_CREDENTIALS_MATCHED = 1;
}
Чтобы использовать isPreferredCredentials
, вам необходимо сначала создать объект ThreadNetworkCredentials
. Существует несколько способов создания экземпляра ThreadNetworkCredentials
. На следующих шагах мы рассмотрим эти варианты.
Учетные данные сети потоков по набору операционных данных
Бывают случаи, когда ваш пограничный маршрутизатор Thread уже настроен с сетью Thread, и вы хотите добавить эту сеть Thread в службы Google Play, чтобы поделиться ею с другими поставщиками. Вы можете создать экземпляр ThreadNetworkCredential
из необработанного списка TLV набора активных рабочих данных потока:
Преобразуйте набор операционных данных в
ByteArray
. Например:val activeDataset = "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
fun String.dsToByteArray(): ByteArray { return chunked(2).map { it.toInt(16).toByte() }.toByteArray() }
Используйте
fromActiveOperationalDataset
для созданияThreadNetworkCredentials
. В случае успеха вы сможете получить имя сети потока, канал и другую сетевую информацию. Полный список свойств см. в ThreadNetworkCredentials .val threadNetworkCredentials = ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset) Log.d( "threadNetworkCredentials", threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
Вызовите API
isPreferredCredentials
и передайте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}]") }
Сетевые учетные данные потока от Border Agent
Идентификатор пограничного агента однозначно идентифицирует устройство пограничного маршрутизатора. Чтобы использовать API getCredentialsByBorderAgent
, сначала вам необходимо создать объект ThreadBorderAgent
и передать идентификатор пограничного агента.
После создания объекта ThreadBorderAgent
вызовите getCredentialsByBorderAgent
. Если учетные данные были сохранены, проверьте, являются ли они предпочтительными.
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}]") }
}
Сетевые учетные данные потока по расширенному идентификатору Pan
Подобно getPreferredCredentials
, вы также можете запросить у пользователя учетные данные из расширенного идентификатора Pan пограничного маршрутизатора. getCredentialsByExtendedPanId
возвращает IntentSender
, а результат действия содержит объект ThreadNetworkCredentials
, когда пользователь одобряет.
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}]") }
}
Удалить учетные данные
Когда ваше устройство Border Router удалено из вашего дома или выполнено восстановление заводских настроек, вам необходимо удалить его сеть Thread из сервисов 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}]") }
}
Ресурсы
Дополнительные сведения о пакете SDK Thread Network см. в справочнике по API .