linkAndroid function
void
linkAndroid(})
Configures android/build.gradle (or .kts) so the generated Kotlin bridge
files in lib/src/generated/kotlin/ are compiled as part of the Android build.
Without the kotlin.srcDirs entry, all .bridge.g.kt files are generated but
never compiled — causing "Unresolved reference: XxxJniBridge" errors at build time.
Implementation
void linkAndroid(
String pluginName,
List<String> moduleLibs, {
String baseDir = '.',
List<ModuleInfo>? moduleInfos,
}) {
File? buildGradle;
for (final candidate in [
File(p.join(baseDir, 'android', 'build.gradle')),
File(p.join(baseDir, 'android', 'build.gradle.kts')),
]) {
if (candidate.existsSync()) {
buildGradle = candidate;
break;
}
}
if (buildGradle == null) return;
var content = buildGradle.readAsStringSync();
bool modified = false;
final isKts = buildGradle.path.endsWith('.kts');
// 0. Upgrade a legacy apply-plugin build.gradle to the modern plugins{} DSL.
final upgrade = _gradleUpgradeToPluginsDsl(content);
content = upgrade.content;
modified = modified || upgrade.modified;
// 1. Ensure kotlin.srcDirs for the generated Kotlin bridges.
final srcDirs = _gradleEnsureKotlinSrcDirs(content, isKts);
content = srcDirs.content;
modified = modified || srcDirs.modified;
// 2. Ensure kotlinOptions has the expected JVM target for correct bytecode.
if (!content.contains('kotlinOptions')) {
final androidMatch = RegExp(r'\bandroid\s*\{').firstMatch(content);
if (androidMatch != null) {
content = content.replaceRange(
androidMatch.end,
androidMatch.end,
'\n kotlinOptions { jvmTarget = "${BuildVersions.androidJvmTarget}" }',
);
modified = true;
}
}
// 3. Ensure kotlinx-coroutines (required for generated Kotlin suspend bridge functions).
if (!content.contains('kotlinx-coroutines')) {
final depsMatch = RegExp(r'\bdependencies\s*\{').firstMatch(content);
if (depsMatch != null) {
content = content.replaceRange(
depsMatch.end,
depsMatch.end,
'\n implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"\n implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3"',
);
} else {
content +=
'\ndependencies {\n implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"\n implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3"\n}\n';
}
modified = true;
}
// 4. Ensure consumerProguardFiles "consumer-rules.pro" is wired into
// defaultConfig for any module using the Kotlin JNI bridge.
final proguard = _gradleEnsureConsumerProguard(
content,
isKts: isKts,
moduleInfos: moduleInfos,
baseDir: baseDir,
);
content = proguard.content;
modified = modified || proguard.modified;
if (modified) buildGradle.writeAsStringSync(content);
}