环境
Flutter 3.29
macOS Sequoia 15.4.1
Xcode 16.3
集成
Flutter
提供了camera
插件来拍照和录视频,它提供了一系列可用的相机,并使用特定的相机展示相机预览、拍照、录视频。
添加依赖
- camera: 提供使用设备相机模块的工具
- path_provider: 寻找存储图片的正确路径
- path: 创建适配任何平台的路径
sh
flutter pub add camera path_provider path
执行完成后iOS工程的GeneratedPluginRegistrant.m
文件会自动生成对应的集成代码
objc
#if __has_include(<camera_avfoundation/CameraPlugin.h>)
#import <camera_avfoundation/CameraPlugin.h>
#else
@import camera_avfoundation;
#endif
#if __has_include(<path_provider_foundation/PathProviderPlugin.h>)
#import <path_provider_foundation/PathProviderPlugin.h>
#else
@import path_provider_foundation;
#endif
...
[CameraPlugin registerWithRegistrar:[registry registrarForPlugin:@"CameraPlugin"]];
[PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]];
分析
[registry registrarForPlugin:@"CameraPlugin"]
在AppDelegate.swfit
的application(_:didFinishLaunchingWithOptions:)
中将FlutterAppDelegate的子类AppDelegate对象作为参数传入并调用该方法
swift
GeneratedPluginRegistrant.register(with: self)
objc
- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
/// <1> 获取应用的flutterRootViewController对象
FlutterViewController* flutterRootViewController = [self rootFlutterViewController];
if (flutterRootViewController) {
/// <4> 返回一个FlutterEngine对象
return [[flutterRootViewController pluginRegistry] registrarForPlugin:pluginKey];
}
return nil;
}
// Returns the key window's rootViewController, if it's a FlutterViewController.
// Otherwise, returns nil.
- (FlutterViewController*)rootFlutterViewController {
///- (FlutterViewController*(^ rootFlutterViewControllerGetter) (void))
/// <2> 检查是否有外部注入,有则使用自定义的回调获取FlutterViewController对象
if (_rootFlutterViewControllerGetter != nil) {
return _rootFlutterViewControllerGetter();
}
/// <3> 没有则检查window的rootViewController属性,如果是FlutterViewController则返回,否则返回nil
UIViewController* rootViewController = _window.rootViewController;
if ([rootViewController isKindOfClass:[FlutterViewController class]]) {
return (FlutterViewController*)rootViewController;
}
return nil;
}
[flutterRootViewController pluginRegistry]
第<4>步中的方法调用在 FlutterViewController.mm
objc
/// pluginRegistry方法获得一个遵守FlutterPluginRegistry协议的对象
- (id<FlutterPluginRegistry>)pluginRegistry {
return self.engine;
}
...
/// engine是FlutterEngine对象
- (void)sharedSetupWithProject:(nullable FlutterDartProject*)project
initialRoute:(nullable NSString*)initialRoute {
...
engine = [[FlutterEngine alloc] initWithName:@"io.flutter"
project:project
allowHeadlessExecution:self.engineAllowHeadlessExecution
restorationEnabled:self.restorationIdentifier != nil];
...
_engine = engine;
...
- (instancetype)initWithEngine:(FlutterEngine*)engine
nibName:(nullable NSString*)nibName
bundle:(nullable NSBundle*)nibBundle {
...
_engine = engine;
FlutterPluginRegistry
协议的继承结构

FlutterEngine
对象调用registrarForPlugin:
方法
objc
/// 文件: FlutterEngine.mm
...
/**
* All registrars returned from registrarForPlugin:
*/
@property(nonatomic, readonly)
NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* pluginRegistrars;
...
- (id<FlutterPluginRegistrar>)registrarForPlugin:(NSString*)pluginName {
/// <5> 检查可变字典中是否已存在插件名的key
id<FlutterPluginRegistrar> registrar = self.pluginRegistrars[pluginName];
if (!registrar) {
/// <6> 首次注册,生成FlutterEngineRegistrar对象并持有pluginName和弱引用FlutterEngine 对象
/// 为什么是弱引用?
/// 文件:FlutterViewController.m 强引入了FlutterEngine对象
/// @property(nonatomic, readonly) FlutterEngine* engine;
FlutterEngineRegistrar* registrarImpl =
[[FlutterEngineRegistrar alloc] initWithPlugin:pluginName flutterEngine:self];
/// 接收传入的pluginName + self即FlutterEngine对象
/// @interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
/// @property(nonatomic, weak) FlutterEngine* flutterEngine;
/// @implementation FlutterEngineRegistrar {
/// NSString* _pluginKey;
/// }
/// 因为FlutterViewController.m 已经强引入了FlutterEngine对象,所以这里的flutterEngine弱引用即可
/// @property(nonatomic, readonly) FlutterEngine* engine;
///
/// <7> 添加到FlutterEngine对象的可变字典中
self.pluginRegistrars[pluginName] = registrarImpl;
registrar = registrarImpl;
}
/// <8> 返回FlutterEngineRegistrar注册对象,其中保存FlutterEngine相关的信息,负责与Flutter的iOS插件交互
return registrar;
}
[CameraPlugin registerWithRegistrar:
registrar]
swift
/// camera插件的类定义
public final class CameraPlugin: NSObject, FlutterPlugin {
objc
@protocol FlutterPlugin <NSObject, FlutterApplicationLifeCycleDelegate>
@required
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;
Flutter中的iOS插件遵守FlutterPlugin
协议且必须实现+registerWithRegistrar:
方法
以camera插件为例,CameraPlugin.swift是对外的Swift的接口包装
swift
public static func register(with registrar: FlutterPluginRegistrar) {
let instance = CameraPlugin(
/// 文件: FlutterEngine.mm
/// <9> 从FlutterEngineRegistrar对象中获取纹理的对象
/// - (NSObject<FlutterTextureRegistry>*)textures {
/// return _flutterEngine.textureRegistry;
/// }
registry: registrar.textures(),
/// Returns a `FlutterBinaryMessenger` for creating Dart/iOS communication
/// channels to be used by the plugin.
/// <10> 从FlutterEngineRegistrar返回Dart与iOS原生消息的对象
messenger: registrar.messenger(),
globalAPI: FCPCameraGlobalEventApi(binaryMessenger: registrar.messenger()),
deviceDiscoverer: FLTDefaultCameraDeviceDiscoverer(),
permissionManager: FLTCameraPermissionManager(
permissionService: FLTDefaultPermissionService()),
deviceFactory: { name in
// TODO(RobertOdrowaz) Implement better error handling and remove non-null assertion
FLTDefaultCaptureDevice(device: AVCaptureDevice(uniqueID: name)!)
},
captureSessionFactory: { FLTDefaultCaptureSession(captureSession: AVCaptureSession()) },
captureDeviceInputFactory: FLTDefaultCaptureDeviceInputFactory(),
captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue")
)
/// <11>设置Dart相机API的消息通道
SetUpFCPCameraApi(registrar.messenger(), instance)
}
registrar.messenger()
从前面可知registrar
是一个FlutterEngineRegistrar
objc
/// 文件: FlutterEngine.mm
@implementation FlutterEngineRegistrar {
...
- (NSObject<FlutterBinaryMessenger>*)messenger {
/// 返回的是FlutterEngineRegistrar对象绑定的FlutterEngine中的binaryMessenger属性
return _flutterEngine.binaryMessenger;
}
...
@implementation FlutterEngine {
...
FlutterBinaryMessengerRelay* _binaryMessenger;
...
/// FlutterEngine对象中的binaryMessenger属性是FlutterBinaryMessengerRelay对象
/// 且parent属性关联的是FlutterEngine对象
_binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self];
SetUpFCPCameraApi(registrar.messenger(), instance)
代码执行进入文件 message.g.m
objc
void SetUpFCPCameraApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger,
NSObject<FCPCameraApi> *api, NSString *messageChannelSuffix) {
messageChannelSuffix = messageChannelSuffix.length > 0
? [NSString stringWithFormat:@".%@", messageChannelSuffix]
: @"";
/// Returns the list of available cameras.
/// 建立设备的相机可用列表API
{
FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
initWithName:[NSString stringWithFormat:@"%@%@",
@"dev.flutter.pigeon.camera_avfoundation."
@"CameraApi.getAvailableCameras",
messageChannelSuffix]
binaryMessenger:binaryMessenger
codec:FCPGetMessagesCodec()];
if (api) {
NSCAssert(
[api respondsToSelector:@selector(availableCamerasWithCompletion:)],
@"FCPCameraApi api (%@) doesn't respond to @selector(availableCamerasWithCompletion:)",
api);
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
[api availableCamerasWithCompletion:^(
NSArray<FCPPlatformCameraDescription *> *_Nullable output,
FlutterError *_Nullable error) {
callback(wrapResult(output, error));
}];
}];
} else {
[channel setMessageHandler:nil];
}
}
...
/// 绑定一系列相机操作的API
FlutterBasicMessageChannel
类在FlutterChannel.m
中,先初始化一个FlutterBasicMessageChannel
对象,实现上只是接收外界参数
objc
- (instancetype)initWithName:(NSString*)name
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
codec:(NSObject<FlutterMessageCodec>*)codec
taskQueue:(NSObject<FlutterTaskQueue>*)taskQueue {
self = [super init];
NSAssert(self, @"Super init cannot be nil");
_name = [name copy];
_messenger = messenger;
_codec = codec;
_taskQueue = taskQueue;
return self;
}
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) ...];
接着判断入参的api
是否不为空,api
是生成的CameraPlugin
对象,所以不为空,然后消息的回调
objc
- (void)setMessageHandler:(FlutterMessageHandler)handler {
/// 未自定义回调时,这里应该是多次调用则清空上一次的,然后再重新创建
if (!handler) {
if (_connection > 0) {
[_messenger cleanUpConnection:_connection];
_connection = 0;
} else {
[_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
}
return;
}
// Grab reference to avoid retain on self.
// `self` might be released before the block, so the block needs to retain the codec to
// make sure it is not released with `self`
/// 从前面的代码可以知道这个self即channel对象只有一个局部对象在持有,所以超过作用域会被回收,所以这里接收到codec
NSObject<FlutterMessageCodec>* codec = _codec;
FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
handler([codec decode:message], ^(id reply) {
callback([codec encode:reply]);
});
};
_connection = SetMessageHandler(_messenger, _name, messageHandler, _taskQueue);
}
objc
static FlutterBinaryMessengerConnection SetMessageHandler(
NSObject<FlutterBinaryMessenger>* messenger,
NSString* name,
FlutterBinaryMessageHandler handler,
NSObject<FlutterTaskQueue>* taskQueue) {
/// 是否要在指定的任务队列上执行
/// name在这里是 dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras...
/// handler是设置的回调
/// 发送给FlutterBinaryMessengerRelay对象
if (taskQueue) {
NSCAssert([messenger respondsToSelector:@selector(setMessageHandlerOnChannel:
binaryMessageHandler:taskQueue:)],
@"");
return [messenger setMessageHandlerOnChannel:name
binaryMessageHandler:handler
taskQueue:taskQueue];
} else {
return [messenger setMessageHandlerOnChannel:name binaryMessageHandler:handler];
}
}
进入到FlutterBinaryMessengerRelay
对象的setMessageHandlerOnChannel:binaryMessageHandler:taskQueue:
文件: FlutterBinaryMessengerRelay.mm
objc
- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
binaryMessageHandler:(FlutterBinaryMessageHandler)handler
taskQueue:
(NSObject<FlutterTaskQueue>*)taskQueue {
/// parent就是engine对象,因此又回到engine上setMessageHandlerOnChannel:binaryMessageHandler: taskQueue:
if (self.parent) {
return [self.parent setMessageHandlerOnChannel:channel
binaryMessageHandler:handler
taskQueue:taskQueue];
} else {
FML_LOG(WARNING) << "Communicating on a dead channel.";
return -1;
}
}
文件: FlutterEngine.mm
objc
- (FlutterBinaryMessengerConnection)
setMessageHandlerOnChannel:(NSString*)channel
binaryMessageHandler:(FlutterBinaryMessageHandler)handler
taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
NSParameterAssert(channel);
if (_shell && _shell->IsSetup()) {
/// 获取原生平台的线程,并传入channel名,回调,任务队列
self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String,
handler, taskQueue);
/// std::unique_ptr<flutter::ConnectionCollection> _connections;
///
/// 文件:connection_collection.mm
/// ConnectionCollection::Connection ConnectionCollection::AquireConnection(const std::string& name) {
/// Connection nextConnection = ++counter_;
/// connections_[name] = nextConnection;
/// return nextConnection;
/// }
/// FlutterEngine对象中的连接集合属性,AcquireConnection方法让connections字典中key为channel的计数加1
return _connections->AquireConnection(channel.UTF8String);
} else {
NSAssert(!handler, @"Setting a message handler before the FlutterEngine has been run.");
// Setting a handler to nil for a channel that has not yet been set up is a no-op.
return flutter::ConnectionCollection::MakeErrorConnection(-1);
}
}
文件: platform_view_ios.h
objc
/// 调用GetPlatformMessageHandlerIos即返回platform_message_handler_属性
class PlatformViewIOS final : public PlatformView {
...
std::shared_ptr<PlatformMessageHandlerIos> GetPlatformMessageHandlerIos() const {
return platform_message_handler_;
}
...
文件: platform_view_ios.mm
objc
PlatformViewIOS::PlatformViewIOS(PlatformView::Delegate& delegate,
const std::shared_ptr<IOSContext>& context,
__weak FlutterPlatformViewsController* platform_views_controller,
const flutter::TaskRunners& task_runners)
: PlatformView(delegate, task_runners),
ios_context_(context),
platform_views_controller_(platform_views_controller),
accessibility_bridge_([this](bool enabled) { PlatformView::SetSemanticsEnabled(enabled); }),
/// 从初始化列表中可以看出platform_message_handler_的值通过GetPlatformTaskRunner获取UI的主线程
platform_message_handler_(
new PlatformMessageHandlerIos(task_runners.GetPlatformTaskRunner())) {}
到这里Flutter的插件的原生代码部分已经将channel
,回调,执行队列(可选)给原生平台的主线程。
获取可用相机列表
dart
/// Dart端调用获取可用摄像头列表
final cameras = await availableCameras();
文件: camera_controller.dart
dart
/// Completes with a list of available cameras.
///
/// May throw a [CameraException].
Future<List<CameraDescription>> availableCameras() async {
return CameraPlatform.instance.availableCameras();
}
调用CameraPlatform
对象的availableCameras
方法
文件: camera_platform.dart
dart
abstract class CameraPlatform extends PlatformInterface {
/// Constructs a CameraPlatform.
CameraPlatform() : super(token: _token);
...
/// Completes with a list of available cameras.
///
/// This method returns an empty list when no cameras are available.
Future<List<CameraDescription>> availableCameras() {
throw UnimplementedError('availableCameras() is not implemented.');
}
CameraPlatform
是个抽象类,要找具体的实现。找到camera插件的pubspec.yaml
yaml
flutter:
plugin:
implements: camera
platforms:
ios:
pluginClass: CameraPlugin
dartPluginClass: AVFoundationCamera
dartPluginClass: Optional. The Dart class that serves as the entry point for a Flutter plugin. This can be used with the Android, iOS, Linux macOS, and Windows platforms.
因此camera
插件dart
的入口应该是AVFoundationCamera
这个类,它继承了上面的CameraPlatform
抽象类
文件: avfoundation_camera.dart
dart
class AVFoundationCamera extends CameraPlatform {
/// Creates a new AVFoundation-based [CameraPlatform] implementation instance.
AVFoundationCamera({@visibleForTesting CameraApi? api})
: _hostApi = api ?? CameraApi();
...
@override
Future<List<CameraDescription>> availableCameras() async {
try {
return (await _hostApi.getAvailableCameras())
.map(cameraDescriptionFromPlatform)
.toList();
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}
从上面代码可知实际调用的是_hostApi
的getAvailableCameras
方法
dart
Future<List<PlatformCameraDescription>> getAvailableCameras() async {
/// 前面建立channel时已经传入了,这样原生执行完相关方法后能通过channel调用对应的回调
final String pigeonVar_channelName =
'dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras$pigeonVar_messageChannelSuffix';
/// A named channel for communicating with platform plugins using asynchronous message passing.
/// 创建异步消息
final BasicMessageChannel<Object?> pigeonVar_channel =
BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
/// 阻塞**发送消息**
final List<Object?>? pigeonVar_replyList =
await pigeonVar_channel.send(null) as List<Object?>?;
/// 消息为空抛异常
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else if (pigeonVar_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
/// 得到可用列表转换为Flutter上的摄像头描述的对象
return (pigeonVar_replyList[0] as List<Object?>?)!
.cast<PlatformCameraDescription>();
}
}
await pigeonVar_channel.send(null) as List<Object?>?;
dart
/// Sends the specified [message] to the platform plugins on this channel.
///
/// Returns a [Future] which completes to the received response, which may
/// be null.
Future<T?> send(T message) async {
/// 调用binaryMessenger对象编码发送消息 && 得到返回后再解码
return codec.decodeMessage(await binaryMessenger.send(name, codec.encodeMessage(message)));
}
Flutter Dart端发送指定channel消息 && 调用原来添加的回调走到Flutter原生插件部分这里,比如当前走到获取可用摄像头的回调
swift
...
[api availableCamerasWithCompletion:^(
NSArray<FCPPlatformCameraDescription *> *_Nullable output,
FlutterError *_Nullable error) {
callback(wrapResult(output, error));
}];
即调用api(CameraPlugin)的availableCamerasWithCompletion:方法
swift
extension CameraPlugin: FCPCameraApi {
public func availableCameras(
completion: @escaping ([FCPPlatformCameraDescription]?, FlutterError?) -> Void
) {
captureSessionQueue.async { [weak self] in
guard let strongSelf = self else { return }
var discoveryDevices: [AVCaptureDevice.DeviceType] = [
.builtInWideAngleCamera,
.builtInTelephotoCamera,
]
...
/// 前置,后置等摄像头,然后统一添加到reply这个数组对象
for device in devices {
var lensFacing: FCPPlatformCameraLensDirection
switch device.position {
case .back:
lensFacing = .back
case .front:
lensFacing = .front
case .unspecified:
...
}
reply.append(cameraDescription)
}
/// 最后执行callback(wrapResult(output, error));
/// 获取成功后,Flutter的Dart部分可以获取到可用的摄像头列表
completion(reply, nil)
}
总结

- 原生插件将方法的channel(约定的字符串),回调设置给Flutter原生平台代码(C++ && OC)
- Flutter的Dart层发送消息并传递channel,Flutter根据channel找到设置的回调(Dart -> C++ && OC),然后执行原生插件提供的方法(C++ && OC)
- 获取执行结果并返回给Flutter的原生平台代码(C++ && OC),再发送给Dart代码(C++ && OC -> Dart)