Android용 스레드 네트워크 SDK

스레드 네트워크 SDK는 디지털 키체인과 비슷한 기능을 제공하여 Android 앱에서 스레드 네트워크 사용자 인증 정보를 Google Play 서비스와 공유할 수 있게 해줍니다. 이를 통해 앱은 사용자 인증 정보와 사용자 데이터를 직접 노출하지 않고도 스마트 홈 생태계에서 모든 Thread 기기를 설정할 수 있습니다.

몇 가지 API 호출만으로 다음 작업을 수행할 수 있습니다.

  1. Google Play 서비스에서 기본 스레드 네트워크 사용자 인증 정보를 요청합니다.
  2. 새 보더 라우터를 설정하고 Google Play 서비스에 스레드 네트워크 사용자 인증 정보를 추가합니다.
  3. 이미 현장 보더 라우터가 있는 경우 보더 라우터가 기본 네트워크에 있는지 확인하고 필요한 경우 마이그레이션합니다.

고려해야 할 몇 가지 사용자 및 개발자 여정이 있습니다. 이 가이드에서는 이러한 기능의 대부분을 다른 주요 기능 및 권장 사용법과 함께 다룹니다.

주요 용어 및 API 개념

시작하기 전에 다음 용어를 이해하는 것이 좋습니다.

  • 스레드 네트워크 사용자 인증 정보: 스레드 기기가 지정된 스레드 네트워크에 조인하는 데 필요한 스레드 네트워크 이름, 네트워크 키, 기타 속성을 인코딩하는 스레드 TLV의 바이너리 blob입니다.

  • 기본 스레드 네트워크 사용자 인증 정보: getPreferredCredentials API를 사용하여 다른 공급업체의 앱과 공유할 수 있는 자동 선택된 스레드 네트워크 사용자 인증 정보

  • 경계 에이전트 ID: 스레드 보더 라우터 기기의 전역적으로 고유한 16바이트 ID입니다. 이 ID는 보더 라우터 공급업체에서 만들고 관리합니다.

  • 스레드 보더 라우터 설정 앱: 새 스레드 보더 라우터 기기를 설정하고 Google Play 서비스에 스레드 네트워크 사용자 인증 정보를 추가하는 Android 앱입니다. 앱이 추가된 사용자 인증 정보의 신뢰할 수 있는 소유자이며 액세스 권한을 가집니다.

많은 Thread Network API가 비동기식으로 완료되는 Task를 반환합니다. addOnSuccessListeneraddOnFailureListener를 사용하여 결과를 수신하는 콜백을 등록할 수 있습니다. 자세한 내용은 작업 문서를 참조하세요.

사용자 인증 정보 소유권 및 유지관리

스레드 네트워크 사용자 인증 정보를 추가하는 앱이 사용자 인증 정보의 소유자가 되어 사용자 인증 정보에 액세스할 수 있는 전체 권한을 가집니다. 다른 앱에서 추가한 사용자 인증 정보에 액세스하려고 하면 PERMISSION_DENIED 오류가 발생합니다.

앱 소유자는 스레드 보더 라우터 네트워크가 업데이트될 때 Google Play 서비스에 저장된 사용자 인증 정보를 최신 상태로 유지하는 것이 좋습니다. 즉, 필요한 경우 사용자 인증 정보를 추가하고, 경계 라우터의 스레드 네트워크 사용자 인증 정보가 변경될 때 사용자 인증 정보를 업데이트하고, 스레드 보더 라우터를 제거하거나 초기화할 때 사용자 인증 정보를 삭제합니다.

Border Agent 검색

사용자 인증 정보는 Border Agent ID로 저장해야 합니다. Thread Border Router 설정 앱이 Thread 테두리 라우터의 Border Agent ID를 결정할 수 있는지 확인해야 합니다.

스레드 테두리 라우터는 mDNS를 사용하여 네트워크 이름, 확장 팬 ID, 경계 에이전트 ID 등의 스레드 네트워크 정보를 광고해야 합니다. 이러한 속성에 상응하는 txt 값은 각각 nn, xp, id입니다.

Google 보더 라우터가 있는 네트워크의 경우 Google Play 서비스가 사용할 Google 스레드 네트워크 사용자 인증 정보를 자동으로 가져옵니다.

Android 앱에 SDK 통합

시작하려면 다음 단계를 완료하세요.

  1. Google Play 서비스 설정의 안내를 따르세요.

  2. build.gradle 파일에 Google Play 서비스 종속 항목을 추가합니다.

    implementation 'com.google.android.gms:play-services-threadnetwork:16.0.0'
    
  3. 선택사항: BorderAgent 데이터 클래스를 정의하여 테두리 라우터 정보를 저장합니다. 이 가이드에서는 이 데이터를 사용합니다.

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

그런 다음 권장 사용자 인증 정보를 추가하고 관리하기 위한 권장 단계를 살펴봅니다.

새로운 보더 라우터 설정

새 보더 라우터를 위한 새 네트워크를 만들기 전에 먼저 원하는 네트워크 사용자 인증 정보를 사용해 보는 것이 중요합니다. 이렇게 하면 가능한 경우 스레드 기기가 단일 스레드 네트워크에 연결됩니다.

getPreferredCredentials를 호출하면 활동을 시작하고 사용자에게 네트워크 요청을 허용하라는 메시지를 표시합니다. 네트워크 사용자 인증 정보가 Thread SDK 디지털 키체인에 저장된 경우 사용자 인증 정보가 앱에 반환됩니다.

사용자 인증 정보 요청

사용자에게 기본 사용자 인증 정보를 요청하는 메시지를 표시하려면 다음 단계를 따르세요.

  1. ActivityLauncher를 선언합니다.

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. 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. preferredCredentials를 호출하고 활동을 시작합니다.

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

새 스레드 네트워크 만들기

사용자의 스레드 네트워크에서 사용할 수 있는 기본 스레드 네트워크 사용자 인증 정보가 없다면 addCredentials API를 사용하여 Google Play 서비스에 사용자 인증 정보를 추가할 수 있습니다. 이렇게 하려면 ThreadBorderAgent를 만들고 ThreadNetworkCredentials 객체도 제공해야 합니다.

랜덤 네트워크를 만들려면 newRandomizeBuilder를 호출합니다.

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

스레드 네트워크 이름을 지정하려면 다음 단계를 따르세요.

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

사용자 인증 정보 추가

스레드 네트워크 사용자 인증 정보를 다른 스레드 공급업체에 제공하려면 Google Play 서비스에 추가해야 합니다. 새 사용자 인증 정보를 추가하기 전에 이 스레드 네트워크가 속한 보더 라우터 기기도 알아야 합니다.

이 예에서는 Border Agent ID에서 ThreadBorderAgent를 만들고 방금 만든 새 스레드 네트워크 사용자 인증 정보를 전달합니다.

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를, 일치하는 경우 1Int 데이터 유형으로 반환합니다. IsPreferredCredentialsResult를 사용하여 결과를 확인할 수 있습니다.

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

isPreferredCredentials를 사용하려면 먼저 ThreadNetworkCredentials 객체를 만들어야 합니다. ThreadNetworkCredentials를 인스턴스화하는 방법에는 여러 가지가 있습니다. 다음 단계에서는 이러한 옵션을 살펴봅니다.

운영 데이터 세트별 스레드 네트워크 사용자 인증 정보

스레드 테두리 라우터가 이미 스레드 네트워크와 함께 설정된 경우 이 스레드 네트워크를 Google Play 서비스에 추가하여 다른 공급업체와 공유하려고 합니다. 원시 스레드 활성 작업 데이터 세트 TLV 목록에서 ThreadNetworkCredential 인스턴스를 만들 수 있습니다.

  1. 운영 데이터 세트를 ByteArray으로 변환합니다. 예를 들면 다음과 같습니다.

    val activeDataset =
          "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
    
    fun String.dsToByteArray(): ByteArray {
      return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
    }
    
  2. fromActiveOperationalDataset를 사용하여 ThreadNetworkCredentials를 만듭니다. 성공하면 스레드 네트워크 이름, 채널, 기타 네트워크 정보를 가져올 수 있습니다. 전체 속성 목록은 ThreadNetworkCredentials를 참고하세요.

    val threadNetworkCredentials =
        ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset)
    Log.d(
        "threadNetworkCredentials",
        threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
    
  3. isPreferredCredentials API를 호출하고 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의 스레드 네트워크 사용자 인증 정보

경계 에이전트 ID는 보더 라우터 기기를 고유하게 식별합니다. getCredentialsByBorderAgent API를 사용하려면 먼저 ThreadBorderAgent 객체를 만들고 Border Agent ID를 전달해야 합니다.

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

확장 팬 ID별 스레드 네트워크 사용자 인증 정보

getPreferredCredentials와 마찬가지로, 테두리 라우터의 확장 팬 ID에서 사용자에게 사용자 인증 정보를 요청하는 메시지를 표시할 수도 있습니다. getCredentialsByExtendedPanIdIntentSender를 반환하고, 사용자가 승인하면 활동 결과에 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 기기가 집이나 초기화 상태에서 제거되면 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에 관한 자세한 내용은 API 참조를 참고하세요.