A Matter commissioning and control companion app by Nordic Semiconductor, built with Kotlin Multiplatform and Compose Multiplatform, with the iOS-specific implementation written in Swift.
The app lets you:
- Commission new Matter devices onto your fabric:
- Android — via the Android Home API / Google Play Services, provisioning the device onto both the Google Home fabric and the app’s local fabric.
- iOS — via Apple's
MatterSupportframework (MatterAddDeviceRequest), onto a local fabric managed directly by the app itself (usingMatter.framework/MTRDeviceController), with a bundled app extension providing the system QR-code scanning UI.
- Control commissioned devices — door locks, lights, switches, and manufacturer-specific clusters.
- Manage bindings between devices, e.g. a switch controlling a light.
- View logs for diagnosing commissioning and cluster interactions.
The apps for working need a Matter-enabled device. There are 2 common ways of getting such a device.
- Using a Matter Virtual Device. It works over a local network, and it's easier to set up.
- Using one of Nordic's DKs. It will require a working Thread Border Router accessible in a local network.
Those 2 approaches are explained in detail in below section.
If you don't have a Thread Border Router or physical accessory handy, Google's Matter Virtual Device (MVD) tool lets you commission a simulated Matter accessory from a Mac or Linux devices instead. The nRF Matter implementation currently supports only a subset of the device types available in the Matter Virtual Device application:
- Dimmable Light
- Door Lock
To explore and test additional device types, a compatible Nordic development kit (DK) is required.
- Download the MVD
.dmgfor your Mac (Apple Silicon or Intel) and drag it intoApplications. The Matter Virtual Device (MVD) can be downloaded from the official Google Home developer resources here. - Launch MVD and configure the simulated accessory (device type, name, discriminator, Matter port, test VID/PID). After launching the application, the initial screen will look like this:
- Commission it from this app like a real device — it shows a QR code and joins over the macOS existing Wi-Fi connection.
- The Mac running MVD and the phone must be on the same Wi-Fi network.
- Once commissioned, you can control the simulated device from this app.
Another option is to configure a Nordic Semiconductor development kit (DK) to act as a Matter device using one of the available Matter samples. The samples can be installed using the Matter Quick Start app which is a part of nRF Connect For Desktop.
- Door Lock — available directly in the Matter Quick Start App.
- Light — available directly in the Matter Quick Start App.
- Switch - build this sample in Visual Studio.
- Manufacturer specific cluster + cluster extension - build this sample in Visual Studio.
Tip
All examples display a link with a QR code required for commissioning in the logs. The logs from a DK can be viewed using the Serial Terminal app. To view the logs, open the Serial Terminal app and connect the DK using the appropriate serial terminal port. If the device has not yet been commissioned, press the reset button on the DK. The device will then print the logs, including the QR code link, in the logs panel.
Commissioning a Thread Matter device requires a Thread Border Router already running on the local network, and Thread network credentials available on the phone. Setup code is not part of this repository — it relies on the OS-provided home hub infrastructure, which is configured once per network before the app is used.
Matter examples installed on DKs require a Thread Border Router connected to the same local network as the app. In addition, the iPhone must already have the corresponding Thread Network Credentials installed. The credentials are installed via the system API and are available to all apps on the phone.
The process for obtaining these credentials depends on the Thread ecosystem being used. In most cases, when the Thread network is provided by a device such as a Samsung TV or a dedicated hub such as Google TV Streamer 4K, the manufacturer's companion app must be used to download and install the Thread Network Credentials on the iPhone.
For example:
- Samsung: SmartThings
- Google: Google Home
For detailed instructions, refer to the documentation provided by the device manufacturer. In general, the required credentials are installed after signing in to the companion app, adding the Thread-enabled device to the home, and enabling its Thread Border Router functionality.
If the credentials are not immediately available, commissioning a Matter device using the corresponding companion app may trigger the download and installation of the Thread Network Credentials.
Note
The app has been tested with Google TV Streamer 4K. At the time of writing, Google does not provide any alternative method for installing or sharing Thread Network Credentials on iPhone other than through the Google Home app.
Set up a Thread Border Router — such as a Nest Hub (2nd gen) or Google TV Streamer 4K — via the Google Home app. Google Play Services (the Home API) then makes the credentials available to this app the same way.
- The phone and the hub must be on the same Wi-Fi network — credential/device discovery relies on local-network multicast (mDNS), which doesn't cross subnets or routers.
- The hub needs a user account signed in (a Google account added via the Google Home app) before it will share any credentials — a freshly unboxed, no-account hub won't work.
- Make sure the router on the network has IPv6 enabled — without it, Thread commissioning can appear to succeed, but device control might fail afterward.
- Matter standardizes Thread credential sharing across ecosystems, so a single hub can plausibly serve both platforms — e.g. a Google TV Streamer 4K set up once in Google Home has been observed working for both iOS and Android commissioning in this app, without a separate Apple-ecosystem hub.
This is a Kotlin Multiplatform project targeting Android and iOS.
/composeApp— shared Compose Multiplatform UI, screens, navigation, and DI (Koin). Contains the usual KMP source sets:commonMain— code shared across all targets (screens for home, commissioning, bindings, logs, and per-device-type controllers for locks, lights, and switches).androidMain/iosMain— platform-specific code, e.g. wiring up Matter commissioning on each platform.
/shared— a thin KMP module thatapi/exports:composeAppand produces the iOS framework the Xcode project consumes. It carries no source of its own; it exists so Swift has a singleimport sharedto reach the Kotlin surface. Both Xcode targets build it through a run-script phase calling./gradlew :shared:embedAndSignAppleFrameworkForXcode./androidDeps— Android library wrapping the native Matter (CHIP) SDK and the Google Home API, exposing helpers such asChipClient,ClustersHelper, andBindingManager. Google Home API, exposing helpers such asChipClient,ClustersHelper, andBindingControllerImpl./core— shared domain models (Device,DeviceMatterInfo,LockDeviceState, …) and theNordicLoggerabstraction used across platforms — backed by Room on Android and, on iOS, byios-matter's Pulse-basedSwiftLogger./androidApp— the Android application entry point./iosApp— the iOS application entry point (SwiftUI host for the shared Compose UI), plus thenrfMattertarget — theMatterSupportapp extension that provides the system commissioning/QR-code UI. Even though the UI is shared, this project is required as the entry point for the iOS app, and is where you'd add any additional SwiftUI code./ios-matter— the Swift package that wraps Apple's Matter and MatterSupport frameworks, vendored into this repo rather than resolved from git.:composeAppcinterops against it, so this is where the iOS half of commissioning, cluster access, and the keypair/storage shared with the Matter extension lives. See/ios-matter— vendored Matter Swift package.
/androidDeps/libs contains prebuilt binaries checked directly into git —
they are not built by this Gradle project:
- Jars:
AndroidPlatform.jar,CHIPClusterID.jar,CHIPClusters.jar,CHIPController.jar,CHIPInteractionModel.jar,OnboardingPayload.jar,libMatterJson.jar,libMatterTlv.jar. - Native libraries:
/androidDeps/libs/jniLibs/arm64-v8a—libCHIPController.soandlibc++_shared.so(arm64-v8aonly — there's nox86_64build, so these libs won't load on an Android emulator, only on a physical arm64 device).
These binaries are built against Matter 1.5.0, as provided by Nordic. It comes from Nordic's
fork of Project CHIP,
nrfconnect/sdk-connectedhomeip (the NCS
downstream of
project-chip/connectedhomeip) — specifically its
Android
chip-tool build target for arm64. To rebuild them from source, follow the instructions provided in the
nrfconnect/sdk-connectedhomeip.
Note: if you build
.jars/.sofiles yourself against a newer Matter version, this project may need some changes to handle the newer version — newer Matter releases can add, rename, or change the behavior of the APIs these binaries expose.
This project includes a ./mavenLocal directory checked directly into git — a pre-built local Maven
repository
with the same directory structure and artifact metadata (maven-metadata.xml, checksums) that
Gradle expects.
It is wired up in settings.gradle.kts.
When you clone this repo and build, Gradle finds the Home API artifacts from ./mavenLocal
transparently
— no manual setup required.
The directory vendors the following Android dependencies Google doesn't publish on public Maven repos:
com.google.android.gms:play-services-homeat17.1.0— the main Google Home Mobile SDK for Matter (the Home API). Provides API interfaces, device control, authorization, and commissioning services.com.google.android.gms:play-services-home-typesat17.1.0— a helper library containing models for device types, traits, command parameters, and other domain types. Its POM declares a compile-scope dependency onplay-services-home, so both artifacts must always be updated together.
Google's public Maven repo (google() / dl.google.com/android/maven2) only publishes
play-services-home
up to 16.0.0 and doesn't publish play-services-home-types at all. Version 17.1.0 introduced
several new
APIs that weren't available in 16.0.0
Note: This is not required just to build the project —
./mavenLocalfolder already ships the vendored17.1.0artifacts in this repo, so the steps below only matter if you're deliberately updating to a newer version.
The Google Home APIs are currently in open beta, which means they are available to developers,
but they may
change without notice. They are not part of the standard Android SDK or the usual Google Play
Services
libraries (com.google.android.gms.*), and they are not yet available in Maven Central or
Google's
standard Maven repositories (google() / dl.google.com/android/maven2).
Therefore, getting started requires a few non-standard integration steps.
- Sign in to the Google Cloud Console with your Google account.
- Access the Home APIs early-access program and download the ZIP archive containing the SDK artifacts.
- Extract the SDK into your system's local Maven repository, the
.m2/repositorydirectory. This is the standard path used for local Maven repositories.- Linux:
~/.m2/repository/ - macOS:
~/.m2/repository/ - Windows:
C:\Users\<User_Name>\.m2\repository\
- Linux:
- Add
mavenLocal()to your Gradlerepositoriesblock so Gradle can find the artifacts —settings.gradle.ktsalready declares it alongside the vendored./mavenLocalrepository. - Repeat this process each time the SDK is updated, until Google officially publishes it to a Maven repository.
Warning: the Home API is still evolving, so a newer version may introduce breaking changes — check
androidDepsand anywhere else the Home API is used (search forplay.services.homein the source), and adjust as needed.
/ios-matter is a full Swift package — manifest and sources — checked directly into
git, the Apple-side counterpart to the vendoring described above. It used to be resolved from
git@github.com:sylwester-zielinski/ios-matter.git at an exact tag; it is now built in place.
It is not a SwiftPM dependency of the Kotlin build. It is compiled to a static library and
consumed through plain cinterop, so the Swift object code ends up inside the published artifact.
Three Gradle tasks per iOS target do this, in build.gradle.kts:
| Task | Does |
|---|---|
compileIosMatterSwift<Target> |
runs xcodebuild on /ios-matter, which also resolves and builds Pulse |
iosMatterStaticLib<Target> |
libtools the resulting objects into libios-matter.a and copies the Swift-generated ObjC header and module map beside it |
cinteropIosMatter<Target> |
translates that module into the iosMatter Kotlin package and embeds the archive in the klib |
./gradlew :composeApp:iosMatterStaticLibs builds the library for every target. All three tasks run
automatically as part of any iOS compile — there is nothing to invoke by hand.
Only the @objc public surface of ios-matter crosses the boundary; the Swift-generated
Objective-C header is the contract, which is why the Kotlin-facing classes are annotated.
Kotlin reaches them through the iosMatter.* package (iosMatter.SwiftLogger,
iosMatter.LocalMatterLightController, …).
Why not localSwiftPackage. A SwiftPM declaration is published as
SwiftPMDependency.Local carrying an absolute path — inspect
matter-support-<version>-swiftpm-metadata.json in any published artifact to see it. A consumer
resolving matter-support from Maven therefore cannot find the Swift code at all, and the Swift
sources are not in the klib either. Only the version-pinned swiftPackage(url = ...) form is
publishable, and that means a second source of truth for the Swift code. Archiving the objects into
the cinterop klib avoids both problems: no.nordicsemi.nrf.matter:matter-support is now
self-contained, and Xcode needs no package graph — neither iosApp nor nrfMatter imports
ios_matter, both reach it through Kotlin bridges such as KeychainKt.prepareKeychain().
Editing it. Change a .swift file under /ios-matter/ios-matter and build — the task inputs
cover the sources and the manifest, so the library is rebuilt and re-archived automatically. There
is no tag to push, no version to bump, and no lockfile to realign. Its own remote dependency,
Pulse, is still pinned by
/ios-matter/Package.resolved and is linked into the same archive.
One consequence of /ios-matter staying a local package: SwiftPM refuses unsafeFlags in a package
consumed as a dependency but exempts local ones, which is what lets
/ios-matter/Package.swift keep -enable-library-evolution. Its
comment explains why that flag is needed.
Use the run configuration from the run widget in your IDE's toolbar, or build it directly from the terminal:
- on macOS/Linux
./gradlew :androidApp:assembleDebug
- on Windows
.\gradlew.bat :androidApp:assembleDebug
Use the run configuration from the run widget in your IDE's toolbar, or open the
/iosApp
directory in Xcode and run it from there.
- Android: minSdk 27+, a device with Google Play Services (Home API is used for commissioning). The
vendored CHIP native libraries are
arm64-v8aonly, so a physical arm64 device is required — the app won't run on an emulator. - iOS: iOS 26.0 or newer — both
/ios-matterand the Xcode targets set that as their minimum, because Apple'sMatter/MatterSupportAPIs the app relies on are only available there. Building needs an Xcode recent enough forswift-tools-version: 6.3(Xcode 26+). Open/iosAppin Xcode to build/run.
The vendored CHIP binaries (see
androidDeps native Matter (CHIP) SDK binaries)
are built against Matter 1.5.0, first introduced in nRF Connect SDK v3.2.0, so below listed
Nordic DK running Matter firmware built with NCS v3.2.0 or
newer should be compatible for testing commissioning/control with this app.
| Development Kit | SoC |
|---|---|
| nRF52840 DK | nRF52840 |
| nRF5340 DK | nRF5340 |
| nRF54L15 DK | nRF54L15 |
| nRF54LM20 DK | nRF54LM20 |
For the authoritative, up-to-date list of supported hardware, see Nordic's Matter hardware and memory requirements page — new DKs and SoCs are added there as they gain Matter support.
Copyright © Nordic Semiconductor. Licensed under a BSD-3-Clause style license — see the LICENSE for full terms.



