linkSwiftPlugin function

void linkSwiftPlugin(
  1. String pluginName,
  2. List<Map<String, String>> modules, {
  3. String baseDir = '.',
})

Implementation

void linkSwiftPlugin(
  String pluginName,
  List<Map<String, String>> modules, {
  String baseDir = '.',
}) {
  final iosDir = Directory(p.join(baseDir, 'ios'));
  if (!iosDir.existsSync()) return;
  final pluginFiles = iosDir
      .listSync(recursive: true, followLinks: false)
      .whereType<File>()
      .where((f) => !f.path.contains('.symlinks'))
      .where((f) => f.path.endsWith('Plugin.swift'))
      .toList();

  if (pluginFiles.isEmpty) {
    // Create default iOS plugin stub if missing (mirrors macOS behaviour).
    final className = _toPascalCase(pluginName);
    final fileName = '${className}Plugin.swift';
    final targetPath = p.join(iosDir.path, 'Classes', fileName);
    Directory(p.dirname(targetPath)).createSync(recursive: true);
    final stub = st.iosPluginSwiftStub(className);
    File(targetPath).writeAsStringSync(stub);
    pluginFiles.add(File(targetPath));
  }
  final pluginFile = pluginFiles.first;
  var content = pluginFile.readAsStringSync();
  bool modified = false;
  for (final m in modules) {
    final name = m['module']!;
    final lib = (m['lib'] ?? name.toLowerCase()).replaceAll('-', '_');
    final reg = '${name}Registry';
    final impl = name.endsWith('Module') ? '${name}Impl' : '${name}ModuleImpl';

    // ── 1. No module import needed — bridge .swift files are compiled into
    //        the same CocoaPods pod target. Remove any stale module import.
    final staleImportPattern = RegExp(
      r'#if canImport\(nitro_' +
          RegExp.escape(lib) +
          r'_module\)\s*\nimport nitro_' +
          RegExp.escape(lib) +
          r'_module\s*\n#endif\s*\n?',
    );
    if (staleImportPattern.hasMatch(content)) {
      content = content.replaceAll(staleImportPattern, '');
      modified = true;
    }
    final bareImport = RegExp(
      r'import nitro_' + RegExp.escape(lib) + r'_module[ \t]*\r?\n?',
    );
    if (bareImport.hasMatch(content)) {
      content = content.replaceAll(bareImport, '');
      modified = true;
    }

    // ── 2. Ensure register() call is present ────────────────────────────────
    if (!content.contains('$reg.register')) {
      final match = RegExp(
        r'\w+Registry\.register\(.*?\)\)',
      ).allMatches(content);
      if (match.isNotEmpty) {
        content = content.replaceFirst(
          match.last.group(0)!,
          '${match.last.group(0)!}\n        $reg.register($impl())',
        );
        modified = true;
      } else {
        content = content.replaceFirst(
          'public static func register(with registrar: FlutterPluginRegistrar) {',
          'public static func register(with registrar: FlutterPluginRegistrar) {\n        $reg.register($impl())',
        );
        modified = true;
      }
    }
  }
  if (modified) pluginFile.writeAsStringSync(content);
}