flutter_meta_wearables_dat 0.9.0
flutter_meta_wearables_dat: ^0.9.0 copied to clipboard
Flutter bridge to Meta's Wearables DAT for iOS and Android.
0.9.0 #
BREAKING CHANGES
- Backgrounding now stops the stream session unless you opt in. Previously the plugin only stopped rendering while backgrounded on iOS and did nothing at all on Android, leaving a live session, an attached camera capability and a registered texture with no event to Dart — apps were left holding a texture id and a
Texturefrozen on its last frame. Now a true background transition (app backgrounded or phone locked) tears theDeviceSessiondown, emits a terminalstopped, and releases the texture. CallenableBackgroundStreaming()beforestartStreamSession()to keep the old behaviour. - There is no auto-resume. Returning to the foreground does nothing by design — the plugin never reactivates the glasses camera on its own. Show your placeholder and let the user restart.
startStreamSession()now fails withAPP_BACKGROUNDEDwhile the app is backgrounded and background streaming is off. Checked on entry and again at the final commit point, so a start that was in flight when the app backgrounded cannot leave a live stream running with nothing to stop it.- New
stoppedForBackgroundcode onstreamSessionErrorStream(), emitted just before the terminalstopped, so a deliberate stop is distinguishable from a fault. Exclude it from any retry logic. - iOS: raw-codec frames now reach
videoFramesStream()while backgrounded.emitRawsat after the background guard whileemitHvc1sat before it, so withVideoCodec.raw— the default — nothing was delivered in background despite the documented contract. Raw frames are also no longer FPS-throttled, matching hvc1 and Android; apps with a lowfpssubscribed tovideoFramesStream()will see more callbacks.
What you must change
Subscribe to streamSessionStateStream() and clear your texture id on StreamSessionState.stopped. An app that caches the texture id and never listens will render an unregistered texture — black or frozen — after any background round trip.
Fixes
- Android emitted no terminal
stoppedon any plugin-initiated teardown. The state handler was detached beforestream.stop(), so the SDK'sSTOPPING/STOPPEDtransitions were never observed. This affected every stop, not just backgrounding — the same bug iOS fixed in 0.8.1. - iOS lifecycle detection missed
UISceneDelegatehosts entirely. Flutter stops forwarding application lifecycle events once a host adopts scenes, and current Flutter templates are scene-based by default, so the plugin was silently blind on a growing share of apps. Lifecycle is now observed viaNotificationCenter, which UIKit posts in both cases. - Android gained process-wide foreground detection, which it had no notion of at all. Rotation, activity transitions and multi-window do not count as backgrounding.
- Teardown noise no longer surfaces as an error: the SDK's
videoStreamingErrorduring a deliberate background stop is suppressed for a bounded window, so apps stop showing "Video streaming encountered an error" for a clean shutdown. - Android: the foreground service no longer resurrects itself after process death with default branding, no engine and an unstoppable wake lock; it also stops when the user swipes the app from Recents. The wake lock gained a timeout backstop.
- Transient interruptions never stop a stream: Control Center, the notification shade, the app-switcher preview and incoming-call banners on iOS; rotation and split-screen on Android.
Added
MetaWearablesDat.isBackgroundStreamingEnabled()— reads the flag from the native side. Dart's copy drifts across a hot restart, where the isolate resets but the audio session or foreground service keeps running.
0.8.1 #
- Stream teardowns are no longer silent. iOS detached the stream-state handler before stopping the camera, so every plugin-initiated teardown — the device-availability watchdog, or a
DeviceSessionthat stopped underneath us — reached Dart as nothing at all. Apps were left holding a live texture id and aTexturefrozen on its last frame, with no state change and no error.streamSessionStateStream()now emits a terminalstoppedon those paths. - The iOS device-availability watchdog no longer tears the session down on a transient link blip.
activeDeviceStream()yieldsnilas soon as no device satisfies the SDK's eligibility test, which requiresLinkState.connected— so a momentary.connectingemittednileven though the glasses never went away. The SDK's own handler stops the stream only on a genuine.disconnected. A 2 s grace period now has to elapse, and the selector is re-checked, before anything is torn down. - iOS
hvc1: recover from a mid-stream codec-configuration change. TheVTDecompressionSessionwas built from the first frame'sCMFormatDescriptionand cached forever. The glasses can push a new codec config mid-stream, after which every decode failed and — because the cached session stayed non-nil— nothing ever recreated it: a permanent freeze with no error on any channel. The session is now revalidated against each frame's format description and recreated when it no longer matches.
0.8.0 #
BREAKING CHANGES
- Update to Meta Wearables DAT 0.9.0 on both platforms.
- Minimum iOS deployment target is now 17.2 (was 17.0). The vendored xcframeworks are built
-target arm64-apple-ios17.2, so apps below that will fail to link. - iOS:
capturePhoto()failures now resolve in milliseconds instead of waiting out the 15 s timeout — DAT 0.9.0 reports them throughStreamError.photoCaptureFailed, surfaced asPlatformException(CAPTURE_PHOTO_FAILED, details: photoCaptureFailed). The timeout remains as a backstop. hingesClosednow also fires when the glasses are taken off, not just when the arms are folded. The SDK does not auto-resume in either case: tear the session down (clear your texture ID and streaming flag) or theTexturewidget freezes on its last frame.- Android: two
DeviceSessionErrorcases that previously collapsed intounexpectedErrornow report properly assessionEndedByDeviceandcapabilityDenied;DEVICE_DISCONNECTEDmaps todeviceNotConnected. - Android: stream-level
thermalEmergencyis gone (DAT 0.9.0 removedStreamError.THERMAL_EMERGENCY) — a thermal emergency now arrives as the session-leveldeviceThermalEmergency.thermalEmergencyis iOS-only from this release. - Android:
Stream.start()failures are no longer silently swallowed; they surface onstreamSessionErrorStream(). - Photo-capture failures are documented as never appearing on
streamSessionErrorStream()on either platform — they reject thecapturePhoto()future. - Add a README note on opting out of DAT crash reporting (host-app config only, no plugin API).
0.7.2 #
- Improve README.
0.7.1 #
- Docs: document the iOS Wi‑Fi vs Bluetooth Classic camera transport choice, with migration/switching steps.
0.7.0 #
BREAKING CHANGES
- Update to Meta Wearables DAT 0.8.0 on both platforms.
- Add the Meta Glasses device type (
WearableDeviceType.metaGlasses). - Android: observe the new
StreamState.pausedmid-session (parity with iOS). - iOS:
capturePhoto()no longer hangs on an accepted-but-undelivered capture — it now times out withPlatformException(CAPTURE_PHOTO_FAILED, details: photoCaptureTimeout). - Surface the SDK's new registration/unregistration
timeouterrors. - Mock add-on:
pairRayBanMeta()→pairGlasses(model:)with a newGlassesModelenum (see its changelog).
0.6.1 #
- iOS: Fix
noEligibleDeviceand emptygetDevices()right after camera permission grant by keeping the SDK device list warm. requestCameraPermission()waits briefly for device discovery before returning (iOS and Android).
0.6.0 #
- Add
getDevices()and wearable device types for listing paired glasses, connection state, compatibility, and the active/streaming pair. - Add device pinning via
startStreamSession(deviceId)(nullkeeps automatic selection), withSTREAM_ACTIVEprotection and a paired-device picker in the example app.
0.5.3 #
- iOS: Fix first-registration device discovery and a
startStreamSessionhang after a failed start; surface genuine session errors.
0.5.2 #
- iOS: Add Swift Package Manager support alongside CocoaPods.
0.5.1 #
- Prepare Android Gradle for Flutter's Built-in Kotlin migration.
- Camera permission errors are now typed
CameraPermissionExceptions on both platforms; afalsereturn means user denied, exclusively. - Gate event-stream
debugPrintbehindkDebugModeso release builds stop logging plugin events.
0.5.0 #
- Update to DAT SDK 0.7.0 on iOS and Android. Existing Dart APIs unchanged; new opt-in additions below — non-breaking, drop-in upgrade.
- New
openDATGlassesAppUpdate()— opens the Meta AI app to update the on-device DAT app. Pair with the newdatAppOnTheGlassesUpdateRequirederror code to drive a "tap to update" UI. - New
deviceStateStream()returningStream<DeviceState>for liveThermalLevelupdates. Lets apps warn the user before a thermal error stops the stream. - New
StreamSessionErrorcodes:thermalEmergency,peakPowerShutdown,batteryCritical, plus device-session variants (deviceThermalCritical,deviceThermalEmergency,devicePeakPowerShutdown,deviceBatteryCritical,datAppOnTheGlassesUpdateRequired,dwaUnavailable). - Inherits DAT 0.7.0 bug fixes: Android
checkPermissiondouble-resume crash, post-Bluetooth-reconnect stale state, photo capture timeout,ServiceConnectionleak during registration; iOS session stop propagation. - Display capability (new in DAT 0.7.0 for Ray-Ban Display glasses) is intentionally not bundled — to keep this package focused on camera. A future
flutter_meta_wearables_dat_displayadd-on will mirror the mock-device split.
0.4.0 #
- BREAKING: MockDeviceKit moved to a separate optional package,
flutter_meta_wearables_dat_mock_device. Production apps no longer linkMWDATMockDevice.xcframework(iOS) ormwdat-mockdevice(Android) and therefore no longer needNSCameraUsageDescription(iOS) or theCAMERApermission (Android) just to ship the plugin. The Apple App Store binary scanner previously rejected v0.3.x builds that omitted those strings because MockDeviceKit unconditionally linkedAVFoundation; that requirement is gone. - Apps that pair against a mock device for development should add
flutter_meta_wearables_dat_mock_devicetopubspec.yamland migrate calls — see the migration table below. The shape mirrors Firebase'sfirebase_core+ per-feature packages and Datadog'sdatadog_flutter_plugin+datadog_session_replay. - Mock APIs renamed (the
Mock*prefix is now redundant given the namespace):
| Before (0.3.x, core) | After (0.4.0, mock add-on) |
|---|---|
MetaWearablesDat.configureMockDevices(...) |
MetaWearablesDatMockDevice.configure(...) |
MetaWearablesDat.disableMockDevices() |
MetaWearablesDatMockDevice.disable() |
MetaWearablesDat.pairMockRayBanMeta() |
MetaWearablesDatMockDevice.pairRayBanMeta() |
MetaWearablesDat.unpairMockRayBanMeta(uuid) |
MetaWearablesDatMockDevice.unpairRayBanMeta(uuid) |
MetaWearablesDat.setMockPermission(p, s) |
MetaWearablesDatMockDevice.setPermission(p, s) |
MetaWearablesDat.setMockPermissionRequestResult(p, s) |
MetaWearablesDatMockDevice.setPermissionRequestResult(p, s) |
MetaWearablesDat.mockDevicePowerOn(uuid) |
MetaWearablesDatMockDevice.powerOn(uuid) |
MetaWearablesDat.mockDevicePowerOff(uuid) |
MetaWearablesDatMockDevice.powerOff(uuid) |
MetaWearablesDat.mockDeviceDon(uuid) |
MetaWearablesDatMockDevice.don(uuid) |
MetaWearablesDat.mockDeviceDoff(uuid) |
MetaWearablesDatMockDevice.doff(uuid) |
MetaWearablesDat.setMockCameraFeed(uuid, path) |
MetaWearablesDatMockDevice.setCameraFeed(uuid, path) |
MetaWearablesDat.setMockCameraFacing(uuid, f) |
MetaWearablesDatMockDevice.setCameraFacing(uuid, f) |
MetaWearablesDat.setMockCapturedImage(uuid, path) |
MetaWearablesDatMockDevice.setCapturedImage(uuid, path) |
- The
Permission,PermissionStatus, andCameraFacingenums (referenced exclusively by mock APIs) moved to the mock add-on. Import them fromflutter_meta_wearables_dat_mock_deviceafter migrating. - All non-mock APIs (
startRegistration,requestCameraPermission,requestAndroidPermissions,startStreamSession/stopStreamSession,capturePhoto,enableBackgroundStreaming/disableBackgroundStreaming, every event stream) keep the same signatures and behavior — production code that doesn't touch mock devices needs no changes other than potentially removingNSCameraUsageDescriptionandCAMERA.
0.3.1 #
- Fix: CMSampleBufferGetFormatDescription used with .hvc1 background streaming to correctly pass VPS/SPS/PPS and enable ffmpeg_kit_flutter use cases while backgrounded.
0.3.0 #
- BREAKING: Update to DAT SDK 0.6.0 on iOS and Android.
- New
setMockCameraFacing()to switch the mock device's camera between front and back; addsCameraFacing. - New
configureMockDevices(),disableMockDevices(),setMockPermission()andsetMockPermissionRequestResult()for finer-grained mock device control. - New
videoStreamSizeStream()exposing the native video frame dimensions so Dart can drive anAspectRatioaround theTexturewidget instead of forcing a fixed size. - New opt-in background streaming on both iOS and Android:
enableBackgroundStreaming(androidNotification:)/disableBackgroundStreaming()keep the session alive when the host app is backgrounded or the phone is locked. iOS activates anAVAudioSession(.playAndRecord/.videoRecordingwith.allowBluetoothHFP+.mixWithOthers) and forces software HEVC decoding so the decoder survives background→foreground without stutter. Android starts a foreground service of typeconnectedDevicewith a user-customizable notification (title/text/channelId/channelName/icon) and aPARTIAL_WAKE_LOCK; the plugin manifest auto-merges the requiredFOREGROUND_SERVICE,FOREGROUND_SERVICE_CONNECTED_DEVICE, andWAKE_LOCKpermissions. iOS hosts must addaudioandbluetooth-centraltoUIBackgroundModes. - New
videoFramesStream()emitting per-frameVideoFramepayloads (codec / bytes / width / height / presentationTimestampUs / isKeyframe) in both foreground and background, so apps can record to disk or run custom processing while the FlutterTexturecan't render. Zero per-frame cost when no subscriber is attached. iOS emits BGRA forrawand rawhvc1NAL units forhvc1; Android emits I420 planar YUV (width * height * 3/2bytes) verbatim from the SDK. - New
BackgroundNotificationvalue type for configuring the Android foreground service notification.
0.2.2 #
- iOS:
VideoCodec.hvc1— invalidateVTDecompressionSessionin background and recreate on foreground; stream session stays alive.
0.2.1 #
- Add AI coding agent configs (
AGENTS.md, Claude Code, Cursor, Copilot) withinstall-skills.shinstaller.
0.2.0 #
- BREAKING: Update to DAT SDK 0.5.0 on iOS and Android.
startStreamSession()gainsvideoCodecand newVideoCodec:raw(default, foreground-only) orhvc1(compressed HEVC, background-friendly, iOS only).- New
streamSessionStateStream()andstreamSessionErrorStream()to observe session lifecycle (stopped, streaming, paused, …) and errors such as thermal limits; addsStreamSessionStateandStreamSessionError. capturePhoto()gainsformatand newPhotoCaptureFormat:heicorjpeg(defaultjpeg).- Android: Photo capture failures use typed
CaptureError(e.g. DeviceDisconnected, NotStreaming, CaptureInProgress, CaptureFailed). - High-resolution streaming at 720×1280 works reliably on both platforms.
0.1.2 #
- Add
captureStreamFramemethod.
0.1.1 #
- Add performance optimizations.
0.1.0 #
- Implement Texture API for streaming optimization.
- Add
streamQualityparameter. - Improve documentation and example app.
0.0.3 #
- Fix demo gif in README.
0.0.2 #
- Improve pub.dev package page.
0.0.1 #
- Initial release.