Android Matter SDK

A complete guide to Matter development with Google Home APIs and connectedhomeip.

Matter 1.4.1Android 8.1+GA

Overview

Android Matter development involves three SDK layers: Google's high-level APIs (commissioning and device management), the open-source connectedhomeip (protocol stack and Cluster control), and the Thread Network SDK.

In August 2026, Google Home APIs reached GA (v1.10.1), providing a unified interface for commissioning, device control, and automation. New projects should use the Home APIs directly; existing projects can continue with the Legacy Mobile SDK.

SDK Selection

Choose the right SDK combination for your project needs:

SDKMaven ArtifactCapabilitiesBest For
Home APIs (New)play-services-home:17.0.0 + play-services-home-types:17.0.0Commission + Control + AutomationNew projects
Legacy Mobile SDKplay-services-home:16.0.0Commissioning and sharing onlyExisting projects
connectedhomeipBuild from source / demo SDKFull protocol stack, cluster-level controlCustom fabric / non-GPS devices
Thread Network SDKplay-services-threadnetwork:16.2.1Thread credential managementThread device pairing

Commissioning Flow

Android commissioning uses a two-layer architecture: Google Play Services handles BLE discovery, PASE session, and network provisioning; then it calls back into your CommissioningService for fabric enrollment.

1User scans QR code
2App calls CommissioningClient.commissionDevice()
3GPS discovers device via BLE, establishes PASE session
4GPS provisions WiFi/Thread credentials, device joins network
5GPS issues NOC, device joins Android fabric
6Callback to your CommissioningService.onCommissioningRequested()
7Your app commissions to your own fabric via ChipDeviceController
8Call sendCommissioningComplete() to finish

Device Control

After commissioning, control devices through the connectedhomeip Cluster API. Each Matter Cluster maps to a Java/Kotlin class.

kotlinOnOff Control Example
// Get connected device pointer
val devicePtr = suspendCoroutine<Long> { cont ->
    controller.getConnectedDevicePointer(nodeId,
        object : GetConnectedDeviceCallback {
            override fun onDeviceConnected(ptr: Long) = cont.resume(ptr)
            override fun onConnectionFailure(id: Long, e: Exception) =
                cont.resumeWithException(e)
        })
}

// Create OnOff cluster instance and send command
val cluster = ChipClusters.OnOffCluster(devicePtr, endpointId)
cluster.toggle(object : ChipClusters.DefaultClusterCallback {
    override fun onSuccess() { /* device toggled */ }
    override fun onError(ex: Exception) { /* handle error */ }
})

Reading device types and capabilities

After commissioning, read the Descriptor cluster (0x001D) to learn which endpoints the device has, what type each endpoint is and which clusters it contains. Then read each cluster's FeatureMap / AcceptedCommandList for the exact capabilities. See Concepts · Reading a device's capabilities for what each field means, and translate the numbers with the Matter ID Lookup.

kotlinReading Descriptor and FeatureMap
// 1. PartsList on endpoint 0: which endpoints exist
val root = ChipClusters.DescriptorCluster(devicePtr, 0)
root.readPartsListAttribute(object :
    ChipClusters.DescriptorCluster.PartsListAttributeCallback {
    override fun onSuccess(endpoints: List<Int>) {
        endpoints.forEach { ep -> readEndpoint(devicePtr, ep) }
    }
    override fun onError(ex: Exception) { /* handle error */ }
})

// 2. DeviceTypeList / ServerList on each endpoint: what it is, which clusters
fun readEndpoint(devicePtr: Long, ep: Int) {
    val descriptor = ChipClusters.DescriptorCluster(devicePtr, ep)
    descriptor.readDeviceTypeListAttribute(object :
        ChipClusters.DescriptorCluster.DeviceTypeListAttributeCallback {
        override fun onSuccess(types: List<ChipStructs.DescriptorClusterDeviceTypeStruct>) {
            // A lock endpoint returns 0x000A (Door Lock) and 0x0011 (Power Source)
            types.forEach { Log.d(TAG, "EP$ep type=0x%04X rev=%d".format(it.deviceType, it.revision)) }
        }
        override fun onError(ex: Exception) {}
    })
    descriptor.readServerListAttribute(object :
        ChipClusters.DescriptorCluster.ServerListAttributeCallback {
        override fun onSuccess(clusters: List<Long>) { /* e.g. [3, 29, 47, 257] */ }
        override fun onError(ex: Exception) {}
    })
}

// 3. Optional features of a cluster: FeatureMap (global attribute 0xFFFC)
ChipClusters.DoorLockCluster(devicePtr, 1).readFeatureMapAttribute(object :
    ChipClusters.LongAttributeCallback {
    override fun onSuccess(value: Long) {
        val supportsFingerprint = (value and (1L shl 2)) != 0L  // bit 2 = FGP
    }
    override fun onError(ex: Exception) {}
})

Limitations & Caveats

Key issues to watch out for in Android Matter development:

Google Play Services Dependency

GPS is mandatory for the Google commissioning flow. Devices without GMS (Huawei, Amazon Fire, custom ROMs) cannot use it — use connectedhomeip directly instead.

Commissioning Window Timeout

Matter devices keep their commissioning window open for 3-5 minutes. If SDK initialization takes too long, the window expires before PASE starts. Pre-warm the SDK.

Controller Conflict

Creating a control ChipDeviceController while a commissioning one is active causes a native platform conflict and SIGABRT. Gate control operations behind a commissioningInProgress flag.

GPS Version Requirements

Home APIs need GPS 26.34.30+, Legacy SDK needs 22.50.14+. Older devices stuck on old GPS versions will silently fail.

Thread Credential Issues

Phone may lack Thread credentials needed for pairing, producing "Thread border router required" errors even when a border router exists on the network.

Missing sendCommissioningComplete()

Forgetting to call this method in your CommissioningService silently fails the entire flow. Not clearly documented.

Resources