linkNativeImplStarters function
Writes missing Swift and Kotlin impl classes. Returns the Apple platforms
(ios/macos) that received a new file (their SwiftPM sources need a resync).
Implementation
Set<String> linkNativeImplStarters({String baseDir = '.'}) {
final generated = p.join(baseDir, 'lib', 'src', 'generated');
final touched = <String>{};
for (final platform in ['ios', 'macos']) {
final classes = Directory(p.join(baseDir, platform, 'Classes'));
if (!classes.existsSync()) continue;
final sources = classes.listSync().whereType<File>().where((f) => f.path.endsWith('.swift')).toList();
final plugin = sources.where((f) => f.path.endsWith('Plugin.swift')).firstOrNull;
if (plugin == null) continue;
final existing = sources.map((f) => f.readAsStringSync()).join('\n');
for (final m in RegExp(r'(\w+)Registry\.register\((\w+)\(').allMatches(plugin.readAsStringSync())) {
final (module, cls) = (m.group(1)!, m.group(2)!);
if (RegExp('class\\s+$cls\\b').hasMatch(existing)) continue;
final members = _protocolMembers(Directory(p.join(generated, 'swift')), 'public protocol Hybrid${module}Protocol: AnyObject {', '.swift');
if (members == null) continue;
File(p.join(classes.path, '$cls.swift')).writeAsStringSync(_swiftStarter(module, cls, members));
touched.add(platform);
}
}
final ktRoot = Directory(p.join(baseDir, 'android', 'src', 'main', 'kotlin'));
if (ktRoot.existsSync()) {
final kts = ktRoot.listSync(recursive: true).whereType<File>().where((f) => f.path.endsWith('.kt')).toList();
final plugin = kts.where((f) => f.path.endsWith('Plugin.kt')).firstOrNull;
if (plugin != null) {
final pluginSrc = plugin.readAsStringSync();
final pkg = RegExp(r'^package\s+([\w.]+)', multiLine: true).firstMatch(pluginSrc)?.group(1);
final existing = kts.map((f) => f.readAsStringSync()).join('\n');
for (final m in RegExp(r'(\w+)JniBridge\.registerFactory\(\{\s*(\w+)\(').allMatches(pluginSrc)) {
final (module, cls) = (m.group(1)!, m.group(2)!);
if (pkg == null || RegExp('class\\s+$cls\\b').hasMatch(existing)) continue;
final genFile = _fileDeclaring(Directory(p.join(generated, 'kotlin')), 'interface Hybrid${module}Spec {', '.kt');
final members = genFile == null ? null : _blockMembers(genFile.readAsStringSync(), 'interface Hybrid${module}Spec {');
if (members == null) continue;
final imports = RegExp(r'^import .+$', multiLine: true).allMatches(genFile!.readAsStringSync()).map((i) => i.group(0)!).toSet();
final genPkg = RegExp(r'^package\s+([\w.]+)', multiLine: true).firstMatch(genFile.readAsStringSync())!.group(1)!;
File(p.join(plugin.parent.path, '$cls.kt')).writeAsStringSync(_kotlinStarter(pkg, genPkg, imports, module, cls, members));
}
}
}
return touched;
}