법적 사안용 Android 앱 빌드

1. 시작하기

IoT 표준을 통합한다는 목표를 바탕으로 Matter는 Google Home, Zigbee, Bluetooth Mesh, Z-Wave 등의 다양한 생태계에서 스마트 홈 기기를 연결합니다.

휴대기기는 스마트 홈 기기와의 중심 상호작용 지점입니다. Matter 기기를 지원하는 자체 Android 앱을 빌드하시려는 경우 빠른 시작을 도와드리겠습니다.

Matter용 Google Home 샘플 앱 (GHSA용 GHSA)에서 사용자가 기기를 수수료와 공유할 수 있는 Home Mobile SDK API를 소개합니다. 또한 샘플 앱을 학습 도구로 사용하여 중요한 Matter 개념을 이해하고 Matter 기기와의 상호작용을 디버깅하고 문제를 해결할 수 있습니다.

실행할 작업

이 Codelab에서는 샘플 앱의 소스 코드를 다운로드하고 Home Mobile SDK를 사용하여 기기를 의뢰하고 공유하는 방법을 알아봅니다. Matter 저장소 (connectedhomeip)에서 수수료 및 클러스터 라이브러리를 사용하는 방법도 알아봅니다.

샘플 앱을 다운로드하면 Android 스튜디오에서 소스 코드를 검토하고 다음 Home Mobile SDK API를 구현합니다.

수수료 개념, Matter 패브릭, Matter 기기 제어 방법에 대해서도 알아봅니다.

필요한 항목

시작하기 전에 다음 단계를 완료해야 합니다.

샘플 앱으로 기기를 의뢰하고 제어하는 데는 Google Nest Hub (2세대)와 같은 허브가 필요하지 않습니다.

2 설정

샘플 앱 GitHub 저장소에는 Matter 저장소 (connectedhomeip)의 타사 라이브러리가 포함되어 있습니다. 이러한 네이티브 라이브러리는 50MB가 넘으며 Git 대용량 파일 저장소 (LFS)를 사용해야 합니다.

Codelab 시작 앱은 codelab 브랜치에 있습니다. Codelab 소스 코드로 작업하려면 ZIP 파일을 다운로드하면 됩니다. 이 ZIP 파일에는 Git LFS가 필요 없는 Matter SDK 네이티브 라이브러리가 포함되어 있습니다.

codelab ZIP 파일을 사용하여 작동하는 샘플을 빌드합니다.

Codelab 버전

codelab 브랜치는 샘플 앱의 1.2.2 출시로 태그되었습니다. 각 단계를 진행하는 동안 업데이트를 비교하려면 이 출시의 완료된 소스 코드를 다운로드하면 됩니다.

GitHub 저장소를 클론하려면 샘플 앱 리드미의 안내를 따르세요.

종속 항목

기기를 공유하고 의뢰하는 데 필요한 소스 코드를 안내해 드리지만 시작하기 전에 다음 종속 항목을 숙지하는 것이 좋습니다.

  • Home 모바일 SDK.
    implementation 'com.google.android.gms:play-services-home:16.0.0'
    
  • Matter SDK 라이브러리.
    // Native libs
    implementation fileTree(dir: "third_party/connectedhomeip/libs", include: ["*.jar", "*.so"])
    
  • Material Design 자세한 내용은 MDC-103 Android: 색상, 고도, 유형 (Kotlin)을 사용한 Material ThemingMaterial 테마 빌더를 참고하세요.
    implementation 'com.google.android.material:material:1.5.0'
    
  • Proto Datastore는 앱 데이터를 유지하는 데 사용됩니다. Datastore 저장소 및 Serializer는 기기 스키마와 사용자 환경설정을 포함하여 java/data에 저장됩니다. Datastore에 관한 자세한 내용은 Proto Datastore 사용을 참고하세요.
    implementation "androidx.datastore:datastore:$dataStoreVersion"
    implementation 'androidx.datastore:datastore-core:1.0.0'
    implementation 'com.google.protobuf:protobuf-javalite:3.18.0'
    
  • Hilt를 사용하면 데이터를 유지하고 종속 항목 삽입을 지원할 수 있습니다.
    kapt 'com.google.dagger:hilt-compiler:2.41'
    implementation 'com.google.dagger:hilt-android:2.41'
    

소스 코드

사용자 인터페이스 및 대부분의 기능이 이미 생성되어 있습니다.

이 Codelab에서는 다음 파일에 Matter 기능을 추가합니다.

  • java/commissioning/AppCommissioningService: 기기를 개발 패브릭에 의뢰할 수 있습니다.
  • java/screens/HomeFragmentjava/screens/HomeViewModel.kt: Home 모바일 SDK 수수료 기능 포함
  • java/screens/DeviceViewModel: Share Device API 호출 포함

각 파일에는 수정할 코드 블록이 있습니다. 예를 들면 다음과 같습니다.

// CODELAB: add commissioningFunction()

이를 통해 Codelab에서 상응하는 섹션을 빠르게 찾을 수 있습니다.

3. Google에 수수료 지급

기기를 제어하고 동일한 패브릭으로 서로 통신할 수 있도록 하려면, 먼저 이 의뢰인(위원은 이 샘플 애플리케이션, Matter용 Google Home 샘플 앱)의 의뢰를 받아야 합니다.

Matter 수수료에 관한 다음 개념을 이해하는 것이 중요합니다.

  • 패브릭을 사용하면 기기가 서로 통신할 수 있습니다.
  • Fabric은 공유된 고유 사용자 인증 정보 집합을 유지합니다.
  • 생태계는 신뢰할 수 있는 루트 인증서를 발급하고, 패브릭 ID를 할당하고, 고유한 노드 ID를 할당해야 합니다. 생태계는 감독자의 백엔드 서비스(예: Google Home 생태계의 홈 그래프)입니다.
  • 기기를 두 개 이상의 패브릭에 지정할 수 있습니다 (다중 관리자 기능).

기기를 수수료하려면 CommissioningClient API를 사용해야 합니다. .commissionDevice()를 호출하면 Google Play 서비스에서 적절한 활동을 실행하는 IntentSender가 반환됩니다.

interface CommissioningClient {
  Task<IntentSender> commissionDevice(CommissioningRequest request);
}

다음 섹션에서는 기기를 Google 패브릭에 의뢰하는 데 필요한 최소한의 코드를 살펴봅니다.

1단계: 활동 런처

CommissioningClient에서 IntentSender를 처리하려면 ActivityResultLauncher를 사용하면 됩니다.

private lateinit var commissioningLauncher: ActivityResultLauncher<IntentSenderRequest>
commissioningLauncher = registerForActivityResult(
    StartIntentSenderForResult()
) { result: ActivityResult ->
    if (result.resultCode == RESULT_OK) {
        Timber.d(TAG, "Commissioning succeeded.")
    } else {
        Timber.d(TAG, "Commissioning failed. " + result.resultCode)
    }
}

2단계: 수수료 함수

다음은 CommissioningClient API를 사용하여 기기를 Google 패브릭에 의뢰하는 기본 예시입니다.

  1. 커밋 프로세스는 commissionDevice() 함수로 시작합니다. 먼저 CommissioningRequest가 정의됩니다. 이 기본 구성을 사용하면 기기가 로컬 Android 패브릭에만 적용됩니다.
  2. Matter는 Home Mobile SDK의 진입점입니다. 다음 호출에서 .getCommissioningClientthis (Activity)의 CommissioningClient를 가져옵니다.
  3. .commissionDevice()CommissioningRequest를 허용합니다.
  4. 마지막으로 .addOnSuccessListener가 호출되어 CommissioningResult를 처리하고 Google Play 서비스 (GPS) 수수료 기기 활동을 실행합니다.
private fun commissionDevice() {
    val request: CommissioningRequest = CommissioningRequest.builder().build()
    Matter.getCommissioningClient(this)
        .commissionDevice(request)
        .addOnSuccessListener { result ->
            commissioningLauncher.launch(IntentSenderRequest.Builder(result).build())
        }
}

로컬 Android Fabric은 Android 설정을 통해 활용되어 기기를 다른 패브릭에 의뢰하는 프로세스를 간소화할 수 있습니다.

다음으로 기기를 개발 패브릭에 의뢰하는 방법을 알아봅니다.

의뢰 절차 중 사용자 인터페이스에 관한 개요는 법적 사안용 Google Home 샘플 앱 가이드를 참고하세요.

4. 개발 패브릭에 대한 수수료

기기에 2개 이상의 패브릭을 할당할 수 있습니다. 신뢰할 수 있는 페어링을 관리하기 위해 기기에는 다양한 FabricInfo 구성원이 포함된 FabricTable가 저장됩니다. 예를 들면 다음과 같습니다.

  • Fabric 식별
  • 패브릭이 기기에 할당한 노드 ID
  • 공급업체 ID
  • 패브릭 ID
  • 기기 운영 사용자 인증 정보

관리 도메인 관리자 (ADM)는 패브릭 사용자 인증 정보를 정의합니다. 이전 시나리오에서 Google Play 서비스는 신뢰할 수 있는 루트 인증 기관 (CA) 역할을 하는 생태계입니다. 기기를 로컬 Android 패브릭에 의뢰하면 모든 기기에 동일한 패브릭 사용자 인증 정보 세트와 동일한 CA 집합이 포함됩니다.

맞춤 커미션 서비스

로컬 Android 패브릭에 커밋하기 위해, 기본 매개변수를 사용해 CommissioningClient API에서 CommissioningRequest를 빌드했습니다.

val request: CommissioningRequest = CommissioningRequest.builder().build()

앱에서 새 기기를 제어하고 관리하려면 로컬 개발 패브릭을 만들고 기기를 위한 운영 사용자 인증 정보를 받아야 합니다. 이 시나리오에서 앱은 기기에 적절한 노드 사용자 인증 정보를 할당하는 고유하고 독립적인 생태계가 됩니다.

맞춤 서비스를 CommissioningRequest에 전달하여 나만의 패브릭에 기기를 의뢰할 것임을 Home Mobile SDK에 알릴 수 있습니다.

class CommissioningRequest {
  static CommissioningRequest.Builder builder();

  class Builder {
    Builder setCommissioningService(@Nullable ComponentName commissioningService);

    CommissioningRequest build();
  }
}

다음 단계에서는 커스텀 서비스를 사용하도록 commissionDevice() 함수를 수정합니다. 또한 홈 프래그먼트에 활동 런처를 추가하고 LiveData 객체를 사용하여 API 흐름을 관리하겠습니다.

1단계: GPS 활동 런처 만들기

먼저 CommissioningClient API에서 IntentSender를 처리할 활동 런처를 만들어 보겠습니다.

  1. java/screens/home/ 폴더에서 HomeFragment을 엽니다.
  2. // CODELAB: commissionDeviceLauncher declaration 주석을 다음 선언으로 바꿉니다.
    // The ActivityResult launcher that launches the "commissionDevice" activity in Google Play
    // Services.
    private lateinit var commissionDeviceLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  3. // CODELAB: commissionDeviceLauncher definition 주석을 다음 코드로 대체하여 수수료 활동 결과를 등록하고 처리합니다.
    commissionDeviceLauncher =
        registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
          // Commission Device Step 5.
          // The Commission Device activity in GPS has completed.
          val resultCode = result.resultCode
          if (resultCode == Activity.RESULT_OK) {
            Timber.d("CommissionDevice: Success")
            // We now need to capture the device information for the app's fabric.
            // Once this completes, a call is made to the viewModel to persist the information
            // about that device in the app.
            showNewDeviceAlertDialog(result)
          } else {
            viewModel.commissionDeviceFailed(resultCode)
          }
        }    ```
    
    

2단계: LiveData 객체 만들기

.commissionDevice() API의 성공 콜백은 Google Play 서비스에서 수수료 기기 활동을 실행하는 데 사용할 IntentSender를 제공합니다. HomeViewModel에서 이 API 호출의 결과를 보고할 두 개의 LiveData 객체를 만듭니다.

  • commissionDeviceStatus: TaskStatus를 추적합니다.
  • commissionDeviceIntentSender: .commissionDevice() 호출의 결과를 처리합니다. 이 LiveData 객체는 방금 만든 ActivityLauncher를 실행하고 사용자에게 GPS 수수료 기기 활동을 표시합니다.
  1. private fun setupObservers()에서 // CODELAB: commissionDeviceStatus 주석을 다음 관찰자로 바꿉니다.
    // The current status of the share device action.
    viewModel.commissionDeviceStatus.observe(viewLifecycleOwner) { status ->
      Timber.d("commissionDeviceStatus.observe: status [${status}]")
    }
    
  2. 그런 다음 // CODELAB: commissionDeviceIntentSender 주석을 다음 관찰자로 바꿉니다.
    viewModel.commissionDeviceIntentSender.observe(viewLifecycleOwner) { sender ->
      Timber.d(
          "commissionDeviceIntentSender.observe is called with [${intentSenderToString(sender)}]")
      if (sender != null) {
        // Commission Device Step 4: Launch the activity described in the IntentSender that
        // was returned in Step 3 (where the viewModel calls the GPS API to commission
        // the device).
        Timber.d("CommissionDevice: Launch GPS activity to commission device")
        commissionDeviceLauncher.launch(IntentSenderRequest.Builder(sender).build())
        viewModel.consumeCommissionDeviceIntentSender()
      }
    }
    

3단계: API 호출

이제 API 흐름을 처리하는 코드를 작성했으므로 API를 호출하고 맞춤 서비스를 전달하고 (다음 단계에서 정의함) LiveData 객체에 게시할 차례입니다.

  1. java/screens/home/ 폴더에서 HomeViewModel.kt을 엽니다.
  2. // CODELAB: commissionDevice 주석을 다음 commissionDeviceRequest으로 바꿉니다. setCommissioningServiceAppCommissioningServiceCommissioningService 인스턴스에 바인딩하여 콜백 함수로 반환합니다. 맞춤 서비스를 통과하면 Home Mobile SDK에서 먼저 기기를 Google 패브릭에 위탁한 다음 온보딩 페이로드를 AppCommissioningService에 다시 전송합니다.
    fun commissionDevice(context: Context) {
      _commissionDeviceStatus.postValue(TaskStatus.InProgress)
    
      val commissionDeviceRequest =
          CommissioningRequest.builder()
              .setCommissioningService(ComponentName(context, AppCommissioningService::class.java))
              .build()
    
  3. .getCommissioningClient()를 호출한 다음 .commissionDevice()를 호출합니다.
    Matter.getCommissioningClient(context)
        .commissionDevice(commissionDeviceRequest)
    

commissionDevice 함수를 완료하려면 addOnSuccessListeneraddOnFailureListener를 추가하고 LiveData 객체에 게시합니다.

      .addOnSuccessListener { result ->
        // Communication with fragment is via livedata
        _commissionDeviceIntentSender.postValue(result)
      }
      .addOnFailureListener { error ->
        Timber.e(error)
        _commissionDeviceStatus.postValue(
          TaskStatus.Failed("Failed to to get the IntentSender.", error)
      }
}

발신자를 사용한 후에는 구성 변경 후 발신자를 다시 수신하지 않도록 consumeCommissionDeviceIntentSender()를 호출해야 합니다.

  /**
   * Consumes the value in [_commissionDeviceIntentSender] and sets it back to null. Needs to be
   * called to avoid re-processing the IntentSender after a configuration change (where the LiveData
   * is re-posted).
   */
  fun consumeCommissionDeviceIntentSender() {
    _commissionDeviceIntentSender.postValue(null)
  }

5. 수수료 서비스 만들기

commissionDevice() 함수에서 CommissioningClient API를 통해 CommissioningService를 가져오도록 요청했습니다. 이 흐름에서 CommissioningClient API는 먼저 로컬 Android 패브릭에 기기를 커밋한 다음 CommissioningRequestMetadata 객체를 포함하는 콜백을 반환합니다.

public interface CommissioningService {
interface Callback {
    void onCommissioningRequested(CommissioningRequestMetadata metadata);
  }
}

이제 CommissioningService.Callback을 상속하고 샘플 앱에 기기를 의뢰하는 데 필요한 기능을 제공해야 합니다. 다음은 기본적인 CommissioningService 구현의 예입니다.

class MatterCommissioningService : Service(), CommissioningService.Callback {
   private val commissioningServiceDelegate =
     CommissioningService.Builder(this)
       .setCallback(this)
       .build()

   override fun onBind(intent: Intent) = commissioningServiceDelegate.asBinder()

   override fun onCommissioningRequested(metadata: CommissioningRequestMetadata) {
     // perform commissioning

     commissioningServiceDelegate
       .sendCommissioningComplete(CommissioningCompleteMetadata.builder().build())
   }
 }

1단계: 맞춤 AppCommissioningService 살펴보기

시작하는 데 도움이 되도록 맞춤 수수료 수수료의 기본 클래스 구조를 이미 정의해 두었습니다. 다음은 서비스 기능에 대한 간단한 개요입니다. 팔로우하려면 java/commissioning에서 AppCommissioningService 앱을 여세요.

Home Mobile SDK API에 다음 가져오기가 추가되었습니다.

import com.google.android.gms.home.matter.commissioning.CommissioningCompleteMetadata
import com.google.android.gms.home.matter.commissioning.CommissioningRequestMetadata
import com.google.android.gms.home.matter.commissioning.CommissioningService

AppCommissioningService에는 Matter 저장소 (connectedhomeip)의 라이브러리도 포함됩니다.

import com.google.home_sample_app_for_matter.chip.ChipClient

마지막으로 서비스에는 HiltKotlin 코루틴을 지원하는 가져오기가 포함됩니다.

다음으로, 생성자를 만들고 commissioningServiceDelegate를 포함한 몇 가지 항목을 설정합니다. 이를 통해 Google Play 서비스가 의뢰가 완료되면 이를 알려 줍니다.

private lateinit var commissioningServiceDelegate: CommissioningService
...
commissioningServiceDelegate = CommissioningService.Builder(this).setCallback(this).build()

이제 위탁 함수를 추가합니다.

2단계: onCommissioningRequested 재정의

앱을 앱의 개발 패브릭에 의뢰하려면 다음 단계를 완료하세요.

  1. java/commissioning에서 AppCommissioningService 앱을 엽니다.
  2. onCommissioningRequested() 함수를 찾습니다. CommissioningRequestMetadata를 출력하는 로그 메시지가 제공되었습니다. // CODELAB: onCommissioningRequested() 주석을 대체하여 serviceScope 코루틴을 시작하고 deviceId를 가져옵니다.
    // Perform commissioning on custom fabric for the sample app.
    serviceScope.launch {
      val deviceId = devicesRepository.incrementAndReturnLastDeviceId()
    
  3. 커미션을 수행합니다. 이 단계에서는 CommissioningRequestMetadata 객체에 반환된 기기 정보를 전달할 수 있습니다. ChipClient은 이 메타데이터 정보를 사용하여 Matter 앱용 GHSA 앱과 기기 간에 보안 채널을 만듭니다.
    Timber.d("Commissioning: App fabric -> ChipClient.establishPaseConnection(): deviceId [${deviceId}]")
    chipClient.awaitEstablishPaseConnection(
        deviceId,
        metadata.networkLocation.ipAddress.hostAddress!!,
        metadata.networkLocation.port,
        metadata.passcode)
    Timber.d("Commissioning: App fabric -> ChipClient.commissionDevice(): deviceId [${deviceId}]")
    chipClient.awaitCommissionDevice(deviceId, null)
    
  4. commissioningServiceDelegate를 사용하여 Google Play 서비스에 의뢰가 완료되었음을 알립니다. .sendCommissioningComplete()에서 CommissioningCompleteMetadata를 전달합니다.
      Timber.d("Commissioning: Calling commissioningServiceDelegate.sendCommissioningComplete()")
      commissioningServiceDelegate
          .sendCommissioningComplete(
              CommissioningCompleteMetadata.builder().setToken(deviceId.toString()).build())
          .addOnSuccessListener {
              Timber.d("Commissioning: OnSuccess for commissioningServiceDelegate.sendCommissioningComplete()")
          }
          .addOnFailureListener { ex -> 
            Timber.e(ex, "Commissioning: Failed to send commissioning complete.", ex)
          }
    }
    

앱 실행

이제 현지 직물에 필요한 모든 코드를 배치했으므로 테스트할 차례입니다. Android 기기를 선택하고 앱을 실행합니다. 홈 화면에서 기기 추가를 탭한 후 기기를 위임하는 단계를 완료합니다.

작업이 완료되면 기기에서 이제 로컬 Android 패브릭과 로컬 개발 패브릭 두 가지로 구성됩니다. 각 패브릭에는 고유한 사용자 인증 정보 세트와 고유한 64비트 패브릭 ID가 있습니다.

6. 기기 제어

개발 패브릭에 의뢰하면 Matter 저장소 (connectedhomeip)의 라이브러리를 사용하여 샘플 앱에서 기기를 제어할 수 있습니다.

기기 클러스터에 더 쉽게 액세스하고 명령어를 전송할 수 있도록 몇 가지 도우미 클래스를 만들었습니다. 자세히 알아보려면 java/clusters에서 ClustersHelper 페이지를 여세요. 이 싱글톤 도우미는 기기 정보에 액세스하기 위해 다음 라이브러리를 가져옵니다.

import chip.devicecontroller.ChipClusters
import chip.devicecontroller.ChipStructs

이 클래스를 사용하여 기기의 켜기/끄기 클러스터를 가져온 다음 .toggle를 호출할 수 있습니다.

suspend fun toggleDeviceStateOnOffCluster(deviceId: Long, endpoint: Int) {
  Timber.d("toggleDeviceStateOnOffCluster())")
  val connectedDevicePtr =
      try {
        chipClient.getConnectedDevicePointer(deviceId)
      } catch (e: IllegalStateException) {
        Timber.e("Can't get connectedDevicePointer.")
        return
      }
  return suspendCoroutine { continuation ->
    getOnOffClusterForDevice(connectedDevicePtr, endpoint)
        .toggle(
            object : ChipClusters.DefaultClusterCallback {
              override fun onSuccess() {
                continuation.resume(Unit)
              }
              override fun onError(ex: Exception) {
                Timber.e("readOnOffAttribute command failure: $ex")
                continuation.resumeWithException(ex)
              }
            })
  }
}

기기 전환

기기를 의뢰하면 CommissioningResult에 반환된 페이로드가 DataStore에 추가됩니다. 이렇게 하면 앱에서 명령어를 전송하는 데 사용할 수 있는 기기 정보에 액세스할 수 있습니다.

Matter 앱은 이벤트에 기반합니다. Matter 스택이 초기화되면 클러스터 서비스는 수신 메시지를 리슨합니다. 기기가 의뢰되면 Matter 클라이언트는 기기 시범 운영 중 설정된 보안 운영 채널을 통해 명령어를 전송합니다.

기기에서 패킷은 유효성 검사 및 복호화된 후 콜백과 함께 전달됩니다. 콜백 함수에는 attributePath에서 액세스할 수 있는 EndpointId, ClusterId, AttributeId가 포함됩니다. 예를 들어 Matter 기기에 다음 코드를 구현할 수 있습니다.

void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type,
                                       uint16_t size, uint8_t * value)
{
    // handle callback
    ClusterId clusterId     = attributePath.mClusterId;
    AttributeId attributeId = attributePath.mAttributeId;
}

다음 단계에서는 Matter SDK와 ClustersHelper를 사용하여 기기를 전환합니다.

  1. java/screens/deviceDeviceViewModel 페이지로 이동합니다.
  2. updateDeviceStateOn 함수를 찾습니다.
  3. // CODELAB: toggle 주석을 clustersHelper를 호출하는 코드로 바꾸고 기기 저장소를 업데이트합니다.
    Timber.d("Handling real device")
        try {
          clustersHelper.setOnOffDeviceStateOnOffCluster(deviceUiModel.device.deviceId, isOn, 1)
          devicesStateRepository.updateDeviceState(deviceUiModel.device.deviceId, true, isOn)
        } catch (e: Throwable) {
          Timber.e("Failed setting on/off state")
        }
    

이 함수는 DeviceFragment에서 호출됩니다.

// Change the on/off state of the device
binding.onoffSwitch.setOnClickListener {
  val isOn = binding.onoffSwitch.isChecked
  viewModel.updateDeviceStateOn(selectedDeviceViewModel.selectedDeviceLiveData.value!!, isOn)
}

앱 실행

앱을 실행하여 업데이트를 새로고침합니다. 홈 화면에서 기기를 켜거나 끕니다.

7. 다른 생태계와 기기 공유

Matter 사양에서는 기기를 공유하는 것을 다중 관리자 흐름이라고 합니다.

이전 단계에서는 Home Mobile SDK를 사용하여 로컬 Android 패브릭과 샘플 앱의 개발 패브릭에 기기를 의뢰할 수 있음을 배웠습니다. 이는 기기가 두 개 이상의 직물에 의뢰될 수 있는 다중 관리 흐름의 예입니다.

특히 패브릭이 더 많은 기기를 공유하고 싶을 수 있습니다. 특히 사람들이 애플리케이션 및 플랫폼에 관해 선호하는 취향이 있는 가정이라면 더욱 그렇습니다.

Home Mobile SDK는 ShareDeviceRequest API에서 이 기능을 제공하여 다음을 수행할 수 있습니다.

  1. 기기의 임시 수수료 창을 엽니다.
  2. 기기 상태를 변경하여 다른 패브릭에 의뢰할 수 있도록 합니다.
  3. 다른 앱 및 생태계에서 기기를 제어하세요.

다음 단계에서는 Home 모바일 SDK를 사용하여 기기를 공유합니다.

1단계: GPS 활동 런처 만들기

개발 패브릭에 의뢰할 때 만든 수수료 활동 런처와 비슷하게, CommissioningClient API에서 IntentSender를 처리하도록 Share Device Activity Launcher를 만들었습니다.

  1. java/screens/device/ 폴더에서 DeviceFragment을 엽니다.
  2. // CODELAB: shareDeviceLauncher definition 주석을 다음 코드로 대체하여 .shareDevice() 활동 결과를 등록하고 처리합니다.
    shareDeviceLauncher =
        registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
          // Share Device Step 5.
          // The Share Device activity in GPS (step 4) has completed.
          val resultCode = result.resultCode
          if (resultCode == RESULT_OK) {
            Timber.d("ShareDevice: Success")
            viewModel.shareDeviceSucceeded(selectedDeviceViewModel.selectedDeviceLiveData.value!!)
          } else {
            viewModel.shareDeviceFailed(
                selectedDeviceViewModel.selectedDeviceLiveData.value!!, resultCode)
          }
        }
    

2단계: LiveData 객체 검토

.shareDevice() API의 성공 콜백은 Google Play 서비스에서 기기 활동 공유 실행에 사용할 IntentSender를 제공합니다. DeviceViewModel에서 이 API 호출의 결과를 보고할 두 개의 LiveData 객체를 만들었습니다.

  • _shareDeviceStatus: TaskStatus를 추적합니다.
    // The current status of the share device action.
    viewModel.shareDeviceStatus.observe(viewLifecycleOwner) { status ->
      val isButtonEnabled = status !is InProgress
      updateShareDeviceButton(isButtonEnabled)
      if (status is TaskStatus.Failed) {
        showAlertDialog(errorAlertDialog, status.message, status.cause!!.toString())
      }
    }
    
  • _shareDeviceIntentSender: .sharedevice() 호출의 결과를 처리합니다.
    viewModel.shareDeviceIntentSender.observe(viewLifecycleOwner) { sender ->
      Timber.d("shareDeviceIntentSender.observe is called with [${intentSenderToString(sender)}]")
      if (sender != null) {
        // Share Device Step 4: Launch the activity described in the IntentSender that
        // was returned in Step 3 (where the viewModel calls the GPS API to commission
        // the device).
        Timber.d("ShareDevice: Launch GPS activity to share device")
        shareDeviceLauncher.launch(IntentSenderRequest.Builder(sender).build())
        viewModel.consumeShareDeviceIntentSender()
      }
    }
    

다음 단계에서는 .shareDevice() API 호출에 이러한 LiveData 객체를 사용합니다.

3단계: API 호출

이제 기기 공유 작업을 시작할 차례입니다.

  1. java/screens/device/ 폴더에서 DeviceViewModel.kt을 엽니다.
  2. shareDevice() 함수를 찾습니다. // CODELAB: shareDevice 주석을 ShareDeviceRequest로 바꿉니다. DeviceDescriptor는 공급업체 ID, 제품 ID, deviceType 등 기기에 관한 구체적인 정보를 제공합니다. 이 예시에서는 값을 하드 코딩합니다.
      Timber.d("ShareDevice: Setting up the IntentSender")
      val shareDeviceRequest =
          ShareDeviceRequest.builder()
              .setDeviceDescriptor(DeviceDescriptor.builder().build())
              .setDeviceName("temp device name")
    
  3. CommissioningWindow매개변수를 설정합니다. 이제 기기에 임시 수수료 기간 창이 열립니다.
              .setCommissioningWindow(
                  CommissioningWindow.builder()
                      .setDiscriminator(Discriminator.forLongValue(DISCRIMINATOR))
                      .setPasscode(SETUP_PIN_CODE)
                      .setWindowOpenMillis(SystemClock.elapsedRealtime())
                      .setDurationSeconds(OPEN_COMMISSIONING_WINDOW_DURATION_SECONDS.toLong())
                      .build())
              .build()
    
  4. .getCommissioningClient()를 호출합니다. 이번에는 .shareDevice() API를 사용합니다. commissioningClient.shareDevice() API의 성공 콜백은 Google Play 서비스에서 기기 활동 공유 실행에 사용할 IntentSender를 제공합니다.
    Matter.getCommissioningClient(activity)
        .shareDevice(shareDeviceRequest)
    
  5. shareDevice 함수를 완료하려면 addOnSuccessListeneraddOnFailureListener를 추가하고 LiveData 객체에 게시합니다.
          .addOnSuccessListener { result ->
            Timber.d("ShareDevice: Success getting the IntentSender: result [${result}]")
            // Communication with fragment is via livedata
            _backgroundWorkAlertDialogAction.postValue(BackgroundWorkAlertDialogAction.Hide)
            _shareDeviceIntentSender.postValue(result)
          }
          .addOnFailureListener { error ->
            Timber.e(error)
            _backgroundWorkAlertDialogAction.postValue(BackgroundWorkAlertDialogAction.Hide)
            _shareDeviceStatus.postValue(
                TaskStatus.Failed("Setting up the IntentSender failed", error))
          }
    

발신자를 사용한 후에는 구성 변경 후 발신자를 다시 수신하지 않도록 consumeShareDeviceIntentSender를 호출해야 합니다.

  /**
   * Consumes the value in [_shareDeviceIntentSender] and sets it back to null. Needs to be called
   * to avoid re-processing an IntentSender after a configuration change where the LiveData is
   * re-posted.
   */
  fun consumeShareDeviceIntentSender() {
    _shareDeviceIntentSender.postValue(null)
  }

앱 실행

Matter 기기를 다른 생태계와 공유하려면 Android 기기에 다른 플랫폼을 설치해야 합니다. 대상 수수료 사용자로 사용할 수 있는 샘플 앱의 다른 인스턴스를 만들었습니다.

Android 기기에 대상 커미셔너가 설치되면 Matter 기기를 공유할 수 있는지 확인합니다. 대상 수수료 입찰 앱은 GHSAFM-TC로 표시됩니다.

이제 기기에서 다음 세 가지 패브릭에 참여할 수 있습니다.

  1. 로컬 Android 패브릭
  2. 개발 패브릭 (이 앱)
  3. 방금 기기를 공유한 세 번째 패브릭입니다.

8. 다음 단계

축하합니다

축하합니다. 이 Codelab을 완료하고 Home Mobile SDK를 사용하여 기기를 의뢰하고 공유하는 방법을 배웠습니다.

샘플 앱에 문제가 있는 경우 다음 단계에 따라 환경을 확인하세요.

샘플 앱 사용과 관련된 질문이 있거나 코드 버그를 발견한 경우 GitHub 저장소의 Issue Tracker에 문제를 제출할 수 있습니다.

기술 관련 질문에 대해 Google의 공식 안내를 받으려면 스마트 홈 개발자 포럼을 사용하세요.

커뮤니티의 기술 지원을 받으려면 Stack Overflow에서 google-smart-home 태그를 사용하세요.