Android で Home API を使用してモバイルアプリを作成する

1. 始める前に

Google Home APIs は、Android デベロッパーが Google Home エコシステムを利用するための一連のライブラリを提供します。これらの新しい API を使用すると、デベロッパーはスマートホーム デバイスをシームレスにコミッショニングして制御するアプリを構築できます。

Google は、Google Home APIs を使用して動作例にアクセスしたいデベロッパー向けに Android サンプルアプリを提供しています。この Codelab は、権限、コミッショニング、デバイス、構造 API の使用方法を説明するサンプルアプリのブランチに基づいています。

前提条件

学習内容

  • ベスト プラクティスに沿って Google Home API を使用して Android アプリを構築する方法。
  • デバイス API と構造 API を使用してスマートホームを表現し、制御する方法。
  • Commissioning API を使用して Google Home エコシステムにデバイスを追加する方法。

省略可: 家を設定する

Google Home API を使用する前に、Google Home アプリを使用して Google アカウントで家をセットアップし、いくつかのデバイスを追加する必要があります。このセクションでは、仮想スマートホーム デバイスを提供する Google Home Playground を使用してこれを行う方法について説明します。

ウェブブラウザで home-playground.withgoogle.com を開き、Google アカウントでログインして、次のエミュレートされたデバイスが表示されるかどうかを確認します。

  • outlet1: オン/オフ プラグ
  • light2: 調光可能な照明
  • light3: オン/オフ ライト
  • ac3: エアコン
  • blinds4: Window Covering
  • washer5: スマート洗濯機

914d23a42b72df8f.png

モバイル デバイスで Google Home アプリを開き、[追加] ボタンをタップして、[Google Home と連携させる] を選択します。リストで「playground」を検索し、[Google Home Playground] プロジェクトを選択して、[続行] をタップします。

e9ec257b0d9b1ed2.png29fd7416e274d216.pngd974573af0611fd8.png

Google Home Playground にアカウントの承認ページが表示されます。[Authorize] または [Sign In with Google] をタップします。ウェブアプリで設定したすべてのデバイスがモバイルアプリに表示されます。

13108a3a15440151.png8791a6d33748f7c8.png

すべてのデバイスを選択して、セットアップ プロセスを完了します。[ホーム] ページに戻ると、利用可能なすべてのデバイスが表示されます。

2b021202e6fd1750.png

リストにある対応デバイスを Google Home API で使用できるようになりました。

2. プロジェクトをセットアップする

次の図は、Home APIs アプリのアーキテクチャを示しています。

Android アプリの Home API のアーキテクチャ

  • アプリコード: デベロッパーがアプリのユーザー インターフェースと Home APIs SDK とのやり取りのロジックを構築するために使用するコアコード。
  • Home APIs SDK: Google が提供する Home APIs SDK は、GMSCore の Home APIs Service と連携してスマートホーム デバイスを制御します。デベロッパーは、Home APIs SDK とバンドルすることで、Home APIs と連携するアプリを構築します。
  • Android の GMSCore: GMSCore(Google Play 開発者サービスとも呼ばれます)は、コア システム サービスを提供する Google プラットフォームであり、すべての認定済み Android デバイスで主要な機能を有効にします。Google Play 開発者サービスのホーム モジュールには、Home API とやり取りするサービスが含まれています。

Home SDK を設定する

SDK を設定するの手順に沿って、最新の SDK を入手します。

サンプルアプリを入手する

サンプルアプリのソースコードは GitHub で入手できます。この Codelab では、サンプルアプリの codelab-branch-1 ブランチの例を使用します。

プロジェクトを保存する場所に移動し、codelab-branch-1 ブランチのクローンを作成します。

$ git clone -b codelab-branch-1 https://github.com/google-home/google-home-api-sample-app-android.git

サンプルアプリをビルドする

アプリをビルドするの手順 1 ~ 5 を実行します。

32f2b3c0cd80fcf1.png

アプリがスマートフォンで正常に実行されると、サンプルアプリのメインページが表示されます。ただし、OAuth 認証を設定し、Permission API を使用して不足している部分を実装するまではログインできません。

3. 認証を設定する

Home API は OAuth 2.0 を使用して、構造内のデバイスへのアクセス権を付与します。OAuth を使用すると、ユーザーはログイン認証情報を公開することなく、アプリやサービスに権限を付与できます。

OAuth 同意を設定するの手順に沿って、同意画面を構成します。テスト アカウントを 1 つ以上作成してください。

次に、OAuth 認証情報を設定するの手順に沿って、アプリの認証情報を作成します。

4. 初期化と権限の処理

このセクションでは、Permissions API を使用して不足している部分を補完し、SDK を初期化してユーザー権限を処理する方法を説明します。

サポートされているタイプとトレイトを定義する

アプリを開発する際は、アプリがサポートするデバイスの種類とトレイトを明示的に記述する必要があります。サンプルアプリでは、HomeApp.kt のコンパニオン オブジェクトで静的リストを定義することで、これを行っています。これにより、必要に応じてアプリ全体で参照できます。

companion object {

  // List of supported device types by this app:
  val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
    OnOffLightDevice,
    DimmableLightDevice,

  // ...
  )
  // List of supported device traits by this app:
  val supportedTraits: List<TraitFactory<out Trait>> = listOf(
  OnOff,
  LevelControl,
  // ...
  )
}

サポートされているデバイスタイプとトレイトの完全なリストについては、サポートされているデバイスタイプAndroid のトレイト インデックスをご覧ください。

HomeApp.kt ソースファイルのステップ 4.1.1 と 4.1.2 のコメントを解除して、権限をリクエストするソースコードを有効にします。

companion object {
// List of supported device types by this app:
val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
// TODO: 4.1.1 - Non-registered device types will be unsupported
//             ContactSensorDevice,
//             ColorTemperatureLightDevice,
//             DimmableLightDevice,
//             ExtendedColorLightDevice,
//             GenericSwitchDevice,
//             GoogleDisplayDevice,
//             GoogleTVDevice,
//             OccupancySensorDevice,
//             OnOffLightDevice,
//             OnOffLightSwitchDevice,
//             OnOffPluginUnitDevice,
//             OnOffSensorDevice,
//             RootNodeDevice,
//             SpeakerDevice,
//             ThermostatDevice,
)
// List of supported device traits by this app:
val supportedTraits: List<TraitFactory<out Trait>> = listOf(
// TODO: 4.1.2 - Non-registered traits will be unsupported
//             AreaAttendanceState,
//             AreaPresenceState,
//             Assistant,
//             AssistantBroadcast,
//             AssistantFulfillment,
//             BasicInformation,
//             BooleanState,
//             OccupancySensing,
//             OnOff,
//             Notification,
//             LevelControl,
//             TemperatureControl,
//             TemperatureMeasurement,
//             Thermostat,
//             Time,
//             Volume,
        )
}

HomeClient オブジェクトを初期化する

Home API を使用するすべてのアプリは、API とやり取りするためのメイン インターフェースである HomeClient オブジェクトを初期化します。このオブジェクトは、HomeAppHomeApp.kt)クラスのイニシャライザで準備します。

// Registry to record device types and traits used in this app:
val registry = FactoryRegistry(
  types = supportedTypes,
  traits = supportedTraits
)
// Configuration options for the HomeClient:
val config = HomeConfig(
  coroutineContext = Dispatchers.IO,
  factoryRegistry = registry
)
// Initialize the HomeClient, which is the primary object to use all Home APIs:
homeClient = Home.getClient(context = context, homeConfig = config)

まず、前に定義したサポートされている型とトレイトを使用して FactoryRegistry を作成します。次に、このレジストリを使用して、API の実行に必要な構成を含む HomeConfig を初期化します。次に、Home.getClient(...) 呼び出しを使用して HomeClient インスタンスを取得します。

Home API とのやり取りはすべて、この HomeClient オブジェクトを介して行われます。

Permissions API を使用する

Home APIs のユーザー認証は Permissions API を介して行われます。サンプルアプリの PermissionsManager.kt ソースファイルには、ユーザー認証用のコードが含まれています。checkPermissions(...) 関数と requestPermissions(...) 関数の内容のコメントを解除して、サンプルアプリの権限を有効にします。

登録:

homeClient.registerActivityResultCallerForPermissions(activity)

リリース:

try {
    val result: PermissionsResult
    result = homeClient.requestPermissions(forceLaunch = true)
    when (result.status) {
        PermissionsResultStatus.SUCCESS -> // Success Case
        PermissionsResultStatus.CANCELLED -> // User Cancelled
        PermissionsResultStatus.ERROR -> // Some Error
else -> // Unsupported Case
    }
}
catch (e: HomeException) { ... }

確認:

try {
    val state: PermissionsState
    state = homeClient.hasPermissions().first { state ->
        state != PermissionsState.PERMISSIONS_STATE_UNINITIALIZED
    }
    when (state) {
        PermissionsState.GRANTED -> // Signed In
        PermissionsState.NOT_GRANTED -> // Not Signed In
        PermissionsState.PERMISSIONS_STATE_UNAVAILABLE -> // ...
        PermissionsState.PERMISSIONS_STATE_UNINITIALIZED -> // ...
else -> // Unsupported case
    }
}
catch (e: HomeException) { ... }

サブスクライブ:

       homeClient.hasPermissions().collect( { state ->
// Track the changes on state
        } )

PermissionsManager.kt のステップ 4.3.1 のコメントを解除して、権限をリクエストするコードを有効にします。

fun requestPermissions() {
    scope.launch {
    try {
// TODO: 4.3.1 - Request the permissions from the Permissions API
//                 // Request permissions from the Permissions API and record the result:
//                 val result: PermissionsResult = client.requestPermissions(forceLaunch = true)
//                 // Adjust the sign-in status according to permission result:
//                 if (result.status == PermissionsResultStatus.SUCCESS)
//                     isSignedIn.emit(true)
//                 // Report the permission result:
//                 reportPermissionResult(result)
    }
    catch (e: HomeException) { MainActivity.showError(this, e.message.toString()) }
    }
}

手順に沿って、スマートフォンでアプリを実行し、権限を許可します。次のフローが表示されます。

c263dcee4e945bf1.png f518cfd1fdb8a9d8.png 59937372f28c472f.png 383073ae57d2ced4.png 89f774a2ba6898ae.png

「読み込み中」のメッセージが消えませんが、これは構造とデバイスを読み取るコードを実装していないためです。次のセクションで説明します。

5. データモデルを理解する

Home API では、データモデルは次の要素で構成されます。

  • Structure は、部屋とデバイスを含む家を表します。
  • Room はストラクチャの一部であり、デバイスが含まれています。
  • デバイス(HomeDevice として定義)は、ストラクチャ(または家)またはストラクチャ内の部屋に割り当てることができます。
  • デバイスは 1 つ以上の DeviceType インスタンスで構成されます。
  • DeviceTypeTrait インスタンスで構成されています。
  • Trait は、Attribute インスタンス(読み取り/書き込み用)、Command インスタンス(属性の制御用)、Event インスタンス(過去の変更のレコードの読み取りまたはサブスクライブ用)で構成されます。
  • Automation インスタンスはストラクチャの一部であり、家のメタデータとデバイスを使用して家のタスクを自動化します。

76d35b44d5a8035e.png

このセクションでは、構造 API を使用して家の構造、部屋、デバイスなどを解析してレンダリングする方法を示すソースコードを開発する方法について説明します。

ストラクチャの読み取り

Home API の設計は、データモデル オブジェクト(StructureHomeDevice など)をストリーミング出力する Kotlin Flow に基づいています。デベロッパーは Flow をサブスクライブして、オブジェクトに含まれるすべてのオブジェクト(StructureRoom など)を取得します。

すべての構造体を取得するには、構造体のフローを返す structures() 関数を呼び出します。次に、フローでリスト関数を呼び出して、ユーザーが所有するすべての構造体を取得します。

// Get the a snapshot of all structures from the current homeClient
val allStructures : Set<Structure> =
    homeClient.structures()   // HomeObjectsFlow<Structure>
    .list()                   // Set<Structure>

アプリ アーキテクチャ ガイドでは、アプリのデータフローと状態管理を改善するために、最新のリアクティブ プログラミング アプローチを採用することを強く推奨しています。

サンプルアプリがリアクティブ コーディング スタイルに準拠している方法は次のとおりです。

  • ビューモデル(状態ホルダーとしての StructureViewModelDeviceViewModel など)は、Home APIs SDK のフローをサブスクライブして値の変更を受け取り、最新の状態を維持します。
  • ビュー(StructureViewDeviceView など)は、ビューモデルをサブスクライブして状態を受け取り、それらの変更を反映するように UI をレンダリングします。
  • ユーザーがビューのボタン(照明デバイスの [オン] ボタンなど)をクリックすると、イベントによってビューモデルの関数がトリガーされ、対応する Home API 関数(OnOff トレイトの On コマンドなど)が呼び出されます。

HomeAppViewModel.kt のステップ 5.1.1 で、collect() 関数を呼び出して構造変更イベントをサブスクライブします。Structures API レスポンスから返され、StructureViewModel's StateFlow で配信される structureSet をトラバースするセクションのコメントを解除します。これにより、アプリは構造の状態の変化をモニタリングできます。

   private suspend fun subscribeToStructures() {
// TODO: 5.1.1 - Subscribe the structure data changes
// // Subscribe to structures returned by the Structures API:
// homeApp.homeClient.structures().collect { structureSet ->
//     val structureVMList: MutableList<StructureViewModel> = mutableListOf()
//     // Store structures in container ViewModels:
//     for (structure in structureSet) {
//         structureVMList.add(StructureViewModel(structure))
//     }
//     // Store the ViewModels:
//     structureVMs.emit(structureVMList)
//
//     // If a structure isn't selected yet, select the first structure from the list:
//     if (selectedStructureVM.value == null && structureVMList.isNotEmpty())
//         selectedStructureVM.emit(structureVMList.first())
//
// }
}

DevicesView.kt では、アプリは StructureViewModel'sStateFlow, をサブスクライブし、構造データが変更されたときに UI の再コンポーズをトリガーします。手順 5.1.2 のソースコードのコメントを解除して、構造リストをプルダウン メニューとしてレンダリングします。

   val structureVMs: List<StructureViewModel> = homeAppVM.structureVMs.collectAsState().value
...
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
// TODO: 5.1.2 - Show list of structures in DropdownMenu
//  for (structure in structureVMs) {
//      DropdownMenuItem(
//          text = { Text(structure.name) },
//          onClick = {
//              scope.launch { homeAppVM.selectedStructureVM.emit(structure) }
//              expanded = false
//          }
//      )
//  }
}
...

アプリを再度実行すると、矢印をタップすると、メニューが表示されます。

f1fc2be1cb6436b6.png

構造を解析する

次のステップでは、ストラクチャ内のホーム オブジェクトをトラバースします。ストラクチャから部屋を取得します。

val rooms: Set<Room>
rooms = structure.rooms().list()

次に、部屋をトラバースしてデバイスを取得できます。

val devices: Set<HomeDevice>
devices = room.devices().list()

重要: Home APIs データモデルでは、構造に部屋に割り当てられていないデバイスを含めることができます。そのため、部屋のないデバイスもアプリでキャプチャするようにしてください。

val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()

for (device in structure.devices().list())
if (device.roomId == null)
  devicesWithoutRooms.add(device)

既存のサンプルコードでは、フローをサブスクライブして最新の Room とデバイスのリストを取得しています。StructureViewModel.kt ソースファイルのステップ 5.2.1 と 5.2.2 のコードを確認し、コメントを解除して、ルームデータのサブスクリプションを有効にします。

val roomVMs : MutableStateFlow<List<RoomViewModel>>
val deviceVMs : MutableStateFlow<List<DeviceViewModel>>
val deviceVMsWithoutRooms : MutableStateFlow<List<DeviceViewModel>>
private suspend fun subscribeToRooms() {
// TODO: 5.2.1 - Subscribe the room data changes
//   // Subscribe to changes on rooms:
//   structure.rooms().collect { roomSet ->
//       val roomVMs = mutableListOf<RoomViewModel>()
//       // Store rooms in container ViewModels:
//       for (room in roomSet) {
//           roomVMs.add(RoomViewModel(room))
//       }
//       // Store the ViewModels:
//       this.roomVMs.emit(roomVMs)
//   }
}
private suspend fun subscribeToDevices() {
// TODO: 5.2.2 - Subscribe the device data changes in a structure
//   // Subscribe to changes on devices:
//   structure.devices().collect { deviceSet ->
//       val deviceVMs = mutableListOf<DeviceViewModel>()
//       val deviceWithoutRoomVMs = mutableListOf<DeviceViewModel>()
//       // Store devices in container ViewModels:
//       for (device in deviceSet) {
//           val deviceVM = DeviceViewModel(device)
//           deviceVMs.add(deviceVM)
//           // For any device that's not in a room, additionally keep track of a separate list:
//           if (device.roomId == null)
//               deviceWithoutRoomVMs.add(deviceVM)
//       }
//       // Store the ViewModels:
//       this.deviceVMs.emit(deviceVMs)
//       deviceVMsWithoutRooms.emit(deviceWithoutRoomVMs)
//   }
    }

DevicesView.kt ソースファイルのステップ 5.2.3 と 5.2.4 をコメント解除して、会議室リストをメニューとしてレンダリングします。

val selectedRoomVMs: List<RoomViewModel> =
selectedStructureVM.roomVMs.collectAsState().value
...
for (roomVM in selectedRoomVMs) {
// TODO: 5.2.3 - Render the list of rooms
//   RoomListItem(roomVM)
// TODO: 5.2.4 - Render the list of devices in a room
//   val deviceVMsInRoom: List<DeviceViewModel> = roomVM.deviceVMs.collectAsState().value
//
//   for (deviceVM in deviceVMsInRoom) {
//       DeviceListItem(deviceVM, homeAppVM)
//   }
}

デバイスを入手したので、デバイスの操作方法を学習しましょう。

e715ddda50e04839.png

6. デバイスを操作する

Home API は、HomeDevice オブジェクトを使用してデバイスとその機能をキャプチャします。デベロッパーはデバイス属性を登録し、アプリでスマートホーム デバイスを表すために使用できます。

デバイスの状態を読み取る

HomeDevice オブジェクトは、デバイス名や接続状態などの静的な値のセットを表します。デベロッパーは、デバイスを API から取得した直後に、これらの情報を取得できます。

val id: String = device.id.id
val name: String = device.name
val connectivity: ConnectivityState =
    device.sourceConnectivity.connectivityState

デバイスの機能を取得するには、HomeDevice からタイプとトレイトを取得する必要があります。これを行うには、次のようにデバイスタイプ フローをサブスクライブし、デバイスタイプからトレイトを取得します。

device.types().collect { typeSet ->
var primaryType : DeviceType = UnknownDeviceType()
for (typeInSet in typeSet)
if (typeInSet.metadata.isPrimaryType)
                    primaryType = typeInSet
            val traits: List<Trait> = mutableListOf()
for (trait in primaryType.traits())
if (trait.factory in myTraits)
                    traits.add(trait)
for (trait in traits)
                parseTrait(trait, primaryType)
        }

各デバイスには、サポートされている DeviceType(バンドルされた機能)のセットが含まれています。このセットは、device.types() を使用して取得できます。これらのデバイスタイプには、type.traits() を使用して取得できるトレイトが含まれています。すべてのデバイスは、アプリで表現する必要があるタイプをプライマリ タイプとしてマークします(type.metadata.isPrimaryType を使用して確認できます)。ユーザーに完全なエクスペリエンスを提供するには、返されたすべてのタイプをトラバースし、利用可能なすべてのトレイトを統合することをおすすめします。

特性を取得したら、次のような関数を使用して解析し、値を解釈できます。

fun <T : Trait?> parseTrait(trait : T, type: DeviceType) {
    val status : String = when (trait) {
        is OnOff -> { if (trait.onOff) "On" else "Off" }
        is LevelControl -> { trait.currentLevel.toString() }
        is BooleanState -> {
            when (type.factory) {
                ContactSensorDevice -> {
if (trait.stateValue) "Closed"
else "Open"
                }
else -> ...
            }
        }
else -> ...
    }
}

トレイトが表す内容は、トレイトを備えているデバイスタイプによって異なる場合があります(前の例の BooleanState を参照)。そのため、トレイトが実際に表す内容を理解するには、各デバイスタイプのコンテキストを把握する必要があります。

DeviceViewModel.kt ソースファイルで手順 6.1.1 と 6.1.2 のコメントを解除して、状態を取得します。

private suspend fun subscribeToType() {
// Subscribe to changes on device type, and the traits/attributes within:
device.types().collect { typeSet ->
// Container for the primary type for this device:
var primaryType : DeviceType = UnknownDeviceType()
...
// TODO: 6.1.1 - Determine the primary type for this device
//       // Among all the types returned for this device, find the primary one:
//       for (typeInSet in typeSet)
//           if (typeInSet.metadata.isPrimaryType)
//               primaryType = typeInSet
//
//       // Optional: For devices with a single type that did not define a primary:
//       if (primaryType is UnknownDeviceType && typeSet.size == 1)
//           primaryType = typeSet.first()
// Container for list of supported traits present on the primary device type:
val supportedTraits: List<Trait> = getSupportedTraits(primaryType.traits())
...
}
fun getSupportedTraits(traits: Set<Trait>) : List<Trait> {
           val supportedTraits: MutableList<Trait> = mutableListOf()
// TODO: 6.1.2 - Get only the supported traits for this device
//   for (trait in traits)
//       if (trait.factory in HomeApp.supportedTraits)
//           supportedTraits.add(trait)
return supportedTraits
}

DeviceView.kt のステップ 6.1.3 のコメントを解除して、名前やステータスなどの OnOff トレイトを String としてレンダリングします。

Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
// TODO: 6.1.3 - Render controls based on the trait type
// Column (Modifier.fillMaxWidth()) {
//     Text(trait.factory.toString(), fontSize = 20.sp)
//     Text(DeviceViewModel.getTraitStatus(trait, type), fontSize = 16.sp)
// }
...
}
is LevelControl -> {
      ...
  }
   is BooleanState -> {
      ...
  }
   is OccupancySensing -> {
      ...
  }
  ...
}

サポートされているデバイスタイプ(照明デバイスなど)でアプリを実行すると、すべてのデバイスの最新の状態が表示されます。

1bd8b3b2796c4c7a.png

デバイスのコマンドを発行する

デバイスにコマンドを発行するために、Home API は trait.on()trait.moveToLevel(...) などの Trait オブジェクトに便利な関数を提供します。

fun <T : Trait?> issueCommand(trait : T) {
     when (trait) {
         is OnOff -> {
// trait.on()
// trait.off()
   }
   is LevelControl -> {
// trait.moveToLevel(...)
// trait.moveToLevelWithOnOff(...)
        }
    }
}

ヒント: トレイトのタイプを特定したら、Android Studio の予測入力機能を使用して、トレイトを操作するために使用できるアクションの種類を確認します。

DeviceView.kt のステップ 6.2.1 のコメントを解除して、アプリに機能制御を追加します。

Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
                ....
// TODO: 6.2.1 - Render controls based on the trait type
//   Switch (checked = (trait.onOff == true), modifier = Modifier.align(Alignment.CenterEnd),
//       onCheckedChange = { state ->
//           scope.launch { if (state) trait.on() else trait.off() }
//       },
//       enabled = isConnected
//   )
}

アプリを実行すると、現実世界の物理デバイスを制御できるようになります。

電球の OnOff コントロールをタップすると、デバイスがオンになります。

c8ed3ecf5031546e.png

デバイスを制御する方法について詳しくは、Android でデバイスを制御するをご覧ください。

7. デバイスをコミッショニングする

Commissioning API を使用すると、デベロッパーはデバイスを Google Home エコシステムに追加し、Home API を使用して制御できるようにすることができます。Matter デバイスのみがサポートされています。このセクションでは、アプリでデバイスのコミッショニングを有効にする方法について説明します。

このセクションを開始する前に、次の前提条件を満たしていることを確認してください。

コミッショニング用の QR コード付きの物理 Matter デバイスがある場合は、コミッショニング API を有効にするに進んでください。それ以外の場合は、次のセクションに進んでください。ここでは、Matter Virtual Device アプリ(MVD)を使用してコミッショニング可能な仮想デバイスを作成する方法について説明します。

省略可: Matter のコミッショニング可能なデバイスを準備する

Matter のコミッショニング可能なデバイスを準備する最も簡単な方法は、Matter Virtual Device アプリ(MVD)が提供するエミュレートされたデバイスを使用することです。

MVD をインストールしてファイアウォールを設定したら、MVD を実行します。

b20283893073ac1b.png

OnOff デバイスを作成します。まだコミッショニングされていないことに注意してください。この Codelab で後ほどコミッショニングします。

5f4855b808312898.png

Commissioning API を有効にする

Commissioning API はアプリの Activity の外部で動作するため、コミッショニングは他の Home API とは異なる方法で処理する必要があります。アプリをコミッショニングの準備をするには、2 つの変数が必要です。

1 つの変数は ActivityResultLauncher で、コミッショニング インテントの送信と結果コールバックの管理に使用されます。もう 1 つの変数は CommissioningResult です。これは、コミッショニングの結果を保存するために使用されるオブジェクトです。コミッショニングの設定方法については、次の例をご覧ください。

var launcher: ActivityResultLauncher<IntentSenderRequest>
lateinit var commissioningResult: CommissioningResult?
launcher = activity.registerForActivityResult(StartIntentSenderForResult()) { result ->
try {
  commissioningResult = CommissioningResult.fromIntentSenderResult(
      result.resultCode, result.data)
  } catch (exception: ApiException) {
// Catch any issues
 }
}

コミッショニング フローを設定したら、コミッショニング インテントをビルドし、前の例で作成したランチャーを使用して起動します。インテントとランチャーは、次のような専用の関数に配置することをおすすめします。専用の関数を UI 要素([+Add Device] ボタンなど)に関連付け、ユーザー リクエストに基づいて呼び出すことができます。

fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
  scope.launch {
    // Create a commissioning request to store the device in Google's Fabric:
    val request = CommissioningRequest.builder()
      .setStoreToGoogleFabric(true)
      .setOnboardingPayload(payload)
      .build()
    // Initialize client and sender for commissioning intent:
    val client: CommissioningClient = Matter.getCommissioningClient(context)
    val sender: IntentSender = client.commissionDevice(request).await()
    // Launch the commissioning intent on the launcher:
    launcher.launch(IntentSenderRequest.Builder(sender).build())
  }
}

CommissioningManager.kt のステップ 7.1.1 のコメントを解除して、コミッショニング機能を有効にし、サンプルアプリで [+Add Device] ボタンが機能するようにします。

// Called by +Add Device button in DeviceView.kt
fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
// TODO: 7.1.1 - Launch the commissioning intent
// scope.launch {
//     // Create a commissioning request to store the device in Google's Fabric:
//     val request = CommissioningRequest.builder()
//         .setStoreToGoogleFabric(true)
//         .setOnboardingPayload(payload)
//         .build()
//     // Initialize client and sender for commissioning intent:
//     val client: CommissioningClient = Matter.getCommissioningClient(context)
//     val sender: IntentSender = client.commissionDevice(request).await()
//     // Launch the commissioning intent on the launcher:
//     launcher.launch(IntentSenderRequest.Builder(sender).build())
// }
}

この関数を実行すると、コミッショニング フローが開始され、次のスクリーンショットのような画面が表示されます。

baae45588f460664.png

コミッショニング フローを理解する

コミッショニング フローには、ユーザーがデバイスを Google アカウントに追加する手順を案内する一連の画面が含まれています。

2fb0404820d4a035.png 3cbfa8ff9cfd5ee4.png a177c197ee7a67bf.png 3fdef24672c77c0.png dec8e599f9aa119.png

ユーザーには QR コード スキャナが表示され、Matter デバイスの QR コードをスキャンできます。その後、ユーザー契約の表示、デバイスの検出とコミッショニング、デバイスの名前付けのフローに進みます。フローが完了すると、フォーカスがアプリに戻り、前のセクションで作成したコールバック関数でコミッショニングの結果が渡されます。

Commissioning API の利点の 1 つは、UX フローが SDK によって処理されるため、デベロッパーが非常に迅速にセットアップして実行できることです。また、ユーザーがさまざまなアプリでデバイスを追加する際にも、一貫したエクスペリエンスを提供できます。

コミッショニング API について詳しくは、Android のコミッショニング API をご覧ください。

8. 完了

これで、Google Home APIs を使用して Android アプリが正常に作成されました。この Codelab では、Permissions API、Devices API、Structures API、Commissioning API について説明しました。次の Codelab「Android で Home API を使用して高度な自動化を作成する」では、Automation API と Discovery API を詳しく見て、アプリを完成させます。

Google Home エコシステム内のデバイスをクリエイティブに制御するアプリの開発をお楽しみください。

次のステップ