generate method
void
generate()
Generates the plugin code based on the current permissions in manifest and plist.
This method:
- Scans manifest/plist for permissions that require code generation.
- Creates necessary Android/iOS platform code (Kotlin/Swift).
- Updates the
tools/permit_plugindirectory. - Updates
pubspec.yamlto 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.');
}
}