FileSelectorPlugin

import Cocoa
import FlutterMacOS
import UniformTypeIdentifiers
/// Protocol for showing panels, allowing for depenedency injection in tests.
protocol PanelController {
  /// Displays the given save panel, and provides the selected URL, or nil if the panel is
  /// cancelled, to the handler.
  /// - Parameters:
  ///   - panel: The panel to show.
  ///   - window: The window to display the panel for.
  ///   - completionHandler: The completion handler to receive the results.
  func display(
    _ panel: NSSavePanel,
    for window: NSWindow?,
}
/// Protocol to provide access to the Flutter view, allowing for dependency injection in tests.
///
/// This is necessary because Swift doesn't allow for only partially implementing a protocol, so
/// a stub implementation of FlutterPluginRegistrar for tests would break any time something was
/// added to that protocol.
protocol ViewProvider {
  /// Returns the view associated with the Flutter content.
  var view: NSView? { get }
}
public class FileSelectorPlugin: NSObject, FlutterPlugin, FileSelectorApi {
  private let viewProvider: ViewProvider
  private let panelController: PanelController
  private let openMethod = "openFile"
  private let openDirectoryMethod = "getDirectoryPath"
  private let saveMethod = "getSavePath"
  var forceLegacyTypes = false
  public static func register(with registrar: FlutterPluginRegistrar) {
    let instance = FileSelectorPlugin(
      viewProvider: DefaultViewProvider(registrar: registrar),
      panelController: DefaultPanelController())
    FileSelectorApiSetup.setUp(binaryMessenger: registrar.messenger, api: instance)
  }
  init(viewProvider: ViewProvider, panelController: PanelController) {
    self.viewProvider = viewProvider
    self.panelController = panelController
  }
  func displayOpenPanel(
  ) {
    let panel = NSSavePanel()
    configure(panel: panel, with: options)
    panelController.display(panel, for: viewProvider.view?.window) { (selection: URL?) in
      completion(.success(selection?.path))
    }
  }
  /// Configures an NSSavePanel based on channel method call arguments.
  /// - Parameters:
  ///   - panel: The panel to configure.
  ///   - arguments: The arguments dictionary from a FlutterMethodCall to this plugin.
  private func configure(panel: NSSavePanel, with options: SavePanelOptions) {
    if let directoryPath = options.directoryPath {
      panel.directoryURL = URL(fileURLWithPath: directoryPath)
    }
    if let suggestedName = options.nameFieldStringValue {
      panel.nameFieldStringValue = suggestedName
    }
    if let prompt = options.prompt {
      panel.prompt = prompt
    }
    if let acceptedTypes = options.allowedFileTypes {
      if #available(macOS 11, *), !forceLegacyTypes {
        var allowedTypes: [UTType] = []
        // The array values are non-null by convention even though Pigeon can't currently express
        // that via the types; see messages.dart and https://github.com/flutter/flutter/issues/97848
        allowedTypes.append(contentsOf: acceptedTypes.utis.compactMap({ UTType($0!) }))
        allowedTypes.append(
          contentsOf: acceptedTypes.extensions.flatMap({
            UTType.types(tag: $0!, tagClass: UTTagClass.filenameExtension, conformingTo: nil)
          }))
        allowedTypes.append(
          contentsOf: acceptedTypes.mimeTypes.flatMap({
            UTType.types(tag: $0!, tagClass: UTTagClass.mimeType, conformingTo: nil)
          }))
        if !allowedTypes.isEmpty {
          panel.allowedContentTypes = allowedTypes
        }
      } else {
        var allowedTypes: [String] = []
        // The array values are non-null by convention even though Pigeon can't currently express
        // that via the types; see messages.dart and https://github.com/flutter/flutter/issues/97848
        allowedTypes.append(contentsOf: acceptedTypes.extensions.map({ $0! }))
        allowedTypes.append(contentsOf: acceptedTypes.utis.map({ $0! }))
        if !allowedTypes.isEmpty {
          panel.allowedFileTypes = allowedTypes
        }
      }
    }
  }
  /// Configures an NSOpenPanel based on channel method call arguments.
  /// - Parameters:
  ///   - panel: The panel to configure.
  ///   - arguments: The arguments dictionary from a FlutterMethodCall to this plugin.
  ///   - choosingDirectory: True if the panel should allow choosing directories rather than files.
  private func configure(
    openPanel panel: NSOpenPanel,
    with options: OpenPanelOptions
  ) {
    configure(panel: panel, with: options.baseOptions)
    panel.allowsMultipleSelection = options.allowsMultipleSelection
    panel.canChooseDirectories = options.canChooseDirectories
    panel.canChooseFiles = options.canChooseFiles
  }
}
/// Non-test implementation of PanelController that calls the standard methods to display the panel
/// either as a sheet (if a window is provided) or modal (if not).
private class DefaultPanelController: PanelController {
  func display(
    _ panel: NSSavePanel,
    for window: NSWindow?,
  ) {
    let completionAdapter = { response in
      completionHandler((response == NSApplication.ModalResponse.OK) ? panel.url : nil)
    }
    if let window = window {
      panel.beginSheetModal(for: window, completionHandler: completionAdapter)
    } else {
      completionAdapter(panel.runModal())
    }
  }
  func display(
    _ panel: NSOpenPanel,
    for window: NSWindow?,
  ) {
    let completionAdapter = { response in
      completionHandler((response == NSApplication.ModalResponse.OK) ? panel.urls : nil)
    }
    if let window = window {
      panel.beginSheetModal(for: window, completionHandler: completionAdapter)
    } else {
      completionAdapter(panel.runModal())
    }
  }
}
/// Non-test implementation of PanelController that forwards to the plugin registrar.
private class DefaultViewProvider: ViewProvider {
  private let registrar: FlutterPluginRegistrar
  init(registrar: FlutterPluginRegistrar) {
    self.registrar = registrar
  }
  var view: NSView? {
    registrar.view
  }
}


messages.g

// Autogenerated from Pigeon (v9.2.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
#if os(iOS)
  import Flutter
#elseif os(macOS)
  import FlutterMacOS
#else
  #error("Unsupported platform.")
#endif
private func wrapResult(_ result: Any?) -> [Any?] {
  return [result]
}
private func wrapError(_ error: Any) -> [Any?] {
  if let flutterError = error as? FlutterError {
    return [
      flutterError.code,
      flutterError.message,
      flutterError.details,
    ]
  }
  return [
    "\(error)",
    "\(type(of: error))",
    "Stacktrace: \(Thread.callStackSymbols)",
  ]
}
private func nilOrValue<T>(_ value: Any?) -> T? {
  if value is NSNull { return nil }
  return (value as Any) as! T?
}
/// A Pigeon representation of the macOS portion of an `XTypeGroup`.
///
/// Generated class from Pigeon that represents data sent in messages.
struct AllowedTypes {
  var extensions: [String?]
  var mimeTypes: [String?]
  var utis: [String?]
  static func fromList(_ list: [Any]) -> AllowedTypes? {
    let extensions = list[0] as! [String?]
    let mimeTypes = list[1] as! [String?]
    let utis = list[2] as! [String?]
    return AllowedTypes(
      extensions: extensions,
      mimeTypes: mimeTypes,
      utis: utis
    )
  }
  func toList() -> [Any?] {
    return [
      extensions,
      mimeTypes,
      utis,
    ]
  }
}
/// Options for save panels.
///
/// These correspond to NSSavePanel properties (which are, by extension
/// NSOpenPanel properties as well).
///
/// Generated class from Pigeon that represents data sent in messages.
struct SavePanelOptions {
  var allowedFileTypes: AllowedTypes? = nil
  var directoryPath: String? = nil
  var nameFieldStringValue: String? = nil
  var prompt: String? = nil
  static func fromList(_ list: [Any]) -> SavePanelOptions? {
    var allowedFileTypes: AllowedTypes? = nil
    if let allowedFileTypesList = list[0] as! [Any]? {
      allowedFileTypes = AllowedTypes.fromList(allowedFileTypesList)
    }
    let directoryPath: String? = nilOrValue(list[1])
    let nameFieldStringValue: String? = nilOrValue(list[2])
    let prompt: String? = nilOrValue(list[3])
    return SavePanelOptions(
      allowedFileTypes: allowedFileTypes,
      directoryPath: directoryPath,
      nameFieldStringValue: nameFieldStringValue,
      prompt: prompt
    )
  }
  func toList() -> [Any?] {
    return [
      allowedFileTypes?.toList(),
      directoryPath,
      nameFieldStringValue,
      prompt,
    ]
  }
}
/// Options for open panels.
///
/// These correspond to NSOpenPanel properties.
///
/// Generated class from Pigeon that represents data sent in messages.
struct OpenPanelOptions {
  var allowsMultipleSelection: Bool
  var canChooseDirectories: Bool
  var canChooseFiles: Bool
  var baseOptions: SavePanelOptions
  static func fromList(_ list: [Any]) -> OpenPanelOptions? {
    let allowsMultipleSelection = list[0] as! Bool
    let canChooseDirectories = list[1] as! Bool
    let canChooseFiles = list[2] as! Bool
    let baseOptions = SavePanelOptions.fromList(list[3] as! [Any])!
    return OpenPanelOptions(
      allowsMultipleSelection: allowsMultipleSelection,
      canChooseDirectories: canChooseDirectories,
      canChooseFiles: canChooseFiles,
      baseOptions: baseOptions
    )
  }
  func toList() -> [Any?] {
    return [
      allowsMultipleSelection,
      canChooseDirectories,
      canChooseFiles,
      baseOptions.toList(),
    ]
  }
}
private class FileSelectorApiCodecReader: FlutterStandardReader {
  override func readValue(ofType type: UInt8) -> Any? {
    switch type {
    case 128:
      return AllowedTypes.fromList(self.readValue() as! [Any])
    case 129:
      return OpenPanelOptions.fromList(self.readValue() as! [Any])
    case 130:
      return SavePanelOptions.fromList(self.readValue() as! [Any])
    default:
      return super.readValue(ofType: type)
    }
  }
}
private class FileSelectorApiCodecWriter: FlutterStandardWriter {
  override func writeValue(_ value: Any) {
    if let value = value as? AllowedTypes {
      super.writeByte(128)
      super.writeValue(value.toList())
    } else if let value = value as? OpenPanelOptions {
      super.writeByte(129)
      super.writeValue(value.toList())
    } else if let value = value as? SavePanelOptions {
      super.writeByte(130)
      super.writeValue(value.toList())
    } else {
      super.writeValue(value)
    }
  }
}
private class FileSelectorApiCodecReaderWriter: FlutterStandardReaderWriter {
  override func reader(with data: Data) -> FlutterStandardReader {
    return FileSelectorApiCodecReader(data: data)
  }
  override func writer(with data: NSMutableData) -> FlutterStandardWriter {
    return FileSelectorApiCodecWriter(data: data)
  }
}
class FileSelectorApiCodec: FlutterStandardMessageCodec {
  static let shared = FileSelectorApiCodec(readerWriter: FileSelectorApiCodecReaderWriter())
}
/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
protocol FileSelectorApi {
  /// Shows an open panel with the given [options], returning the list of
  /// selected paths.
  ///
  /// An empty list corresponds to a cancelled selection.
  func displayOpenPanel(
}
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
class FileSelectorApiSetup {
  /// The codec used by FileSelectorApi.
  static var codec: FlutterStandardMessageCodec { FileSelectorApiCodec.shared }
  /// Sets up an instance of `FileSelectorApi` to handle messages through the `binaryMessenger`.
  static func setUp(binaryMessenger: FlutterBinaryMessenger, api: FileSelectorApi?) {
    /// Shows an open panel with the given [options], returning the list of
    /// selected paths.
    ///
    /// An empty list corresponds to a cancelled selection.
    let displayOpenPanelChannel = FlutterBasicMessageChannel(
      name: "dev.flutter.pigeon.FileSelectorApi.displayOpenPanel", binaryMessenger: binaryMessenger,
      codec: codec)
    if let api = api {
      displayOpenPanelChannel.setMessageHandler { message, reply in
        let args = message as! [Any]
        let optionsArg = args[0] as! OpenPanelOptions
        api.displayOpenPanel(options: optionsArg) { result in
          switch result {
          case .success(let res):
            reply(wrapResult(res))
          case .failure(let error):
            reply(wrapError(error))
          }
        }
      }
    } else {
      displayOpenPanelChannel.setMessageHandler(nil)
    }
    /// Shows a save panel with the given [options], returning the selected path.
    ///
    /// A null return corresponds to a cancelled save.
    let displaySavePanelChannel = FlutterBasicMessageChannel(
      name: "dev.flutter.pigeon.FileSelectorApi.displaySavePanel", binaryMessenger: binaryMessenger,
      codec: codec)
    if let api = api {
      displaySavePanelChannel.setMessageHandler { message, reply in
        let args = message as! [Any]
        let optionsArg = args[0] as! SavePanelOptions
        api.displaySavePanel(options: optionsArg) { result in
          switch result {
          case .success(let res):
            reply(wrapResult(res))
          case .failure(let error):
            reply(wrapError(error))
          }
        }
      }
    } else {
      displaySavePanelChannel.setMessageHandler(nil)
    }
  }
}


RunnerTests

class TestPanelController: NSObject, PanelController {
  // The last panels that the relevant display methods were called on.
  public var savePanel: NSSavePanel?
  public var openPanel: NSOpenPanel?
  // Mock return values for the display methods.
  public var saveURL: URL?
  public var openURLs: [URL]?
  func display(
  ) {
    openPanel = panel
    handler(openURLs)
  }
}
class TestViewProvider: NSObject, ViewProvider {
  var view: NSView? {
    window?.contentView
  }
  var window: NSWindow? = NSWindow()
}
class exampleTests: XCTestCase {
  func testOpenSimple() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let returnPath = "/foo/bar"
    panelController.openURLs = [URL(fileURLWithPath: returnPath)]
    let called = XCTestExpectation()
    let options = OpenPanelOptions(
      allowsMultipleSelection: false,
      canChooseDirectories: false,
      canChooseFiles: true,
      baseOptions: SavePanelOptions())
    plugin.displayOpenPanel(options: options) { result in
      switch result {
      case .success(let paths):
        XCTAssertEqual(paths[0], returnPath)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.openPanel)
    if let panel = panelController.openPanel {
      XCTAssertTrue(panel.canChooseFiles)
      // For consistency across platforms, directory selection is disabled.
      XCTAssertFalse(panel.canChooseDirectories)
    }
  }
  func testOpenWithArguments() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let returnPath = "/foo/bar"
    panelController.openURLs = [URL(fileURLWithPath: returnPath)]
    let called = XCTestExpectation()
    let options = OpenPanelOptions(
      allowsMultipleSelection: false,
      canChooseDirectories: false,
      canChooseFiles: true,
      baseOptions: SavePanelOptions(
        directoryPath: "/some/dir",
        nameFieldStringValue: "a name",
        prompt: "Open it!"))
    plugin.displayOpenPanel(options: options) { result in
      switch result {
      case .success(let paths):
        XCTAssertEqual(paths[0], returnPath)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.openPanel)
    if let panel = panelController.openPanel {
      XCTAssertEqual(panel.directoryURL?.path, "/some/dir")
      XCTAssertEqual(panel.nameFieldStringValue, "a name")
      XCTAssertEqual(panel.prompt, "Open it!")
    }
  }
  func testOpenMultiple() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let returnPaths = ["/foo/bar", "/foo/baz"]
    panelController.openURLs = returnPaths.map({ path in URL(fileURLWithPath: path) })
    let called = XCTestExpectation()
    let options = OpenPanelOptions(
      allowsMultipleSelection: true,
      canChooseDirectories: false,
      canChooseFiles: true,
      baseOptions: SavePanelOptions())
    plugin.displayOpenPanel(options: options) { result in
      switch result {
      case .success(let paths):
        XCTAssertEqual(paths.count, returnPaths.count)
        XCTAssertEqual(paths[0], returnPaths[0])
        XCTAssertEqual(paths[1], returnPaths[1])
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.openPanel)
  }
  func testOpenWithFilter() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let returnPath = "/foo/bar"
    panelController.openURLs = [URL(fileURLWithPath: returnPath)]
    let called = XCTestExpectation()
    let options = OpenPanelOptions(
      allowsMultipleSelection: true,
      canChooseDirectories: false,
      canChooseFiles: true,
      baseOptions: SavePanelOptions(
        allowedFileTypes: AllowedTypes(
          extensions: ["txt", "json"],
          mimeTypes: ["text/html"],
          utis: ["public.text", "public.image"])))
    plugin.displayOpenPanel(options: options) { result in
      switch result {
      case .success(let paths):
        XCTAssertEqual(paths[0], returnPath)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.openPanel)
    if let panel = panelController.openPanel {
      if #available(macOS 11.0, *) {
        XCTAssertTrue(panel.allowedContentTypes.contains(UTType.plainText))
        XCTAssertTrue(panel.allowedContentTypes.contains(UTType.json))
        XCTAssertTrue(panel.allowedContentTypes.contains(UTType.html))
        XCTAssertTrue(panel.allowedContentTypes.contains(UTType.image))
      } else {
        // MIME type is not supported for the legacy codepath, but the rest should be set.
        XCTAssertEqual(panel.allowedFileTypes, ["txt", "json", "public.text", "public.image"])
      }
    }
  }
  func testOpenWithFilterLegacy() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    plugin.forceLegacyTypes = true
    let returnPath = "/foo/bar"
    panelController.openURLs = [URL(fileURLWithPath: returnPath)]
    let called = XCTestExpectation()
    let options = OpenPanelOptions(
      allowsMultipleSelection: true,
      canChooseDirectories: false,
      canChooseFiles: true,
      baseOptions: SavePanelOptions(
        allowedFileTypes: AllowedTypes(
          extensions: ["txt", "json"],
          mimeTypes: ["text/html"],
          utis: ["public.text", "public.image"])))
    plugin.displayOpenPanel(options: options) { result in
      switch result {
      case .success(let paths):
        XCTAssertEqual(paths[0], returnPath)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.openPanel)
    if let panel = panelController.openPanel {
      // On the legacy path, the allowedFileTypes should be set directly.
      XCTAssertEqual(panel.allowedFileTypes, ["txt", "json", "public.text", "public.image"])
      // They should also be translated to corresponding allowed content types.
      if #available(macOS 11.0, *) {
        XCTAssertTrue(panel.allowedContentTypes.contains(UTType.plainText))
        XCTAssertTrue(panel.allowedContentTypes.contains(UTType.json))
        XCTAssertTrue(panel.allowedContentTypes.contains(UTType.image))
        // MIME type is not supported for the legacy codepath.
        XCTAssertFalse(panel.allowedContentTypes.contains(UTType.html))
      }
    }
  }
  func testOpenCancel() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let called = XCTestExpectation()
    let options = OpenPanelOptions(
      allowsMultipleSelection: false,
      canChooseDirectories: false,
      canChooseFiles: true,
      baseOptions: SavePanelOptions())
    plugin.displayOpenPanel(options: options) { result in
      switch result {
      case .success(let paths):
        XCTAssertEqual(paths.count, 0)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.openPanel)
  }
  func testSaveSimple() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let returnPath = "/foo/bar"
    panelController.saveURL = URL(fileURLWithPath: returnPath)
    let called = XCTestExpectation()
    let options = SavePanelOptions()
    plugin.displaySavePanel(options: options) { result in
      switch result {
      case .success(let path):
        XCTAssertEqual(path, returnPath)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.savePanel)
  }
  func testSaveWithArguments() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let returnPath = "/foo/bar"
    panelController.saveURL = URL(fileURLWithPath: returnPath)
    let called = XCTestExpectation()
    let options = SavePanelOptions(
      directoryPath: "/some/dir",
      prompt: "Save it!")
    plugin.displaySavePanel(options: options) { result in
      switch result {
      case .success(let path):
        XCTAssertEqual(path, returnPath)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.savePanel)
    if let panel = panelController.savePanel {
      XCTAssertEqual(panel.directoryURL?.path, "/some/dir")
      XCTAssertEqual(panel.prompt, "Save it!")
    }
  }
  func testSaveCancel() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let called = XCTestExpectation()
    let options = SavePanelOptions()
    plugin.displaySavePanel(options: options) { result in
      switch result {
      case .success(let path):
        XCTAssertNil(path)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.savePanel)
  }
  func testGetDirectorySimple() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let returnPath = "/foo/bar"
    panelController.openURLs = [URL(fileURLWithPath: returnPath)]
    let called = XCTestExpectation()
    let options = OpenPanelOptions(
      allowsMultipleSelection: false,
      canChooseDirectories: true,
      canChooseFiles: false,
      baseOptions: SavePanelOptions())
    plugin.displayOpenPanel(options: options) { result in
      switch result {
      case .success(let paths):
        XCTAssertEqual(paths[0], returnPath)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.openPanel)
    if let panel = panelController.openPanel {
      XCTAssertTrue(panel.canChooseDirectories)
      // For consistency across platforms, file selection is disabled.
      XCTAssertFalse(panel.canChooseFiles)
      // The Dart API only allows a single directory to be returned, so users shouldn't be allowed
      // to select multiple.
      XCTAssertFalse(panel.allowsMultipleSelection)
    }
  }
  func testGetDirectoryCancel() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let called = XCTestExpectation()
    let options = OpenPanelOptions(
      allowsMultipleSelection: false,
      canChooseDirectories: true,
      canChooseFiles: false,
      baseOptions: SavePanelOptions())
    plugin.displayOpenPanel(options: options) { result in
      switch result {
      case .success(let paths):
        XCTAssertEqual(paths.count, 0)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.openPanel)
  }
  func testGetDirectoriesMultiple() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let returnPaths = ["/foo/bar", "/foo/test"];
    panelController.openURLs = returnPaths.map({ path in URL(fileURLWithPath: path) })
    let called = XCTestExpectation()
    let options = OpenPanelOptions(
      allowsMultipleSelection: true,
      canChooseDirectories: true,
      canChooseFiles: false,
      baseOptions: SavePanelOptions())
    plugin.displayOpenPanel(options: options) { result in
      switch result {
      case .success(let paths):
        XCTAssertEqual(paths, returnPaths)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.openPanel)
    if let panel = panelController.openPanel {
      XCTAssertTrue(panel.canChooseDirectories)
      // For consistency across platforms, file selection is disabled.
      XCTAssertFalse(panel.canChooseFiles)
      XCTAssertTrue(panel.allowsMultipleSelection)
    }
  }
  func testGetDirectoryMultipleCancel() throws {
    let panelController = TestPanelController()
    let plugin = FileSelectorPlugin(
      viewProvider: TestViewProvider(),
      panelController: panelController)
    let called = XCTestExpectation()
    let options = OpenPanelOptions(
      allowsMultipleSelection: true,
      canChooseDirectories: true,
      canChooseFiles: false,
      baseOptions: SavePanelOptions())
    plugin.displayOpenPanel(options: options) { result in
      switch result {
      case .success(let paths):
        XCTAssertEqual(paths.count, 0)
      case .failure(let error):
        XCTFail("\(error)")
      }
      called.fulfill()
    }
    wait(for: [called], timeout: 0.5)
    XCTAssertNotNil(panelController.openPanel)
  }
}


AppDelegate

class AppDelegate: FlutterAppDelegate {
  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
    return true
  }
}


MainFlutterWindow

import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController.init()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.setFrame(windowFrame, display: true)
    RegisterGeneratedPlugins(registry: flutterViewController)
    super.awakeFromNib()
  }
}


AppDelegate

  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}


SharedPreferencesPlugin

import Foundation
#if os(iOS)
import Flutter
#elseif os(macOS)
import FlutterMacOS
#endif
public class SharedPreferencesPlugin: NSObject, FlutterPlugin, UserDefaultsApi {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let instance = SharedPreferencesPlugin()
    // Workaround for https://github.com/flutter/flutter/issues/118103.
#if os(iOS)
    let messenger = registrar.messenger()
#else
    let messenger = registrar.messenger
#endif
    UserDefaultsApiSetup.setUp(binaryMessenger: messenger, api: instance)
  }
  func getAllWithPrefix(prefix: String) -> [String? : Any?] {
    return getAllPrefs(prefix: prefix)
  }
  func setBool(key: String, value: Bool) {
    UserDefaults.standard.set(value, forKey: key)
  }
  func setDouble(key: String, value: Double) {
    UserDefaults.standard.set(value, forKey: key)
  }
  func setValue(key: String, value: Any) {
    UserDefaults.standard.set(value, forKey: key)
  }
  func remove(key: String) {
    UserDefaults.standard.removeObject(forKey: key)
  }
  func clearWithPrefix(prefix: String) {
    let defaults = UserDefaults.standard
    for (key, _) in getAllPrefs(prefix: prefix) {
      defaults.removeObject(forKey: key)
    }
  }
  /// Returns all preferences stored with specified prefix.
  func getAllPrefs(prefix: String) -> [String: Any] {
    var filteredPrefs: [String: Any] = [:]
    if let appDomain = Bundle.main.bundleIdentifier,
      let prefs = UserDefaults.standard.persistentDomain(forName: appDomain)
    {
      for (key, value) in prefs where key.hasPrefix(prefix) {
        filteredPrefs[key] = value
      }
    }
    return filteredPrefs
  }
}


messages.g

// Autogenerated from Pigeon (v9.2.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
#if os(iOS)
import Flutter
#elseif os(macOS)
import FlutterMacOS
#else
#error("Unsupported platform.")
#endif
private func wrapResult(_ result: Any?) -> [Any?] {
  return [result]
}
private func wrapError(_ error: Any) -> [Any?] {
  if let flutterError = error as? FlutterError {
    return [
      flutterError.code,
      flutterError.message,
      flutterError.details
    ]
  }
  return [
    "\(error)",
    "\(type(of: error))",
    "Stacktrace: \(Thread.callStackSymbols)"
  ]
}
private func nilOrValue<T>(_ value: Any?) -> T? {
  if value is NSNull { return nil }
  return (value as Any) as! T?
}
/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
protocol UserDefaultsApi {
  func remove(key: String) throws
  func setBool(key: String, value: Bool) throws
  func setDouble(key: String, value: Double) throws
  func setValue(key: String, value: Any) throws
  func getAllWithPrefix(prefix: String) throws -> [String?: Any?]
  func clearWithPrefix(prefix: String) throws
}
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
class UserDefaultsApiSetup {
  /// The codec used by UserDefaultsApi.
  /// Sets up an instance of `UserDefaultsApi` to handle messages through the `binaryMessenger`.
  static func setUp(binaryMessenger: FlutterBinaryMessenger, api: UserDefaultsApi?) {
    let removeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.remove", binaryMessenger: binaryMessenger)
    if let api = api {
      removeChannel.setMessageHandler { message, reply in
        let args = message as! [Any]
        let keyArg = args[0] as! String
        do {
          try api.remove(key: keyArg)
          reply(wrapResult(nil))
        } catch {
          reply(wrapError(error))
        }
      }
    } else {
      removeChannel.setMessageHandler(nil)
    }
    let setBoolChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.setBool", binaryMessenger: binaryMessenger)
    if let api = api {
      setBoolChannel.setMessageHandler { message, reply in
        let args = message as! [Any]
        let keyArg = args[0] as! String
        let valueArg = args[1] as! Bool
        do {
          try api.setBool(key: keyArg, value: valueArg)
          reply(wrapResult(nil))
        } catch {
          reply(wrapError(error))
        }
      }
    } else {
      setBoolChannel.setMessageHandler(nil)
    }
    let setDoubleChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.setDouble", binaryMessenger: binaryMessenger)
    if let api = api {
      setDoubleChannel.setMessageHandler { message, reply in
        let args = message as! [Any]
        let keyArg = args[0] as! String
        let valueArg = args[1] as! Double
        do {
          try api.setDouble(key: keyArg, value: valueArg)
          reply(wrapResult(nil))
        } catch {
          reply(wrapError(error))
        }
      }
    } else {
      setDoubleChannel.setMessageHandler(nil)
    }
    let setValueChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.setValue", binaryMessenger: binaryMessenger)
    if let api = api {
      setValueChannel.setMessageHandler { message, reply in
        let args = message as! [Any]
        let keyArg = args[0] as! String
        let valueArg = args[1]
        do {
          try api.setValue(key: keyArg, value: valueArg)
          reply(wrapResult(nil))
        } catch {
          reply(wrapError(error))
        }
      }
    } else {
      setValueChannel.setMessageHandler(nil)
    }
    let getAllWithPrefixChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix", binaryMessenger: binaryMessenger)
    if let api = api {
      getAllWithPrefixChannel.setMessageHandler { message, reply in
        let args = message as! [Any]
        let prefixArg = args[0] as! String
        do {
          let result = try api.getAllWithPrefix(prefix: prefixArg)
          reply(wrapResult(result))
        } catch {
          reply(wrapError(error))
        }
      }
    } else {
      getAllWithPrefixChannel.setMessageHandler(nil)
    }
    let clearWithPrefixChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix", binaryMessenger: binaryMessenger)
    if let api = api {
      clearWithPrefixChannel.setMessageHandler { message, reply in
        let args = message as! [Any]
        let prefixArg = args[0] as! String
        do {
          try api.clearWithPrefix(prefix: prefixArg)
          reply(wrapResult(nil))
        } catch {
          reply(wrapError(error))
        }
      }
    } else {
      clearWithPrefixChannel.setMessageHandler(nil)
    }
  }
}


RunnerTests

class RunnerTests: XCTestCase {
  let prefixes: [String] = ["aPrefix", ""]
  func testSetAndGet() throws {
    for aPrefix in prefixes {
      let plugin = SharedPreferencesPlugin()
      plugin.setBool(key: "\(aPrefix)aBool", value: true)
      plugin.setDouble(key: "\(aPrefix)aDouble", value: 3.14)
      plugin.setValue(key: "\(aPrefix)anInt", value: 42)
      plugin.setValue(key: "\(aPrefix)aString", value: "hello world")
      plugin.setValue(key: "\(aPrefix)aStringList", value: ["hello", "world"])
      let storedValues = plugin.getAllWithPrefix(prefix: aPrefix)
      XCTAssertEqual(storedValues["\(aPrefix)aBool"] as? Bool, true)
      XCTAssertEqual(storedValues["\(aPrefix)aDouble"] as! Double, 3.14, accuracy: 0.0001)
      XCTAssertEqual(storedValues["\(aPrefix)anInt"] as? Int, 42)
      XCTAssertEqual(storedValues["\(aPrefix)aString"] as? String, "hello world")
      XCTAssertEqual(storedValues["\(aPrefix)aStringList"] as? Array<String>, ["hello", "world"])
    }
  }
  func testRemove() throws {
    for aPrefix in prefixes {
      let plugin = SharedPreferencesPlugin()
      let testKey = "\(aPrefix)foo"
      plugin.setValue(key: testKey, value: 42)
      // Make sure there is something to remove, so the test can't pass due to a set failure.
      let preRemovalValues = plugin.getAllWithPrefix(prefix: aPrefix)
      XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
      // Then verify that removing it works.
      plugin.remove(key: testKey)
      let finalValues = plugin.getAllWithPrefix(prefix: aPrefix)
      XCTAssertNil(finalValues[testKey] as Any?)
    }
  }
  func testClear() throws {
    for aPrefix in prefixes {
      let plugin = SharedPreferencesPlugin()
      let testKey = "\(aPrefix)foo"
      plugin.setValue(key: testKey, value: 42)
      // Make sure there is something to clear, so the test can't pass due to a set failure.
      let preRemovalValues = plugin.getAllWithPrefix(prefix: aPrefix)
      XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
      // Then verify that clearing works.
      plugin.clearWithPrefix(prefix: aPrefix)
      let finalValues = plugin.getAllWithPrefix(prefix: aPrefix)
      XCTAssertNil(finalValues[testKey] as Any?)
    }
  }

}


UrlLauncherPlugin

import FlutterMacOS
import Foundation
/// A handler that can launch other apps, check if any app is able to open the URL.
public protocol SystemURLHandler {
  /// Opens the location at the specified URL.
  ///
  /// - Parameters:
  ///   - url: A URL specifying the location to open.
  /// - Returns: true if the location was successfully opened; otherwise, false.
  func open(_ url: URL) -> Bool
  /// Returns the URL to the default app that would be opened.
  ///
  /// - Parameters:
  ///   - toOpen: The URL of the file to open.
  /// - Returns: The URL of the default app that would open the specified url.
  ///   Returns nil if no app is able to open the URL, or if the file URL does not exist.
  func urlForApplication(toOpen: URL) -> URL?
}
extension NSWorkspace: SystemURLHandler {}
public class UrlLauncherPlugin: NSObject, FlutterPlugin, UrlLauncherApi {
  private var workspace: SystemURLHandler
  public init(_ workspace: SystemURLHandler = NSWorkspace.shared) {
    self.workspace = workspace
  }
  public static func register(with registrar: FlutterPluginRegistrar) {
    let instance = UrlLauncherPlugin()
    UrlLauncherApiSetup.setUp(binaryMessenger: registrar.messenger, api: instance)
  }
  func canLaunch(url: String) throws -> UrlLauncherBoolResult {
    guard let nsurl = URL.init(string: url) else {
      return UrlLauncherBoolResult(value: false, error: .invalidUrl)
    }
    let canOpen = workspace.urlForApplication(toOpen: nsurl) != nil
    return UrlLauncherBoolResult(value: canOpen, error: nil)
  }
  func launch(url: String) throws -> UrlLauncherBoolResult {
    guard let nsurl = URL.init(string: url) else {
      return UrlLauncherBoolResult(value: false, error: .invalidUrl)
    }
    let success = workspace.open(nsurl)
    return UrlLauncherBoolResult(value: success, error: nil)
  }
}


messages.g

// Autogenerated from Pigeon (v9.2.4), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
#if os(iOS)
  import Flutter
#elseif os(macOS)
  import FlutterMacOS
#else
  #error("Unsupported platform.")
#endif
private func wrapResult(_ result: Any?) -> [Any?] {
  return [result]
}
private func wrapError(_ error: Any) -> [Any?] {
  if let flutterError = error as? FlutterError {
    return [
      flutterError.code,
      flutterError.message,
      flutterError.details,
    ]
  }
  return [
    "\(error)",
    "\(type(of: error))",
    "Stacktrace: \(Thread.callStackSymbols)",
  ]
}
private func nilOrValue<T>(_ value: Any?) -> T? {
  if value is NSNull { return nil }
  return (value as Any) as! T?
}
/// Possible error conditions for [UrlLauncherApi] calls.
enum UrlLauncherError: Int {
  /// The URL could not be parsed as an NSURL.
  case invalidUrl = 0
}
/// Possible results for a [UrlLauncherApi] call with a boolean outcome.
///
/// Generated class from Pigeon that represents data sent in messages.
struct UrlLauncherBoolResult {
  var value: Bool
  var error: UrlLauncherError? = nil
  static func fromList(_ list: [Any]) -> UrlLauncherBoolResult? {
    let value = list[0] as! Bool
    var error: UrlLauncherError? = nil
    let errorEnumVal: Int? = nilOrValue(list[1])
    if let errorRawValue = errorEnumVal {
      error = UrlLauncherError(rawValue: errorRawValue)!
    }
    return UrlLauncherBoolResult(
      value: value,
      error: error
    )
  }
  func toList() -> [Any?] {
    return [
      value,
      error?.rawValue,
    ]
  }
}
private class UrlLauncherApiCodecReader: FlutterStandardReader {
  override func readValue(ofType type: UInt8) -> Any? {
    switch type {
    case 128:
      return UrlLauncherBoolResult.fromList(self.readValue() as! [Any])
    default:
      return super.readValue(ofType: type)
    }
  }
}
private class UrlLauncherApiCodecWriter: FlutterStandardWriter {
  override func writeValue(_ value: Any) {
    if let value = value as? UrlLauncherBoolResult {
      super.writeByte(128)
      super.writeValue(value.toList())
    } else {
      super.writeValue(value)
    }
  }
}
private class UrlLauncherApiCodecReaderWriter: FlutterStandardReaderWriter {
  override func reader(with data: Data) -> FlutterStandardReader {
    return UrlLauncherApiCodecReader(data: data)
  }
  override func writer(with data: NSMutableData) -> FlutterStandardWriter {
    return UrlLauncherApiCodecWriter(data: data)
  }
}
class UrlLauncherApiCodec: FlutterStandardMessageCodec {
  static let shared = UrlLauncherApiCodec(readerWriter: UrlLauncherApiCodecReaderWriter())
}
/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
protocol UrlLauncherApi {
  /// Returns a true result if the URL can definitely be launched.
  func canLaunch(url: String) throws -> UrlLauncherBoolResult
  /// Opens the URL externally, returning a true result if successful.
  func launch(url: String) throws -> UrlLauncherBoolResult
}
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
class UrlLauncherApiSetup {
  /// The codec used by UrlLauncherApi.
  static var codec: FlutterStandardMessageCodec { UrlLauncherApiCodec.shared }
  /// Sets up an instance of `UrlLauncherApi` to handle messages through the `binaryMessenger`.
  static func setUp(binaryMessenger: FlutterBinaryMessenger, api: UrlLauncherApi?) {
    /// Returns a true result if the URL can definitely be launched.
    let canLaunchUrlChannel = FlutterBasicMessageChannel(
      name: "dev.flutter.pigeon.UrlLauncherApi.canLaunchUrl", binaryMessenger: binaryMessenger,
      codec: codec)
    if let api = api {
      canLaunchUrlChannel.setMessageHandler { message, reply in
        let args = message as! [Any]
        let urlArg = args[0] as! String
        do {
          let result = try api.canLaunch(url: urlArg)
          reply(wrapResult(result))
        } catch {
          reply(wrapError(error))
        }
      }
    } else {
      canLaunchUrlChannel.setMessageHandler(nil)
    }
    /// Opens the URL externally, returning a true result if successful.
    let launchUrlChannel = FlutterBasicMessageChannel(
      name: "dev.flutter.pigeon.UrlLauncherApi.launchUrl", binaryMessenger: binaryMessenger,
      codec: codec)
    if let api = api {
      launchUrlChannel.setMessageHandler { message, reply in
        let args = message as! [Any]
        let urlArg = args[0] as! String
        do {
          let result = try api.launch(url: urlArg)
          reply(wrapResult(result))
        } catch {
          reply(wrapError(error))
        }
      }
    } else {
      launchUrlChannel.setMessageHandler(nil)
    }
  }
}


RunnerTests

/// A stub to simulate the system Url handler.
class StubWorkspace: SystemURLHandler {
  var isSuccessful = true
  func open(_ url: URL) -> Bool {
    return isSuccessful
  }
  func urlForApplication(toOpen: URL) -> URL? {
    return toOpen
  }
}
class RunnerTests: XCTestCase {
  func testCanLaunchSuccessReturnsTrue() throws {
    let plugin = UrlLauncherPlugin()
    let result = try plugin.canLaunch(url: "https://flutter.dev")
    XCTAssertNil(result.error)
    XCTAssertTrue(result.value)
  }
  func testCanLaunchNoAppIsAbleToOpenUrlReturnsFalse() throws {
    let plugin = UrlLauncherPlugin()
    let result = try plugin.canLaunch(url: "example://flutter.dev")
    XCTAssertNil(result.error)
    XCTAssertFalse(result.value)
  }
  func testCanLaunchInvalidUrlReturnsError() throws {
    let plugin = UrlLauncherPlugin()
    let result = try plugin.canLaunch(url: "invalid url")
    XCTAssertEqual(result.error, .invalidUrl)
  }
  func testLaunchSuccessReturnsTrue() throws {
    let workspace = StubWorkspace()
    let plugin = UrlLauncherPlugin(workspace)
    let result = try plugin.launch(url: "https://flutter.dev")
    XCTAssertNil(result.error)
    XCTAssertTrue(result.value)
  }
  func testLaunchNoAppIsAbleToOpenUrlReturnsFalse() throws {
    let workspace = StubWorkspace()
    workspace.isSuccessful = false
    let plugin = UrlLauncherPlugin(workspace)
    let result = try plugin.launch(url: "schemethatdoesnotexist://flutter.dev")
    XCTAssertNil(result.error)
    XCTAssertFalse(result.value)
  }
  func testLaunchInvalidUrlReturnsError() throws {
    let plugin = UrlLauncherPlugin()
    let result = try plugin.launch(url: "invalid url")
    XCTAssertEqual(result.error, .invalidUrl)
  }
}


MethodChannel

import Flutter
/// A channel for platform code to communicate with the Dart code.
protocol MethodChannel {
  /// Invokes a method in Dart code.
  /// - Parameter method the method name.
  /// - Parameter arguments the method arguments.
  func invokeMethod(_ method: String, arguments: Any?)
}
/// A default implementation of the `MethodChannel` protocol.
extension FlutterMethodChannel: MethodChannel {}


ShortcutItemProviding

import UIKit
/// Provides the capability to get and set the app's home screen shortcut items.
protocol ShortcutItemProviding: AnyObject {
  /// An array of shortcut items for home screen.
  var shortcutItems: [UIApplicationShortcutItem]? { get set }
}
/// A default implementation of the `ShortcutItemProviding` protocol.
extension UIApplication: ShortcutItemProviding {}


QuickActionsPlugin

import Flutter
public final class QuickActionsPlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(
      name: "plugins.flutter.io/quick_actions_ios",
      binaryMessenger: registrar.messenger())
    let instance = QuickActionsPlugin(channel: channel)
    registrar.addMethodCallDelegate(instance, channel: channel)
    registrar.addApplicationDelegate(instance)
  }
  private let channel: MethodChannel
  private let shortcutItemProvider: ShortcutItemProviding
  private let shortcutItemParser: ShortcutItemParser
  /// The type of the shortcut item selected when launching the app.
  private var launchingShortcutType: String? = nil
  init(
    channel: MethodChannel,
    shortcutItemProvider: ShortcutItemProviding = UIApplication.shared,
    shortcutItemParser: ShortcutItemParser = DefaultShortcutItemParser()
  ) {
    self.channel = channel
    self.shortcutItemProvider = shortcutItemProvider
    self.shortcutItemParser = shortcutItemParser
  }
    switch call.method {
    case "setShortcutItems":
      // `arguments` must be an array of dictionaries
      let items = call.arguments as! [[String: Any]]
      shortcutItemProvider.shortcutItems = shortcutItemParser.parseShortcutItems(items)
      result(nil)
    case "clearShortcutItems":
      shortcutItemProvider.shortcutItems = []
      result(nil)
    case "getLaunchAction":
      result(nil)
    case _:
      result(FlutterMethodNotImplemented)
    }
  }
  public func application(
    _ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem,
  ) -> Bool {
    handleShortcut(shortcutItem.type)
    return true
  }
  public func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [AnyHashable: Any] = [:]
  ) -> Bool {
    if let shortcutItem = launchOptions[UIApplication.LaunchOptionsKey.shortcutItem]
      as? UIApplicationShortcutItem
    {
      // Keep hold of the shortcut type and handle it in the
      // `applicationDidBecomeActive:` method once the Dart MethodChannel
      // is initialized.
      launchingShortcutType = shortcutItem.type
      // Return false to indicate we handled the quick action to ensure
      // the `application:performActionFor:` method is not called (as
      // per Apple's documentation:
      // https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622935-application).
      return false
    }
    return true
  }
  public func applicationDidBecomeActive(_ application: UIApplication) {
    if let shortcutType = launchingShortcutType {
      handleShortcut(shortcutType)
      launchingShortcutType = nil
    }
  }
  private func handleShortcut(_ shortcut: String) {
    channel.invokeMethod("launch", arguments: shortcut)
  }
}


ShortcutItemParser

import UIKit
/// A parser that parses an array of raw shortcut items.
protocol ShortcutItemParser {
  /// Parses an array of raw shortcut items into an array of UIApplicationShortcutItems
  ///
  /// - Parameter items an array of raw shortcut items to be parsed.
  /// - Returns an array of parsed shortcut items to be set.
  ///
  func parseShortcutItems(_ items: [[String: Any]]) -> [UIApplicationShortcutItem]
}
/// A default implementation of the `ShortcutItemParser` protocol.
final class DefaultShortcutItemParser: ShortcutItemParser {
  func parseShortcutItems(_ items: [[String: Any]]) -> [UIApplicationShortcutItem] {
    return items.compactMap { deserializeShortcutItem(with: $0) }
  }
  private func deserializeShortcutItem(with serialized: [String: Any]) -> UIApplicationShortcutItem?
  {
    guard
      let type = serialized["type"] as? String,
      let localizedTitle = serialized["localizedTitle"] as? String
    else {
      return nil
    }
    let icon = (serialized["icon"] as? String).map {
      UIApplicationShortcutIcon(templateImageName: $0)
    }
    // type and localizedTitle are required.
    return UIApplicationShortcutItem(
      type: type,
      localizedTitle: localizedTitle,
      localizedSubtitle: nil,
      icon: icon,
      userInfo: nil)
  }
}


DefaultShortcutItemParserTests

class DefaultShortcutItemParserTests: XCTestCase {
  func testParseShortcutItems() {
    let rawItem = [
      "type": "SearchTheThing",
      "localizedTitle": "Search the thing",
      "icon": "search_the_thing.png",
    ]
    let expectedItem = UIApplicationShortcutItem(
      type: "SearchTheThing",
      localizedTitle: "Search the thing",
      localizedSubtitle: nil,
      icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
      userInfo: nil)
    let parser = DefaultShortcutItemParser()
    XCTAssertEqual(parser.parseShortcutItems([rawItem]), [expectedItem])
  }
  func testParseShortcutItems_noIcon() {
    let rawItem: [String: Any] = [
      "type": "SearchTheThing",
      "localizedTitle": "Search the thing",
      "icon": NSNull(),
    ]
    let expectedItem = UIApplicationShortcutItem(
      type: "SearchTheThing",
      localizedTitle: "Search the thing",
      localizedSubtitle: nil,
      icon: nil,
      userInfo: nil)
    let parser = DefaultShortcutItemParser()
    XCTAssertEqual(parser.parseShortcutItems([rawItem]), [expectedItem])
  }
  func testParseShortcutItems_noType() {
    let rawItem = [
      "localizedTitle": "Search the thing",
      "icon": "search_the_thing.png",
    ]
    let parser = DefaultShortcutItemParser()
    XCTAssertEqual(parser.parseShortcutItems([rawItem]), [])
  }
  func testParseShortcutItems_noLocalizedTitle() {
    let rawItem = [
      "type": "SearchTheThing",
      "icon": "search_the_thing.png",
    ]
    let parser = DefaultShortcutItemParser()
    XCTAssertEqual(parser.parseShortcutItems([rawItem]), [])
  }
}


QuickActionsPluginTests

class QuickActionsPluginTests: XCTestCase {
  func testHandleMethodCall_setShortcutItems() {
    let rawItem = [
      "type": "SearchTheThing",
      "localizedTitle": "Search the thing",
      "icon": "search_the_thing.png",
    ]
    let item = UIApplicationShortcutItem(
      type: "SearchTheThing",
      localizedTitle: "Search the thing",
      localizedSubtitle: nil,
      icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
      userInfo: nil)
    let call = FlutterMethodCall(methodName: "setShortcutItems", arguments: [rawItem])
    let mockChannel = MockMethodChannel()
    let mockShortcutItemProvider = MockShortcutItemProvider()
    let mockShortcutItemParser = MockShortcutItemParser()
    let plugin = QuickActionsPlugin(
      channel: mockChannel,
      shortcutItemProvider: mockShortcutItemProvider,
      shortcutItemParser: mockShortcutItemParser)
    let parseShortcutItemsExpectation = expectation(
      description: "parseShortcutItems must be called.")
    mockShortcutItemParser.parseShortcutItemsStub = { items in
      XCTAssertEqual(items as? [[String: String]], [rawItem])
      parseShortcutItemsExpectation.fulfill()
      return [item]
    }
    let resultExpectation = expectation(description: "result block must be called.")
    plugin.handle(call) { result in
      XCTAssertNil(result, "result block must be called with nil.")
      resultExpectation.fulfill()
    }
    XCTAssertEqual(mockShortcutItemProvider.shortcutItems, [item], "Must set shortcut items.")
    waitForExpectations(timeout: 1)
  }
  func testHandleMethodCall_clearShortcutItems() {
    let item = UIApplicationShortcutItem(
      type: "SearchTheThing",
      localizedTitle: "Search the thing",
      localizedSubtitle: nil,
      icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
      userInfo: nil)
    let call = FlutterMethodCall(methodName: "clearShortcutItems", arguments: nil)
    let mockChannel = MockMethodChannel()
    let mockShortcutItemProvider = MockShortcutItemProvider()
    let mockShortcutItemParser = MockShortcutItemParser()
    mockShortcutItemProvider.shortcutItems = [item]
    let plugin = QuickActionsPlugin(
      channel: mockChannel,
      shortcutItemProvider: mockShortcutItemProvider,
      shortcutItemParser: mockShortcutItemParser)
    let resultExpectation = expectation(description: "result block must be called.")
    plugin.handle(call) { result in
      XCTAssertNil(result, "result block must be called with nil.")
      resultExpectation.fulfill()
    }
    XCTAssertEqual(mockShortcutItemProvider.shortcutItems, [], "Must clear shortcut items.")
    waitForExpectations(timeout: 1)
  }
  func testHandleMethodCall_getLaunchAction() {
    let call = FlutterMethodCall(methodName: "getLaunchAction", arguments: nil)
    let mockChannel = MockMethodChannel()
    let mockShortcutItemProvider = MockShortcutItemProvider()
    let mockShortcutItemParser = MockShortcutItemParser()
    let plugin = QuickActionsPlugin(
      channel: mockChannel,
      shortcutItemProvider: mockShortcutItemProvider,
      shortcutItemParser: mockShortcutItemParser)
    let resultExpectation = expectation(description: "result block must be called.")
    plugin.handle(call) { result in
      XCTAssertNil(result, "result block must be called with nil.")
      resultExpectation.fulfill()
    }
    waitForExpectations(timeout: 1)
  }
  func testHandleMethodCall_nonExistMethods() {
    let call = FlutterMethodCall(methodName: "nonExist", arguments: nil)
    let mockChannel = MockMethodChannel()
    let mockShortcutItemProvider = MockShortcutItemProvider()
    let mockShortcutItemParser = MockShortcutItemParser()
    let plugin = QuickActionsPlugin(
      channel: mockChannel,
      shortcutItemProvider: mockShortcutItemProvider,
      shortcutItemParser: mockShortcutItemParser)
    let resultExpectation = expectation(description: "result block must be called.")
    plugin.handle(call) { result in
      XCTAssertEqual(
        result as? NSObject, FlutterMethodNotImplemented,
        "result block must be called with FlutterMethodNotImplemented")
      resultExpectation.fulfill()
    }
    waitForExpectations(timeout: 1)
  }
  func testApplicationPerformActionForShortcutItem() {
    let mockChannel = MockMethodChannel()
    let mockShortcutItemProvider = MockShortcutItemProvider()
    let mockShortcutItemParser = MockShortcutItemParser()
    let plugin = QuickActionsPlugin(
      channel: mockChannel,
      shortcutItemProvider: mockShortcutItemProvider,
      shortcutItemParser: mockShortcutItemParser)
    let item = UIApplicationShortcutItem(
      type: "SearchTheThing",
      localizedTitle: "Search the thing",
      localizedSubtitle: nil,
      icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
      userInfo: nil)
    let invokeMethodExpectation = expectation(description: "invokeMethod must be called.")
    mockChannel.invokeMethodStub = { method, arguments in
      XCTAssertEqual(method, "launch")
      XCTAssertEqual(arguments as? String, item.type)
      invokeMethodExpectation.fulfill()
    }
    let actionResult = plugin.application(
      UIApplication.shared,
      performActionFor: item
    ) { success in /* no-op */ }
    XCTAssert(actionResult, "performActionForShortcutItem must return true.")
    waitForExpectations(timeout: 1)
  }
  func testApplicationDidFinishLaunchingWithOptions_launchWithShortcut() {
    let mockChannel = MockMethodChannel()
    let mockShortcutItemProvider = MockShortcutItemProvider()
    let mockShortcutItemParser = MockShortcutItemParser()
    let plugin = QuickActionsPlugin(
      channel: mockChannel,
      shortcutItemProvider: mockShortcutItemProvider,
      shortcutItemParser: mockShortcutItemParser)
    let item = UIApplicationShortcutItem(
      type: "SearchTheThing",
      localizedTitle: "Search the thing",
      localizedSubtitle: nil,
      icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
      userInfo: nil)
    let launchResult = plugin.application(
      UIApplication.shared,
      didFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey.shortcutItem: item])
    XCTAssertFalse(
      launchResult, "didFinishLaunchingWithOptions must return false if launched from shortcut.")
  }
  func testApplicationDidFinishLaunchingWithOptions_launchWithoutShortcut() {
    let mockChannel = MockMethodChannel()
    let mockShortcutItemProvider = MockShortcutItemProvider()
    let mockShortcutItemParser = MockShortcutItemParser()
    let plugin = QuickActionsPlugin(
      channel: mockChannel,
      shortcutItemProvider: mockShortcutItemProvider,
      shortcutItemParser: mockShortcutItemParser)
    let launchResult = plugin.application(UIApplication.shared, didFinishLaunchingWithOptions: [:])
    XCTAssert(
      launchResult, "didFinishLaunchingWithOptions must return true if not launched from shortcut.")
  }
  func testApplicationDidBecomeActive_launchWithoutShortcut() {
    let mockChannel = MockMethodChannel()
    let mockShortcutItemProvider = MockShortcutItemProvider()
    let mockShortcutItemParser = MockShortcutItemParser()
    let plugin = QuickActionsPlugin(
      channel: mockChannel,
      shortcutItemProvider: mockShortcutItemProvider,
      shortcutItemParser: mockShortcutItemParser)
    mockChannel.invokeMethodStub = { _, _ in
      XCTFail("invokeMethod should not be called if launch without shortcut.")
    }
    let launchResult = plugin.application(UIApplication.shared, didFinishLaunchingWithOptions: [:])
    XCTAssert(
      launchResult, "didFinishLaunchingWithOptions must return true if not launched from shortcut.")
    plugin.applicationDidBecomeActive(UIApplication.shared)
  }
  func testApplicationDidBecomeActive_launchWithShortcut() {
    let item = UIApplicationShortcutItem(
      type: "SearchTheThing",
      localizedTitle: "Search the thing",
      localizedSubtitle: nil,
      icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
      userInfo: nil)
    let mockChannel = MockMethodChannel()
    let mockShortcutItemProvider = MockShortcutItemProvider()
    let mockShortcutItemParser = MockShortcutItemParser()
    let plugin = QuickActionsPlugin(
      channel: mockChannel,
      shortcutItemProvider: mockShortcutItemProvider,
      shortcutItemParser: mockShortcutItemParser)
    let invokeMethodExpectation = expectation(description: "invokeMethod must be called.")
    mockChannel.invokeMethodStub = { method, arguments in
      XCTAssertEqual(method, "launch")
      XCTAssertEqual(arguments as? String, item.type)
      invokeMethodExpectation.fulfill()
    }
    let launchResult = plugin.application(
      UIApplication.shared,
      didFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey.shortcutItem: item])
    XCTAssertFalse(
      launchResult, "didFinishLaunchingWithOptions must return false if launched from shortcut.")
    plugin.applicationDidBecomeActive(UIApplication.shared)
    waitForExpectations(timeout: 1)
  }
  func testApplicationDidBecomeActive_launchWithShortcut_becomeActiveTwice() {
    let item = UIApplicationShortcutItem(
      type: "SearchTheThing",
      localizedTitle: "Search the thing",
      localizedSubtitle: nil,
      icon: UIApplicationShortcutIcon(templateImageName: "search_the_thing.png"),
      userInfo: nil)
    let mockChannel = MockMethodChannel()
    let mockShortcutItemProvider = MockShortcutItemProvider()
    let mockShortcutItemParser = MockShortcutItemParser()
    let plugin = QuickActionsPlugin(
      channel: mockChannel,
      shortcutItemProvider: mockShortcutItemProvider,
      shortcutItemParser: mockShortcutItemParser)
    let invokeMethodExpectation = expectation(description: "invokeMethod must be called.")
    var invokeMehtodCount = 0
    mockChannel.invokeMethodStub = { method, arguments in
      invokeMehtodCount += 1
      invokeMethodExpectation.fulfill()
    }
    let launchResult = plugin.application(
      UIApplication.shared,
      didFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey.shortcutItem: item])
    XCTAssertFalse(
      launchResult, "didFinishLaunchingWithOptions must return false if launched from shortcut.")
    plugin.applicationDidBecomeActive(UIApplication.shared)
    waitForExpectations(timeout: 1)
    XCTAssertEqual(invokeMehtodCount, 1, "shortcut should only be handled once per launch.")
  }
}


MockShortcutItemParser

final class MockShortcutItemParser: ShortcutItemParser {
  var parseShortcutItemsStub: ((_ items: [[String: Any]]) -> [UIApplicationShortcutItem])? = nil
  func parseShortcutItems(_ items: [[String: Any]]) -> [UIApplicationShortcutItem] {
    return parseShortcutItemsStub?(items) ?? []
  }
}


MockShortcutItemProvider

final class MockShortcutItemProvider: ShortcutItemProviding {
  var shortcutItems: [UIApplicationShortcutItem]? = nil
}


MockMethodChannel

final class MockMethodChannel: MethodChannel {
  var invokeMethodStub: ((_ methods: String, _ arguments: Any?) -> Void)? = nil
  func invokeMethod(_ method: String, arguments: Any?) {
    invokeMethodStub?(method, arguments)
  }
}


RunnerUITests

import XCTest
private let elementWaitingTime: TimeInterval = 30
// The duration in when pressing the app icon to open the
// quick action menu. This duration is undocumented by Apple.
// The duration will be adjusted with `pressDurationRetryAdjustment` if
// this duration does not result in the quick action menu opened.
private let quickActionPressDuration: TimeInterval = 1.5
// If the previous try to open quick action menu did not work,
// a new try with adjust the press time by this value.
// The adjusment could be + or - depends on the result of the previous try.
private let pressDurationRetryAdjustment: TimeInterval = 0.2
// Max number of tries to open the quick action menu if failed.
// This is to deflake a situation where the quick action menu is not present after
// the long press.
// See: https://github.com/flutter/flutter/issues/125509
private let quickActionMaxRetries: Int = 4;
class RunnerUITests: XCTestCase {
  private var exampleApp: XCUIApplication!
  override func setUp() {
    super.setUp()
    self.continueAfterFailure = false
    exampleApp = XCUIApplication()
  }
  override func tearDown() {
    super.tearDown()
    exampleApp.terminate()
    exampleApp = nil
  }
  func testQuickActionWithFreshStart() {
    let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
    let quickActionsAppIcon = springboard.icons["quick_actions_example"]
    findAndTapQuickActionButton(buttonName: "Action two", quickActionsAppIcon: quickActionsAppIcon, springboard: springboard);
    let actionTwoConfirmation = exampleApp.otherElements["action_two"]
    if !actionTwoConfirmation.waitForExistence(timeout: elementWaitingTime) {
      XCTFail(
        "Failed due to not able to find the actionTwoConfirmation in the app with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)"
      )
    }
    XCTAssert(actionTwoConfirmation.exists)
  }
  func testQuickActionWhenAppIsInBackground() {
    exampleApp.launch()
    let actionsReady = exampleApp.otherElements["actions ready"]
    if !actionsReady.waitForExistence(timeout: elementWaitingTime) {
      XCTFail(
        "Failed due to not able to find the actionsReady in the app with \(elementWaitingTime) seconds. App debug description: \(exampleApp.debugDescription)"
      )
    }
    XCUIDevice.shared.press(.home)
    let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
    let quickActionsAppIcon = springboard.icons["quick_actions_example"]
    if !quickActionsAppIcon.waitForExistence(timeout: elementWaitingTime) {
      XCTFail(
        "Failed due to not able to find the example app from springboard with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)"
      )
    }
    findAndTapQuickActionButton(buttonName: "Action one", quickActionsAppIcon: quickActionsAppIcon, springboard: springboard);
    let actionOneConfirmation = exampleApp.otherElements["action_one"]
    if !actionOneConfirmation.waitForExistence(timeout: elementWaitingTime) {
      XCTFail(
        "Failed due to not able to find the actionOneConfirmation in the app with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)"
      )
    }
    XCTAssert(actionOneConfirmation.exists)
  }
  private func findAndTapQuickActionButton(buttonName: String, quickActionsAppIcon: XCUIElement, springboard: XCUIElement) {
    var actionButton: XCUIElement?
    var pressDuration = quickActionPressDuration
    for _ in 1...quickActionMaxRetries {
      if !quickActionsAppIcon.waitForExistence(timeout: elementWaitingTime) {
        XCTFail(
          "Failed due to not able to find the example app from springboard with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)"
        )
      }
      quickActionsAppIcon.press(forDuration: pressDuration)
      actionButton = springboard.buttons[buttonName]
      if actionButton!.waitForExistence(timeout: elementWaitingTime) {
        // find the button, exit the retry loop.
        break
      }
      let deleteButton = springboard.buttons["DeleteButton"]
      if deleteButton.waitForExistence(timeout: elementWaitingTime) {
        // Found delete button instead, we pressed too long, reduce the press time.
        pressDuration -= pressDurationRetryAdjustment
      } else {
        // Neither action button nor delete button was found, we need a longer press.
        pressDuration += pressDurationRetryAdjustment
      }
      // Reset to previous state.
      XCUIDevice.shared.press(XCUIDevice.Button.home)
    }
    if (!actionButton!.exists) {
      XCTFail(
        "Failed due to not able to find the \(buttonName) button from springboard with \(elementWaitingTime) seconds. Springboard debug description: \(springboard.debugDescription)"
      )
    }
    actionButton!.tap();
  }
}


AppDelegate

  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    let controller = window?.rootViewController as! FlutterViewController
    let api = PigeonApiImplementation()
    ExampleHostApiSetup.setUp(binaryMessenger: controller.binaryMessenger, api: api)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}


Messages.g

// Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
#if os(iOS)
  import Flutter
#elseif os(macOS)
  import FlutterMacOS
#else
  #error("Unsupported platform.")
#endif
private func wrapResult(_ result: Any?) -> [Any?] {
  return [result]
}
private func wrapError(_ error: Any) -> [Any?] {
  if let flutterError = error as? FlutterError {
    return [
      flutterError.code,
      flutterError.message,
      flutterError.details,
    ]
  }
  return [
    "\(error)",
    "\(type(of: error))",
    "Stacktrace: \(Thread.callStackSymbols)",
  ]
}
private func nilOrValue<T>(_ value: Any?) -> T? {
  if value is NSNull { return nil }
  return (value as Any) as! T?
}
/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
protocol ExampleHostApi {
  func getHostLanguage() throws -> String
}
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
class ExampleHostApiSetup {
  /// The codec used by ExampleHostApi.
  /// Sets up an instance of `ExampleHostApi` to handle messages through the `binaryMessenger`.
  static func setUp(binaryMessenger: FlutterBinaryMessenger, api: ExampleHostApi?) {
    let getHostLanguageChannel = FlutterBasicMessageChannel(
      name: "dev.flutter.pigeon.ExampleHostApi.getHostLanguage", binaryMessenger: binaryMessenger)
    if let api = api {
      getHostLanguageChannel.setMessageHandler { _, reply in
        do {
          let result = try api.getHostLanguage()
          reply(wrapResult(result))
        } catch {
          reply(wrapError(error))
        }
      }
    } else {
      getHostLanguageChannel.setMessageHandler(nil)
    }
  }
}


AppDelegate

class AppDelegate: FlutterAppDelegate {
  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
    return true
  }
}


MainFlutterWindow

import Cocoa
import FlutterMacOS
private class PigeonApiImplementation: ExampleHostApi {
  func getHostLanguage() throws -> String {
    return "Swift"
  }
}
class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController()
    let windowFrame = self.frame
    self.contentViewController = flutterViewController
    self.setFrame(windowFrame, display: true)
    RegisterGeneratedPlugins(registry: flutterViewController)
    let hostApi = PigeonApiImplementation()
    ExampleHostApiSetup.setUp(
      binaryMessenger: flutterViewController.engine.binaryMessenger, api: hostApi)
    super.awakeFromNib()
  }
}


TestPlugin

import Flutter
import UIKit
extension FlutterError: Error {}
/**
 * This plugin handles the native side of the integration tests in
 * example/integration_test/.
 */
public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi {
  var flutterAPI: FlutterIntegrationCoreApi
  public static func register(with registrar: FlutterPluginRegistrar) {
    let plugin = TestPlugin(binaryMessenger: registrar.messenger())
    HostIntegrationCoreApiSetup.setUp(binaryMessenger: registrar.messenger(), api: plugin)
  }
  init(binaryMessenger: FlutterBinaryMessenger) {
    flutterAPI = FlutterIntegrationCoreApi(binaryMessenger: binaryMessenger)
  }
  // MARK: HostIntegrationCoreApi implementation
  func noop() {
  }
  func echo(_ everything: AllTypes) -> AllTypes {
    return everything
  }
  func echo(_ everything: AllNullableTypes?) -> AllNullableTypes? {
    return everything
  }
  func throwError() throws -> Any? {
    throw FlutterError(code: "code", message: "message", details: "details")
  }
  func throwErrorFromVoid() throws {
    throw FlutterError(code: "code", message: "message", details: "details")
  }
  func throwFlutterError() throws -> Any? {
    throw FlutterError(code: "code", message: "message", details: "details")
  }
  func echo(_ anInt: Int64) -> Int64 {
    return anInt
  }
  func echo(_ aDouble: Double) -> Double {
    return aDouble
  }
  func echo(_ aBool: Bool) -> Bool {
    return aBool
  }
  func echo(_ aString: String) -> String {
    return aString
  }
  func echo(_ aUint8List: FlutterStandardTypedData) -> FlutterStandardTypedData {
    return aUint8List
  }
  func echo(_ anObject: Any) -> Any {
    return anObject
  }
  func echo(_ aList: [Any?]) throws -> [Any?] {
    return aList
  }
  func echo(_ aMap: [String?: Any?]) throws -> [String?: Any?] {
    return aMap
  }
  func extractNestedNullableString(from wrapper: AllNullableTypesWrapper) -> String? {
    return wrapper.values.aNullableString;
  }
  func createNestedObject(with nullableString: String?) -> AllNullableTypesWrapper {
    return AllNullableTypesWrapper(values: AllNullableTypes(aNullableString: nullableString))
  }
  func sendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int64?, aString aNullableString: String?) -> AllNullableTypes {
    let someThings = AllNullableTypes(aNullableBool: aNullableBool, aNullableInt: aNullableInt, aNullableString: aNullableString)
    return someThings
  }
  func echo(_ aNullableInt: Int64?) -> Int64? {
    return aNullableInt
  }
  func echo(_ aNullableDouble: Double?) -> Double? {
    return aNullableDouble
  }
  func echo(_ aNullableBool: Bool?) -> Bool? {
    return aNullableBool
  }
  func echo(_ aNullableString: String?) -> String? {
    return aNullableString
  }
  func echo(_ aNullableUint8List: FlutterStandardTypedData?) -> FlutterStandardTypedData? {
    return aNullableUint8List
  }
  func echo(_ aNullableObject: Any?) -> Any? {
    return aNullableObject
  }
  func echoNullable(_ aNullableList: [Any?]?) throws -> [Any?]? {
    return aNullableList
  }
  func echoNullable(_ aNullableMap: [String?: Any?]?) throws -> [String?: Any?]? {
    return aNullableMap
  }
    completion(.success(everything))
  }
    completion(.success(aString))
  }
    completion(.success(anInt))
  }
    completion(.success(anObject))
  }
    // TODO: (tarrinneal) Once flutter api error handling is added, enable these tests.
    // See issue https://github.com/flutter/flutter/issues/118243
  }
  ) {
    flutterAPI.sendMultipleNullableTypes(
      aBool: aNullableBool,
      anInt: aNullableInt,
      aString: aNullableString
    ) {
      completion(.success($0))
    }
  }
    flutterAPI.echo(aDouble) {
      completion(.success($0))
    }
  }
    flutterAPI.echo(aList) {
      completion(.success($0))
    }
  }
    flutterAPI.echoNullable(anInt) {
      completion(.success($0))
    }
  }
    flutterAPI.echoNullable(aList) {
      completion(.success($0))
    }
  }
    flutterAPI.echoNullable(aMap) {
      completion(.success($0))
    }
  }
}