generate method

void generate()

Generates the plugin code based on the current permissions in manifest and plist.

This method:

  1. Scans manifest/plist for permissions that require code generation.
  2. Creates necessary Android/iOS platform code (Kotlin/Swift).
  3. Updates the tools/permit_plugin directory.
  4. Updates pubspec.yaml to include the generated local plugin.

Implementation

void generate() {
  final templates = <Template>[];
  final swiftHandlers = _getSwiftHandlers();
  if (swiftHandlers.isNotEmpty) {
    templates.addAll([
      PluginPodTemp(),
      PluginPrivacyManifestTemp(),
      PluginSwiftClassTemp(List.of(swiftHandlers)),
    ]);
  } else {
    _deleteDir(_iosDir);
  }

  final kotlinHandlers = _getKotlinHandlers();

  // adds Bluetooth handler if iOS Bluetooth permission is requested
  // granular handlers will still be generated
  if (swiftHandlers.any((e) => e.key == IosPermissions.bluetooth.group)) {
    final androidPermissionKeys = kotlinHandlers
        .expand((handler) => handler.permissions.map((e) => e.key))
        .toSet();
    final androidBluetoothPermissions = <AndroidPermissionDef>{};
    if (androidPermissionKeys.contains(
      AndroidPermissions.bluetoothScan.key,
    )) {
      androidBluetoothPermissions.add(AndroidPermissions.bluetoothScan);
    }
    if (androidPermissionKeys.contains(
      AndroidPermissions.bluetoothConnect.key,
    )) {
      androidBluetoothPermissions.add(AndroidPermissions.bluetoothConnect);
    }
    if (androidBluetoothPermissions.isNotEmpty) {
      kotlinHandlers.add(
        KotlinHandlerSnippet(
          key: IosPermissions.bluetooth.group,
          permissions: List.of(androidBluetoothPermissions),
        ),
      );
    }
  }

  if (kotlinHandlers.isNotEmpty) {
    templates.addAll([
      PluginManifestTemp(),
      PluginGradleTemp(),
      PluginKotlinClassTemp(handlers: kotlinHandlers),
    ]);
  } else {
    _deleteDir(_androidDir);
  }

  final rootPath = pathFinder.root.path;
  if (templates.isEmpty) {
    _deleteDir(
      _toolRoot,
      message: 'Deleted existing plugin generation directory.',
    );
    final toolDir = Directory(p.join(rootPath, 'tools'));
    if (toolDir.existsSync() && toolDir.listSync().isEmpty) {
      toolDir.deleteSync();
    }
    // remove dependency from pubspec.yaml
    final pubspecFile = pathFinder.getPubspec();
    if (pubspecFile != null) {
      final pubspecEditor = PubspecEditor(pubspecFile.readAsStringSync());
      if (pubspecEditor.removeDependency('permit_plugin')) {
        if (pubspecEditor.save(pubspecFile)) {
          Logger.info('Removed permit_plugin dependency from pubspec.yaml');
        }
      }
    }
    return;
  }

  templates.add(
    PluginPubspecTemp(
      android: kotlinHandlers.isNotEmpty,
      ios: swiftHandlers.isNotEmpty,
    ),
  );

  final allKeys = {
    ...kotlinHandlers.map((e) => e.key),
    ...swiftHandlers.map((e) => e.key),
  };

  final snippets = allKeys.map((key) {
    final kotlinHandler = kotlinHandlers.firstWhereOrNull(
      (h) => h.key == key,
    );
    final swiftHandler = swiftHandlers.firstWhereOrNull((h) => h.key == key);
    return PermissionGetterSnippet(
      key,
      entries: [
        ...?kotlinHandler?.permissions,
        if (swiftHandler != null) swiftHandler.entry,
      ],
    );
  }).toList();

  templates.add(PluginDartTemp(snippets));

  for (var template in templates) {
    try {
      final file = File(p.join(rootPath, _toolRoot, template.path));
      file.createSync(recursive: true);
      file.writeAsStringSync(template.generate());
    } catch (e) {
      Logger.error('Failed to generate ${template.path}: $e');
    }
  }

  final pubspecFile = pathFinder.getPubspec();
  if (pubspecFile == null) {
    Logger.error('Pubspec.yaml not found. Cannot update dependencies.');
    return;
  }
  final pubspecEditor = PubspecEditor(pubspecFile.readAsStringSync());
  if (!pubspecEditor.hasDependency('permit_plugin')) {
    pubspecEditor.addPathDependency('permit_plugin', _toolRoot);
    if (pubspecEditor.save(pubspecFile)) {
      Logger.info(
        'pubspec.yaml updated, run ${Logger.mutedPen("flutter pub get")} then hard-reload App.',
      );
    } else {
      Logger.error(
        'Failed to update pubspec.yaml with permit_plugin dependency.',
      );
    }
  } else {
    Logger.info('Plugin code updated, hard-reload is required.');
  }
}