camera: macOS port via darwin/ split (no shared-file pragmas)
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.
This commit is contained in:
9
macos/Classes/Camera/AudioSession.swift
Normal file
9
macos/Classes/Camera/AudioSession.swift
Normal file
@@ -0,0 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
/// macOS counterpart of `ios/Classes/Camera/AudioSession.swift`.
|
||||
/// `AVAudioSession` is an iOS/tvOS/watchOS concept — macOS apps have
|
||||
/// no such global category state. `AVCaptureSession` configures its
|
||||
/// own audio routing on macOS, so this is a pure no-op.
|
||||
enum AudioSession {
|
||||
static func upgradeForRecording() {}
|
||||
}
|
||||
22
macos/Classes/Camera/CameraSession+macOS.swift
Normal file
22
macos/Classes/Camera/CameraSession+macOS.swift
Normal file
@@ -0,0 +1,22 @@
|
||||
import AVFoundation
|
||||
import Foundation
|
||||
|
||||
/// macOS counterpart of `CameraSession+iOS.swift`. Intentionally a
|
||||
/// no-op:
|
||||
///
|
||||
/// - `automaticallyConfiguresApplicationAudioSession` /
|
||||
/// `usesApplicationAudioSession` are iOS-only properties on
|
||||
/// `AVCaptureSession`. macOS doesn't have an app-wide
|
||||
/// `AVAudioSession`, so there's nothing to "configure".
|
||||
/// - `AVCaptureSessionWasInterrupted` and `InterruptionReason` are
|
||||
/// iOS/tvOS/watchOS only — desktop AVCaptureSessions never get
|
||||
/// "interrupted by a phone call" or "displaced by another app's
|
||||
/// exclusive camera hold" in the way iOS does.
|
||||
///
|
||||
/// `onInterrupted` and `onResumed` on [CameraSession] are present
|
||||
/// for surface parity but stay silent on macOS.
|
||||
extension CameraSession {
|
||||
func setupPlatform() {
|
||||
// Intentionally empty.
|
||||
}
|
||||
}
|
||||
16
macos/Classes/Camera/CameraSettings.swift
Normal file
16
macos/Classes/Camera/CameraSettings.swift
Normal file
@@ -0,0 +1,16 @@
|
||||
import AppKit
|
||||
|
||||
/// macOS counterpart of the iOS `CameraSettings.openAppSettings`.
|
||||
/// There's no per-app deep link on macOS; we go straight to the
|
||||
/// Camera privacy pane in System Settings. The URL scheme has been
|
||||
/// stable since macOS 10.14.
|
||||
enum CameraSettings {
|
||||
@MainActor
|
||||
static func openAppSettings() {
|
||||
if let url = URL(
|
||||
string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Camera"
|
||||
) {
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
19
macos/Classes/Camera/DeviceOrientationBridge.swift
Normal file
19
macos/Classes/Camera/DeviceOrientationBridge.swift
Normal file
@@ -0,0 +1,19 @@
|
||||
import Foundation
|
||||
|
||||
/// macOS counterpart of `ios/Classes/Camera/DeviceOrientationBridge.swift`.
|
||||
/// Desktops don't rotate; the bridge is shaped identically to the iOS
|
||||
/// one so [CameraInstance] can call it without `#if` blocks, but
|
||||
/// `current` stays at `.portraitUp` and the listener never fires.
|
||||
final class DeviceOrientationBridge {
|
||||
typealias Listener = (DeviceOrientationFlutter) -> Void
|
||||
|
||||
private(set) var current: DeviceOrientationFlutter = .portraitUp
|
||||
|
||||
func start(listener: @escaping Listener) {
|
||||
// Intentionally empty — no rotation events on macOS.
|
||||
}
|
||||
|
||||
func stop() {
|
||||
// Intentionally empty — nothing to unwind.
|
||||
}
|
||||
}
|
||||
11
macos/Classes/Camera/FlutterRegistrar+macOS.swift
Normal file
11
macos/Classes/Camera/FlutterRegistrar+macOS.swift
Normal file
@@ -0,0 +1,11 @@
|
||||
import FlutterMacOS
|
||||
|
||||
/// macOS counterpart of `ios/Classes/Camera/FlutterRegistrar+iOS.swift`.
|
||||
/// On macOS, `FlutterPluginRegistrar.textures` and `.messenger` are
|
||||
/// properties (no parens) rather than methods. Shared `CameraPlugin`
|
||||
/// uses `registrar.uxTextures` and `registrar.uxMessenger` for
|
||||
/// surface parity.
|
||||
extension FlutterPluginRegistrar {
|
||||
var uxTextures: FlutterTextureRegistry { textures }
|
||||
var uxMessenger: FlutterBinaryMessenger { messenger }
|
||||
}
|
||||
@@ -9,6 +9,7 @@ public class UxPlugin: NSObject, FlutterPlugin {
|
||||
FilePlugin(),
|
||||
ClipboardPlugin(),
|
||||
GalleryPlugin(),
|
||||
CameraPlugin(),
|
||||
]
|
||||
for plugin in plugins {
|
||||
plugin.register(with: registrar)
|
||||
|
||||
Reference in New Issue
Block a user