- video_player: ExoPlayer (Android) / AVPlayer (iOS/macOS) backend with
PixelBufferSink, method-channel adapter, Dart-side XVideoPlayer +
testing fake.
- insets: XInsets singleton + XAnimatedInsets widget lerp the system
viewPadding over 220ms so OS bar visibility toggles
(immersiveSticky <-> edgeToEdge) slide bottom-/top-anchored UI into
place instead of snapping by the nav-bar / status-bar height.
Sync FFI from Dart into platform detectors:
- iOS / macOS: NSDataDetector(.link | .phoneNumber) + a tight bare-domain
pass that requires `/` or `?` (so `etc.` / `v1.2.3` don't false-positive
while `example.com/path` does match). NFKD-fold the phone capture so
full-width / Arabic-Indic digits collapse to ASCII; stop the digit run
at the first letter so `+1 555 1234 ext.99` doesn't fuse the extension.
- Android: JNI into android.util.Patterns (WEB_URL / EMAIL_ADDRESS / PHONE)
via a cached JavaVM, std::call_once for init, full per-call
ExceptionCheck coverage. UTF-16→UTF-8 conversion is hand-rolled to dodge
the Modified-UTF-8 / CESU-8 incompatibility with Dart's utf8.decode.
`UxUrl.launch(url)` is the matching tap action. Channel side dispatches via
UIApplication / NSWorkspace / Intent.ACTION_VIEW. Dart-side gates the URL
against a scheme allowlist (http, https, mailto, tel, sms, banlu, tg),
rejects bidi-override controls (U+202A..E / U+2066..9) to prevent visual
spoofs, and blocks USSD / MMI tel: codes containing `*` or `#`.
Library/native cleanup along the way:
- Renamed libux_keyboard.so to libux.so (also covers sensor + url).
- Collapsed three near-identical FFI loader stanzas across keyboard / sensor
/ url into a shared lib/src/_ffi.dart with `uxLib` + typed `uxLookupX`
helpers.
`prepare_command` runs only on `pod install`. Mid-iteration Swift
edits to `darwin/Camera/*.swift` would never reach the built binary
until the user ran pod install or cleaned the Pods dir — confusing
during debugging (NSLog/diag additions silently absent from the
running app).
Add a `script_phases` build phase to both podspecs that rsyncs
darwin/Camera into Classes/Camera-shared before each compile. The
existing `prepare_command` stays as the install-time primer that
gives CocoaPods the initial file set to glob; the build phase keeps
contents fresh on every Swift edit thereafter. Verified: the resulting
binary now contains the NSLog strings that the prior build was
missing.
(Adding new files to darwin/Camera/ still requires pod install so
CocoaPods' source_files glob picks them up — script_phases only
refreshes content of files CocoaPods already knows about.)
Reuse the AVFoundation Swift files between iOS and macOS without
sprinkling `#if canImport(UIKit)` through them. The split is:
darwin/Camera/ platform-shared (AVFoundation only)
CameraPlugin channel + instance map
CameraInstance session + outputs + texture
CameraSession AVCaptureSession + runtime-error obs
CaptureDevice front/back discovery
PhotoOutput AVCapturePhotoOutput
PreviewSink CVPixelBuffer → FlutterTexture
VideoRecorder AVAssetWriter
DeviceOrientation wire-string enum
ios/Classes/Camera/ iOS-only impls + extensions
AudioSession AVAudioSession.upgradeForRecording
DeviceOrientationBridge UIDevice.orientation listener
CameraSession+iOS AVCaptureSessionWasInterrupted obs
+ InterruptionReason decode + the
application-audio-session flags
(all iOS-only on AVCaptureSession)
CameraSettings UIApplication.openSettingsURLString
FlutterRegistrar+iOS method-form of textures/messenger
macos/Classes/Camera/ macOS no-op stubs (same surface)
AudioSession no-op (no AVAudioSession on macOS)
DeviceOrientationBridge no-op (desktops don't rotate)
CameraSession+macOS no-op setupPlatform()
CameraSettings NSWorkspace → System Settings'
Privacy_Camera pane
FlutterRegistrar+macOS property-form of textures/messenger
`CameraSession.init` now calls `setupPlatform()` which each platform
provides via an extension — keeps the iOS-only interruption observer
and the `automaticallyConfiguresApplicationAudioSession` /
`usesApplicationAudioSession` flags (both iOS-only on AVCaptureSession)
out of the shared file. Flash-mode in PhotoOutput uses
`if #available(macOS 11/13, *)` rather than `#if`, since those are
plain version gates not platform splits.
The shared files compile into the iOS pod from `ios/Classes/Camera-shared/`
and into the macOS pod from `macos/Classes/Camera-shared/`, each a
mirror populated by a `prepare_command` in the podspec:
rm -rf Classes/Camera-shared && cp -R ../darwin/Camera Classes/Camera-shared
Symlinks and `../` source globs both fail — Pathname.glob bails on
symlinks, and CocoaPods silently drops paths that escape the pod
directory. The mirror destinations are .gitignore'd.
macOS UxPlugin now registers CameraPlugin alongside the others.
Swift `import PhotosUI` made the compiler happy but the binary never
referenced any PhotosUI symbol directly — `presentLimitedLibraryPicker`
is dispatched via `objc_msgSend` against an Obj-C category on
`PHPhotoLibrary`. Without an explicit framework link the linker
dropped PhotosUI, the category never registered, and iOS 26 raised
NSInvalidArgumentException for an "unrecognized selector".
Declare Photos + PhotosUI as podspec frameworks so the linker force-
loads them.