linkKotlinPlugin function
void
linkKotlinPlugin(})
Implementation
void linkKotlinPlugin(
String pluginName,
List<Map<String, String>> modules, {
String baseDir = '.',
}) {
final kotlinDir = Directory(
p.join(baseDir, 'android', 'src', 'main', 'kotlin'),
);
if (!kotlinDir.existsSync()) return;
final pluginFiles = kotlinDir
.listSync(recursive: true, followLinks: false)
.whereType<File>()
.where((f) => !f.path.contains('.symlinks'))
.where((f) => f.path.endsWith('Plugin.kt'))
.toList();
if (pluginFiles.isEmpty) return;
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}JniBridge';
final impl = '${name}Impl';
// The Kotlin generator emits: package nitro.${lib}_module
// so the fully-qualified import is: import nitro.${lib}_module.${Module}JniBridge
final importLine = 'import nitro.${lib}_module.$reg';
// ── 1. Ensure import is present ─────────────────────────────────────────
if (!content.contains(importLine)) {
// Insert after the last 'import …' line in the file for clean ordering.
final importMatches = RegExp(
r'^import .+$',
multiLine: true,
).allMatches(content);
if (importMatches.isNotEmpty) {
final lastImport = importMatches.last;
content = content.replaceRange(
lastImport.end,
lastImport.end,
'\n$importLine',
);
} else {
// No imports yet — add one blank line after the package declaration.
content = content.replaceFirstMapped(
RegExp(r'^package .+$', multiLine: true),
(m) => '${m.group(0)!}\n\n$importLine',
);
}
modified = true;
}
// ── 2. Ensure register() call is present ────────────────────────────────
// Detect whether XxxImpl needs a Context argument by scanning the impl file.
// Nitro Kotlin impls commonly take Context in their primary constructor.
// If we inject XxxImpl() when XxxImpl(context: Context) is required, the
// call compiles but crashes at runtime — pass binding.applicationContext.
final implArg = _detectKotlinImplArg(impl, baseDir: baseDir);
final registerCall = '$reg.register($impl($implArg))';
if (!content.contains('$reg.register')) {
final match = RegExp(
r'\w+JniBridge\.register\(.*?\)\)',
).allMatches(content);
if (match.isNotEmpty) {
// Append after the last existing JniBridge.register() call.
content = content.replaceFirst(
match.last.group(0)!,
'${match.last.group(0)!}\n $registerCall',
);
} else {
content = content.replaceFirst(
'override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {',
'override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {\n $registerCall',
);
}
modified = true;
}
}
if (modified) pluginFile.writeAsStringSync(content);
}