linkKotlinLoadLibraries function

void linkKotlinLoadLibraries(
  1. List<String> libs, {
  2. String baseDir = '.',
})

Ensures System.loadLibrary("lib") is present in the Kotlin plugin's companion object init block for each cpp module lib. cpp modules use __attribute__((constructor)) for auto-registration, so no JniBridge.register call is needed — just loading the .so is enough.

Implementation

void linkKotlinLoadLibraries(List<String> libs, {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 lib in libs) {
    if (!content.contains('loadLibrary("$lib")')) {
      // Insert after the last existing System.loadLibrary call in the init block
      final match = RegExp(
        r'System\.loadLibrary\("[^"]+"\)',
      ).allMatches(content);
      if (match.isNotEmpty) {
        content = content.replaceFirst(
          match.last.group(0)!,
          '${match.last.group(0)!}\n            System.loadLibrary("$lib")',
        );
      } else {
        // Fallback: inject into existing companion object, or insert a new one.
        final className = p.basenameWithoutExtension(pluginFile.path);
        final classPattern = RegExp('class\\s+$className[^{]*\\{');
        final classMatch = classPattern.firstMatch(content);
        if (classMatch == null) {
          throw Exception(
            'nitrogen link failed: Cannot find opening "{" for class $className in ${p.basename(pluginFile.path)} '
            'to inject System.loadLibrary("$lib"). Please add it manually.',
          );
        }
        // Check if there's already a companion object in the class body
        final classBody = classMatch.group(0)!;
        final companionPattern = RegExp(r'companion\s+object');
        if (companionPattern.hasMatch(content)) {
          // Inject into existing companion object before its closing brace
          final companionMatch = RegExp(
            r'companion\s+object[^{]*\{([^}]*)\}',
          ).firstMatch(content);
          if (companionMatch != null) {
            content = content.replaceFirst(
              companionMatch.group(0)!,
              companionMatch
                  .group(0)!
                  .replaceFirst(
                    '}',
                    '    System.loadLibrary("$lib")\n        }',
                  ),
            );
          } else {
            throw Exception(
              'nitrogen link failed: Found companion object in $className (${p.basename(pluginFile.path)}) '
              'but could not locate its closing brace to inject System.loadLibrary("$lib"). Please add it manually.',
            );
          }
        } else {
          content = content.replaceFirst(
            classBody,
            '$classBody\n    companion object {\n        init { System.loadLibrary("$lib") }\n    }\n',
          );
        }
      }
      modified = true;
    }
  }
  if (modified) pluginFile.writeAsStringSync(content);
}