run method

  1. @override
Future<void> run()
override

Runs this command.

The return value is wrapped in a Future if necessary and returned by CommandRunner.runCommand.

Implementation

@override
Future<void> run() async {
  var key = argResults?.rest.isNotEmpty == true ? argResults!.rest[0] : '';

  // Read existing permissions from both platforms
  final manifestFile = pathFinder.getManifest();
  final plistFile = pathFinder.getInfoPlist();
  if (manifestFile == null && plistFile == null) {
    Logger.error(
      'Could not locate AndroidManifest.xml or Info.plist in the current directory.',
    );
    return;
  }

  final manifestEditor = manifestFile == null
      ? null
      : ManifestEditor(manifestFile.readAsStringSync());
  final plistEditor = plistFile == null
      ? null
      : PListEditor(plistFile.readAsStringSync());

  final existingEntries = [
    ...?manifestEditor?.getPermissions(),
    ...?plistEditor?.getUsageDescriptions(),
  ];

  if (existingEntries.isEmpty) {
    Logger.info('No permissions found to remove.');
    return;
  }

  void onRemoveEntries(List<XmlEntry> entries) {
    final androidEntries = entries.whereType<ManifestPermissionEntry>();
    final iosEntries = entries.whereType<PListUsageDescription>();

    if (androidEntries.isNotEmpty) {
      _removeAndroidPermissions(
        androidEntries.toList(),
        manifestEditor!,
        manifestFile!,
      );
    }
    if (iosEntries.isNotEmpty) {
      _removeIosPermissions(iosEntries.toList(), plistEditor!, plistFile!);
    }
    PluginGenerator(pathFinder: pathFinder).generate();
  }

  // If no key provided, show multi-select of all existing permissions
  if (key.isEmpty) {
    final maxLineLength = existingEntries
        .map((e) => e.key.length)
        .reduce(max);

    final selectedEntries = multiSelect(
      'Select permissions to remove',
      options: existingEntries,
      display: (entry) {
        final platform = entry is ManifestPermissionEntry ? 'Android' : 'iOS';
        final option = '$platform: ${entry.key}';
        if (entry.isLegacy) {
          return option.padRight(maxLineLength + 12) +
              Logger.mutedPen.write('(legacy)');
        } else {
          return option;
        }
      },
    );

    if (selectedEntries.isEmpty) {
      Logger.info('No permissions selected.');
      return;
    }

    onRemoveEntries(selectedEntries);
    return;
  }

  // If key provided, lookup matching entries
  final entriesLookup = EntriesLookup.forDefaults(
    androidOnly: argResults?['android'] == true,
    iosOnly: argResults?['ios'] == true,
  );

  final definitions = entriesLookup.find(key);

  if (definitions.isEmpty) {
    Logger.info('No permission definitions found for: $key');
    return;
  }

  // Filter existing entries by the looked-up definitions
  final matchingEntries = existingEntries.where((entry) {
    return definitions.any((def) => def.key == entry.key);
  }).toList();

  if (matchingEntries.isEmpty) {
    Logger.info('No installed permissions found matching: $key');
    return;
  }

  var selected = matchingEntries;
  if (matchingEntries.length > 1) {
    selected = multiSelect(
      'Select which permissions to remove',
      options: matchingEntries,
      display: (entry) {
        final platform = entry is ManifestPermissionEntry ? 'Android' : 'iOS';
        return '$platform: ${entry.key}';
      },
    );
  }

  onRemoveEntries(selected);
}