companion_device_manager 0.2.1 copy "companion_device_manager: ^0.2.1" to clipboard
companion_device_manager: ^0.2.1 copied to clipboard

Android-only Flutter plugin for Companion Device Manager (CDM) association and wake callbacks

companion_device_manager #

An Android-only Flutter plugin that wraps the Android Companion Device Manager API and provides a simple Dart-facing association flow plus a background wake callback.

Features #

  • Android-only companion device association flow
  • typed Dart models for requests, associations, and events
  • convenience APIs for cross-session association/disassociation by MAC address
  • background callback registration for device-appearance wake-ups
  • reactive stream for real-time device_appeared / device_disappeared events
  • stored last background event for post-wake inspection
  • example app showing the complete flow

Supported platforms #

  • Android: supported (see API-level matrix below)
  • iOS: not supported
  • Desktop: not supported
  • Web: not supported

Android API-level support #

This plugin wraps multiple Android CDM APIs that were introduced in different Android releases.

  • Android 8.0+ (API 26+): base Companion Device Manager support (isAvailable, associate, getAssociations, disassociate).
  • Android 12+ (API 31+): device presence observation (startObservingDevicePresence) used for background wake and presence events.
  • Android 13+ (API 33+): id-based presence observation path (ObservingDevicePresenceRequest) used by this plugin when available.

In short:

  • if you only need association flow, Android 8.0+ is enough
  • if you need wake/background presence events, target Android 12+

Documentation #

Detailed design and implementation notes live in the doc/ folder:

  • doc/project-architecture.md
  • doc/public-api.md
  • doc/example-app.md

Installation #

Add the dependency to your pubspec.yaml:

dependencies:
  companion_device_manager:
	path: ../companion_device_manager

Or, for a published version:

dependencies:
  companion_device_manager: ^0.2.1

Basic usage #

import 'package:companion_device_manager/companion_device_manager.dart';

final manager = CompanionDeviceManager();

@pragma('vm:entry-point')
Future<void> companionDeviceWakeCallback() async {
  print('Companion device wake callback invoked');
}

Future<void> setup() async {
  final available = await manager.isAvailable();
  if (!available) {
	return;
  }

  await manager.registerBackgroundCallback(companionDeviceWakeCallback);

  final association = await manager.associateByMacAddress('00:11:22:33:44:55');

  print('Associated device: ${association.macAddress}');
}

void watchBackgroundEvents() {
  // Note: this stream only emits events while the app is running in foreground.
  // To react to events when the app is backgrounded or killed, use the background callback.
  manager.backgroundEvents.listen((event) {
    print('Companion event: ${event.type} at ${event.timestamp}');
  });
}

MAC address format (for new convenience APIs) #

associateByMacAddress and disassociateByMacAddress accept only the Android classic MAC format:

  • XX:XX:XX:XX:XX:XX (hex pairs separated by :)
  • examples: 00:11:22:33:44:55, AA:BB:CC:DD:EE:FF

Behavior:

  • input is validated strictly
  • input is normalized to uppercase before being sent to Android APIs
  • the same normalized format is compatible with CompanionDeviceAssociation.macAddress

If you need full control (custom display name / advanced filters), keep using associate(CompanionDeviceAssociationRequest(...)).

Background callback requirements #

The callback passed to registerBackgroundCallback must be:

  • a top-level or static function
  • annotated with @pragma('vm:entry-point')

Additionally, when the callback is invoked in a headless Flutter engine (after app wake from device presence):

  • call WidgetsFlutterBinding.ensureInitialized() early in the callback body
  • call ui.DartPluginRegistrant.ensureInitialized() to ensure all plugins (including this one) are ready for method channel calls

Example:

import 'dart:ui' as ui;
import 'package:flutter/widgets.dart';

@pragma('vm:entry-point')
Future<void> companionDeviceWakeCallback() async {
  WidgetsFlutterBinding.ensureInitialized();
  ui.DartPluginRegistrant.ensureInitialized();
  
  // Now you can safely call plugin methods
  final manager = CompanionDeviceManager();
  final lastEvent = await manager.getLastBackgroundEvent();
  // ...
}

This is required because Android may need to start a headless Flutter engine when the companion device service wakes the app.

Example app #

The example app shows how to:

  • register and clear the background callback
  • start an association request
  • use MAC-only convenience APIs for cross-session operations
  • react to real-time backgroundEvents while the app is running
  • inspect current associations
  • read the last persisted background event

Run it with:

cd example
flutter run

Android notes #

The plugin targets Android devices that support Companion Device Manager.

CompanionDeviceManager.isAvailable() returns true only on Android 8.0+ (API 26+).

Background presence observation and wake callbacks require Android 12+ (API 31+), because they rely on newer CDM presence APIs.

Depending on the device type you are pairing with, you may also need Bluetooth-related runtime permissions in the host app.

Use CompanionDeviceFilter.bluetoothLe(...) for BLE peripherals and CompanionDeviceFilter.bluetooth(...) for classic Bluetooth devices.

The first version of the plugin focuses on Bluetooth address-based filters to keep the API simple and predictable.

Event delivery #

  • When app is running in foreground: subscribe to manager.backgroundEvents stream for real-time device_appeared and device_disappeared events.
  • When app is backgrounded or killed: the CompanionDeviceService broadcasts events to the background callback (if registered).
  • Persisted events: the last event payload is always stored on device and can be retrieved via getLastBackgroundEvent().
  • Stream and persistence are synchronized: both paths use the same native event source, so the UI stays in sync.

Publishing checklist #

Before publishing to pub.dev, verify that:

  • the example app works on a real Android device
  • the background callback is documented in the host app README
  • the version is bumped appropriately
  • the Android-only support statement stays visible
  • the docs folder remains in sync with the public API
1
likes
0
points
105
downloads

Publisher

unverified uploader

Weekly Downloads

Android-only Flutter plugin for Companion Device Manager (CDM) association and wake callbacks

Repository (GitHub)
View/report issues

Topics

#companion-device #android #bluetooth #plugin #background

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on companion_device_manager

Packages that implement companion_device_manager