Flutter - 原生交互 - 相机Camera - 01

[复制链接]
发表于 2025-7-5 23:59:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
情况

   Flutter 3.29
  macOS Sequoia 15.4.1
  Xcode 16.3
  集成

Flutter提供了camera插件来拍照和录视频,它提供了一系列可用的相机,并利用特定的相机展示相机预览、拍照、录视频。
添加依赖



  • camera: 提供利用设备相机模块的工具
  • path_provider: 寻找存储图片的精确路径
  • path: 创建适配任何平台的路径
  1. flutter pub add camera path_provider path
复制代码
执行完成后iOS工程的GeneratedPluginRegistrant.m文件会自动天生对应的集成代码
  1. #if __has_include(<camera_avfoundation/CameraPlugin.h>)
  2. #import <camera_avfoundation/CameraPlugin.h>
  3. #else
  4. @import camera_avfoundation;
  5. #endif
  6. #if __has_include(<path_provider_foundation/PathProviderPlugin.h>)
  7. #import <path_provider_foundation/PathProviderPlugin.h>
  8. #else
  9. @import path_provider_foundation;
  10. #endif
  11. ...
  12. [CameraPlugin registerWithRegistrar:[registry registrarForPlugin:@"CameraPlugin"]];
  13. [PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]];
复制代码
分析

[registry registrarForPlugin“CameraPlugin”]

在AppDelegate.swfit的application(_:didFinishLaunchingWithOptions中将FlutterAppDelegate的子类AppDelegate对象作为参数传入并调用该方法
  1. GeneratedPluginRegistrant.register(with: self)
复制代码
源码: FlutterAppDelegate.mm
  1. - (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
  2.   /// <1> 获取应用的flutterRootViewController对象
  3.   FlutterViewController* flutterRootViewController = [self rootFlutterViewController];
  4.   if (flutterRootViewController) {
  5.     /// <4> 返回一个FlutterEngine对象
  6.     return [[flutterRootViewController pluginRegistry] registrarForPlugin:pluginKey];
  7.   }
  8.   return nil;
  9. }
  10. // Returns the key window's rootViewController, if it's a FlutterViewController.
  11. // Otherwise, returns nil.
  12. - (FlutterViewController*)rootFlutterViewController {
  13.   ///- (FlutterViewController*(^ rootFlutterViewControllerGetter) (void))
  14.   /// <2> 检查是否有外部注入,有则使用自定义的回调获取FlutterViewController对象
  15.   if (_rootFlutterViewControllerGetter != nil) {
  16.     return _rootFlutterViewControllerGetter();
  17.   }
  18.   /// <3> 没有则检查window的rootViewController属性,如果是FlutterViewController则返回,否则返回nil
  19.   UIViewController* rootViewController = _window.rootViewController;
  20.   if ([rootViewController isKindOfClass:[FlutterViewController class]]) {
  21.     return (FlutterViewController*)rootViewController;
  22.   }
  23.   return nil;
  24. }
复制代码
[flutterRootViewController pluginRegistry]

第<4>步中的方法调用在 FlutterViewController.mm
  1. ///  pluginRegistry方法获得一个遵守FlutterPluginRegistry协议的对象
  2. - (id<FlutterPluginRegistry>)pluginRegistry {
  3.     return self.engine;
  4. }
  5. ...
  6. /// engine是FlutterEngine对象
  7. - (void)sharedSetupWithProject:(nullable FlutterDartProject*)project
  8.                   initialRoute:(nullable NSString*)initialRoute {
  9. ...
  10. engine = [[FlutterEngine alloc] initWithName:@"io.flutter"
  11.                                          project:project
  12.                           allowHeadlessExecution:self.engineAllowHeadlessExecution
  13.                               restorationEnabled:self.restorationIdentifier != nil];
  14. ...
  15. _engine = engine;
  16. ...              
  17. - (instancetype)initWithEngine:(FlutterEngine*)engine
  18.                        nibName:(nullable NSString*)nibName
  19.                         bundle:(nullable NSBundle*)nibBundle {
  20. ...
  21. _engine = engine;         
复制代码
FlutterPluginRegistry协议的继承布局

FlutterEngine对象调用registrarForPlugin:方法

源码: FlutterEngine.mm
  1. /// 文件: FlutterEngine.mm
  2. ...
  3. /**
  4. * All registrars returned from registrarForPlugin:
  5. */
  6. @property(nonatomic, readonly)
  7.     NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* pluginRegistrars;
  8. ...
  9. - (id<FlutterPluginRegistrar>)registrarForPlugin:(NSString*)pluginName {
  10.   /// <5> 检查可变字典中是否已存在插件名的key
  11.   id<FlutterPluginRegistrar> registrar = self.pluginRegistrars[pluginName];
  12.   if (!registrar) {
  13.     /// <6> 首次注册,生成FlutterEngineRegistrar对象并持有pluginName和弱引用FlutterEngine 对象
  14.     /// 为什么是弱引用?
  15.     /// 文件:FlutterViewController.m 强引入了FlutterEngine对象
  16.     /// @property(nonatomic, readonly) FlutterEngine* engine;
  17.    
  18.     FlutterEngineRegistrar* registrarImpl =
  19.         [[FlutterEngineRegistrar alloc] initWithPlugin:pluginName flutterEngine:self];
  20.     /// 接收传入的pluginName  + self即FlutterEngine对象
  21.     /// @interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
  22.     /// @property(nonatomic, weak) FlutterEngine* flutterEngine;
  23.     /// @implementation FlutterEngineRegistrar {
  24.     ///   NSString* _pluginKey;
  25.     /// }
  26.    
  27.     /// 因为FlutterViewController.m 已经强引入了FlutterEngine对象,所以这里的flutterEngine弱引用即可
  28.     /// @property(nonatomic, readonly) FlutterEngine* engine;
  29.     ///
  30.     /// <7> 添加到FlutterEngine对象的可变字典中
  31.     self.pluginRegistrars[pluginName] = registrarImpl;
  32.     registrar = registrarImpl;
  33.   }
  34.   /// <8> 返回FlutterEngineRegistrar注册对象,其中保存FlutterEngine相关的信息,负责与Flutter的iOS插件交互
  35.   return registrar;
  36. }
复制代码
[CameraPlugin registerWithRegistrar:registrar]

  1. /// camera插件的类定义
  2. public final class CameraPlugin: NSObject, FlutterPlugin {
复制代码
  1. @protocol FlutterPlugin <NSObject, FlutterApplicationLifeCycleDelegate>
  2. @required
  3. + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;
复制代码
Flutter中的iOS插件服从FlutterPlugin协议且必须实现+registerWithRegistrar:方法
以camera插件为例,CameraPlugin.swift是对外的Swift的接口包装
  1. public static func register(with registrar: FlutterPluginRegistrar) {
  2.     let instance = CameraPlugin(
  3.       /// 文件: FlutterEngine.mm
  4.       /// <9> 从FlutterEngineRegistrar对象中获取纹理的对象
  5.       /// - (NSObject<FlutterTextureRegistry>*)textures {
  6.       ///   return _flutterEngine.textureRegistry;
  7.       /// }
  8.       registry: registrar.textures(),
  9.       /// Returns a `FlutterBinaryMessenger` for creating Dart/iOS communication
  10.       /// channels to be used by the plugin.
  11.       /// <10> 从FlutterEngineRegistrar返回Dart与iOS原生消息的对象
  12.       messenger: registrar.messenger(),
  13.       globalAPI: FCPCameraGlobalEventApi(binaryMessenger: registrar.messenger()),
  14.       deviceDiscoverer: FLTDefaultCameraDeviceDiscoverer(),
  15.       permissionManager: FLTCameraPermissionManager(
  16.         permissionService: FLTDefaultPermissionService()),
  17.       deviceFactory: { name in
  18.         // TODO(RobertOdrowaz) Implement better error handling and remove non-null assertion
  19.         FLTDefaultCaptureDevice(device: AVCaptureDevice(uniqueID: name)!)
  20.       },
  21.       captureSessionFactory: { FLTDefaultCaptureSession(captureSession: AVCaptureSession()) },
  22.       captureDeviceInputFactory: FLTDefaultCaptureDeviceInputFactory(),
  23.       captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue")
  24.     )
  25.    
  26.     /// <11>设置Dart相机API的消息通道
  27.     SetUpFCPCameraApi(registrar.messenger(), instance)
  28.   }
复制代码
registrar.messenger()

从前面可知registrar是一个FlutterEngineRegistrar
  1. /// 文件: FlutterEngine.mm
  2. @implementation FlutterEngineRegistrar {
  3. ...
  4. - (NSObject<FlutterBinaryMessenger>*)messenger {
  5.   /// 返回的是FlutterEngineRegistrar对象绑定的FlutterEngine中的binaryMessenger属性
  6.   return _flutterEngine.binaryMessenger;
  7. }
  8. ...
  9. @implementation FlutterEngine {
  10. ...
  11. FlutterBinaryMessengerRelay* _binaryMessenger;
  12. ...
  13. /// FlutterEngine对象中的binaryMessenger属性是FlutterBinaryMessengerRelay对象
  14. /// 且parent属性关联的是FlutterEngine对象
  15. _binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self];
复制代码
SetUpFCPCameraApi(registrar.messenger(), instance)

代码执行进入文件 message.g.m
  1. void SetUpFCPCameraApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger,
  2.                                  NSObject<FCPCameraApi> *api, NSString *messageChannelSuffix) {
  3.   messageChannelSuffix = messageChannelSuffix.length > 0
  4.                              ? [NSString stringWithFormat:@".%@", messageChannelSuffix]
  5.                              : @"";
  6.   /// Returns the list of available cameras.
  7.   /// 建立设备的相机可用列表API
  8.   {
  9.     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
  10.            initWithName:[NSString stringWithFormat:@"%@%@",
  11.                                                    @"dev.flutter.pigeon.camera_avfoundation."
  12.                                                    @"CameraApi.getAvailableCameras",
  13.                                                    messageChannelSuffix]
  14.         binaryMessenger:binaryMessenger
  15.                   codec:FCPGetMessagesCodec()];
  16.     if (api) {
  17.       NSCAssert(
  18.           [api respondsToSelector:@selector(availableCamerasWithCompletion:)],
  19.           @"FCPCameraApi api (%@) doesn't respond to @selector(availableCamerasWithCompletion:)",
  20.           api);
  21.       [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
  22.         [api availableCamerasWithCompletion:^(
  23.                  NSArray<FCPPlatformCameraDescription *> *_Nullable output,
  24.                  FlutterError *_Nullable error) {
  25.           callback(wrapResult(output, error));
  26.         }];
  27.       }];
  28.     } else {
  29.       [channel setMessageHandler:nil];
  30.     }
  31.   }
  32.   ...
  33.   /// 绑定一系列相机操作的API
  34.                                  
复制代码
FlutterBasicMessageChannel类在FlutterChannel.m中,先初始化一个FlutterBasicMessageChannel对象,实现上只是接收外界参数
  1. - (instancetype)initWithName:(NSString*)name
  2.              binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
  3.                        codec:(NSObject<FlutterMessageCodec>*)codec
  4.                    taskQueue:(NSObject<FlutterTaskQueue>*)taskQueue {
  5.   self = [super init];
  6.   NSAssert(self, @"Super init cannot be nil");
  7.   _name = [name copy];
  8.   _messenger = messenger;
  9.   _codec = codec;
  10.   _taskQueue = taskQueue;
  11.   return self;
  12. }
复制代码
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) ...];

接着判断入参的api是否不为空,api是天生的CameraPlugin对象,以是不为空,然后消息的回调
  1. - (void)setMessageHandler:(FlutterMessageHandler)handler {
  2.   /// 未自定义回调时,这里应该是多次调用则清空上一次的,然后再重新创建
  3.   if (!handler) {
  4.     if (_connection > 0) {
  5.       [_messenger cleanUpConnection:_connection];
  6.       _connection = 0;
  7.     } else {
  8.       [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
  9.     }
  10.     return;
  11.   }
  12.   // Grab reference to avoid retain on self.
  13.   // `self` might be released before the block, so the block needs to retain the codec to
  14.   // make sure it is not released with `self`
  15.   /// 从前面的代码可以知道这个self即channel对象只有一个局部对象在持有,所以超过作用域会被回收,所以这里接收到codec
  16.   NSObject<FlutterMessageCodec>* codec = _codec;
  17.   FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
  18.     handler([codec decode:message], ^(id reply) {
  19.       callback([codec encode:reply]);
  20.     });
  21.   };
  22.   _connection = SetMessageHandler(_messenger, _name, messageHandler, _taskQueue);
  23. }
复制代码
  1. static FlutterBinaryMessengerConnection SetMessageHandler(
  2.     NSObject<FlutterBinaryMessenger>* messenger,
  3.     NSString* name,
  4.     FlutterBinaryMessageHandler handler,
  5.     NSObject<FlutterTaskQueue>* taskQueue) {
  6.   /// 是否要在指定的任务队列上执行
  7.   /// name在这里是 dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras...
  8.   /// handler是设置的回调
  9.   /// 发送给FlutterBinaryMessengerRelay对象
  10.   if (taskQueue) {
  11.     NSCAssert([messenger respondsToSelector:@selector(setMessageHandlerOnChannel:
  12.                                                             binaryMessageHandler:taskQueue:)],
  13.               @"");
  14.     return [messenger setMessageHandlerOnChannel:name
  15.                             binaryMessageHandler:handler
  16.                                        taskQueue:taskQueue];
  17.   } else {
  18.     return [messenger setMessageHandlerOnChannel:name binaryMessageHandler:handler];
  19.   }
  20. }
复制代码
进入到FlutterBinaryMessengerRelay对象的setMessageHandlerOnChannel:binaryMessageHandler:taskQueue:
文件: FlutterBinaryMessengerRelay.mm
  1. - (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
  2.                                           binaryMessageHandler:(FlutterBinaryMessageHandler)handler
  3.                                                      taskQueue:
  4.                                                          (NSObject<FlutterTaskQueue>*)taskQueue {
  5.   /// parent就是engine对象,因此又回到engine上setMessageHandlerOnChannel:binaryMessageHandler:                                         taskQueue:
  6.   if (self.parent) {
  7.     return [self.parent setMessageHandlerOnChannel:channel
  8.                               binaryMessageHandler:handler
  9.                                          taskQueue:taskQueue];
  10.   } else {
  11.     FML_LOG(WARNING) << "Communicating on a dead channel.";
  12.     return -1;
  13.   }
  14. }
复制代码
文件: FlutterEngine.mm
  1. - (FlutterBinaryMessengerConnection)
  2.     setMessageHandlerOnChannel:(NSString*)channel
  3.           binaryMessageHandler:(FlutterBinaryMessageHandler)handler
  4.                      taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
  5.   NSParameterAssert(channel);
  6.   if (_shell && _shell->IsSetup()) {
  7.     /// 获取原生平台的线程,并传入channel名,回调,任务队列
  8.     self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String,
  9.                                                                          handler, taskQueue);
  10.     /// std::unique_ptr<flutter::ConnectionCollection> _connections;
  11.     ///
  12.     ///  文件:connection_collection.mm
  13.     ///  ConnectionCollection::Connection   ConnectionCollection::AquireConnection(const std::string& name) {
  14.     ///   Connection nextConnection = ++counter_;
  15.     ///   connections_[name] = nextConnection;
  16.     ///   return nextConnection;
  17.     /// }
  18.     /// FlutterEngine对象中的连接集合属性,AcquireConnection方法让connections字典中key为channel的计数加1
  19.     return _connections->AquireConnection(channel.UTF8String);
  20.   } else {
  21.     NSAssert(!handler, @"Setting a message handler before the FlutterEngine has been run.");
  22.     // Setting a handler to nil for a channel that has not yet been set up is a no-op.
  23.     return flutter::ConnectionCollection::MakeErrorConnection(-1);
  24.   }
  25. }
复制代码
文件: platform_view_ios.h
  1. /// 调用GetPlatformMessageHandlerIos即返回platform_message_handler_属性
  2. class PlatformViewIOS final : public PlatformView {
  3. ...
  4. std::shared_ptr<PlatformMessageHandlerIos> GetPlatformMessageHandlerIos() const {
  5.     return platform_message_handler_;
  6.   }
  7. ...
复制代码
文件: platform_view_ios.mm
  1. PlatformViewIOS::PlatformViewIOS(PlatformView::Delegate& delegate,
  2.                                  const std::shared_ptr<IOSContext>& context,
  3.                                  __weak FlutterPlatformViewsController* platform_views_controller,
  4.                                  const flutter::TaskRunners& task_runners)
  5.     : PlatformView(delegate, task_runners),
  6.       ios_context_(context),
  7.       platform_views_controller_(platform_views_controller),
  8.       accessibility_bridge_([this](bool enabled) { PlatformView::SetSemanticsEnabled(enabled); }),
  9.       /// 从初始化列表中可以看出platform_message_handler_的值通过GetPlatformTaskRunner获取UI的主线程
  10.       platform_message_handler_(
  11.           new PlatformMessageHandlerIos(task_runners.GetPlatformTaskRunner())) {}
复制代码
到这里Flutter的插件的原生代码部分已经将channel,回调,执行队列(可选)给原生平台的主线程。
获取可用相机列表

  1. /// Dart端调用获取可用摄像头列表
  2. final cameras = await availableCameras();
复制代码
文件: camera_controller.dart
  1. /// Completes with a list of available cameras.
  2. ///
  3. /// May throw a [CameraException].
  4. Future<List<CameraDescription>> availableCameras() async {
  5.   return CameraPlatform.instance.availableCameras();
  6. }
复制代码
调用CameraPlatform对象的availableCameras方法
文件: camera_platform.dart
  1. abstract class CameraPlatform extends PlatformInterface {
  2.   /// Constructs a CameraPlatform.
  3.   CameraPlatform() : super(token: _token);
  4.   ...
  5.   /// Completes with a list of available cameras.
  6.   ///
  7.   /// This method returns an empty list when no cameras are available.
  8.   Future<List<CameraDescription>> availableCameras() {
  9.     throw UnimplementedError('availableCameras() is not implemented.');
  10.   }
复制代码
CameraPlatform是个抽象类,要找详细的实现。找到camera插件的pubspec.yaml
  1. flutter:
  2.   plugin:
  3.     implements: camera
  4.     platforms:
  5.       ios:
  6.         pluginClass: CameraPlugin
  7.         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
  1. class AVFoundationCamera extends CameraPlatform {
  2.   /// Creates a new AVFoundation-based [CameraPlatform] implementation instance.
  3.   AVFoundationCamera({@visibleForTesting CameraApi? api})
  4.       : _hostApi = api ?? CameraApi();
  5.   ...
  6.   @override
  7.   Future<List<CameraDescription>> availableCameras() async {
  8.     try {
  9.       return (await _hostApi.getAvailableCameras())
  10.           .map(cameraDescriptionFromPlatform)
  11.           .toList();
  12.     } on PlatformException catch (e) {
  13.       throw CameraException(e.code, e.message);
  14.     }
  15.   }
复制代码
从上面代码可知实际调用的是_hostApi的getAvailableCameras方法
  1. Future<List<PlatformCameraDescription>> getAvailableCameras() async {
  2.     /// 前面建立channel时已经传入了,这样原生执行完相关方法后能通过channel调用对应的回调
  3.     final String pigeonVar_channelName =
  4.         'dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras$pigeonVar_messageChannelSuffix';
  5.    
  6.     /// A named channel for communicating with platform plugins using asynchronous message passing.
  7.     /// 创建异步消息
  8.     final BasicMessageChannel<Object?> pigeonVar_channel =
  9.         BasicMessageChannel<Object?>(
  10.       pigeonVar_channelName,
  11.       pigeonChannelCodec,
  12.       binaryMessenger: pigeonVar_binaryMessenger,
  13.     );
  14.     /// 阻塞**发送消息**
  15.     final List<Object?>? pigeonVar_replyList =
  16.         await pigeonVar_channel.send(null) as List<Object?>?;
  17.    
  18.     /// 消息为空抛异常
  19.     if (pigeonVar_replyList == null) {
  20.       throw _createConnectionError(pigeonVar_channelName);
  21.     } else if (pigeonVar_replyList.length > 1) {
  22.       throw PlatformException(
  23.         code: pigeonVar_replyList[0]! as String,
  24.         message: pigeonVar_replyList[1] as String?,
  25.         details: pigeonVar_replyList[2],
  26.       );
  27.     } else if (pigeonVar_replyList[0] == null) {
  28.       throw PlatformException(
  29.         code: 'null-error',
  30.         message: 'Host platform returned null value for non-null return value.',
  31.       );
  32.     } else {
  33.       /// 得到可用列表转换为Flutter上的摄像头描述的对象
  34.       return (pigeonVar_replyList[0] as List<Object?>?)!
  35.           .cast<PlatformCameraDescription>();
  36.     }
  37.   }
复制代码
await pigeonVar_channel.send(null) as List<Object?>?;

  1. /// Sends the specified [message] to the platform plugins on this channel.
  2.   ///
  3.   /// Returns a [Future] which completes to the received response, which may
  4.   /// be null.
  5.   Future<T?> send(T message) async {
  6.     /// 调用binaryMessenger对象编码发送消息 && 得到返回后再解码
  7.     return codec.decodeMessage(await binaryMessenger.send(name, codec.encodeMessage(message)));
  8.   }
复制代码
Flutter Dart端发送指定channel消息 && 调用原来添加的回调走到Flutter原生插件部分这里,好比当前走到获取可用摄像头的回调
  1. ...
  2. [api availableCamerasWithCompletion:^(
  3.                  NSArray<FCPPlatformCameraDescription *> *_Nullable output,
  4.                  FlutterError *_Nullable error) {
  5.           callback(wrapResult(output, error));
  6.         }];
复制代码
即调用api(CameraPlugin)的availableCamerasWithCompletion:方法
  1. extension CameraPlugin: FCPCameraApi {
  2.   public func availableCameras(
  3.     completion: @escaping ([FCPPlatformCameraDescription]?, FlutterError?) -> Void
  4.   ) {
  5.     captureSessionQueue.async { [weak self] in
  6.       guard let strongSelf = self else { return }
  7.       var discoveryDevices: [AVCaptureDevice.DeviceType] = [
  8.         .builtInWideAngleCamera,
  9.         .builtInTelephotoCamera,
  10.       ]
  11.       ...
  12.       /// 前置,后置等摄像头,然后统一添加到reply这个数组对象
  13.       for device in devices {
  14.         var lensFacing: FCPPlatformCameraLensDirection
  15.         switch device.position {
  16.         case .back:
  17.           lensFacing = .back
  18.         case .front:
  19.           lensFacing = .front
  20.         case .unspecified:
  21.       ...
  22.         }
  23.         reply.append(cameraDescription)
  24.       }
  25.       
  26.       /// 最后执行callback(wrapResult(output, error));
  27.       /// 获取成功后,Flutter的Dart部分可以获取到可用的摄像头列表
  28.       completion(reply, nil)
  29. }
复制代码
总结



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


  • camera
  • 利用 Camera 插件实现拍照功能
  • do-not-use-buildcontexts-across-async-gaps
  • Flutter pubspec options
  • 一张图明白Flutter中Dart与原生情况通信
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表