From 91516c2f20dae29c3bf469317b7e1b404704dea9 Mon Sep 17 00:00:00 2001 From: Zach Russell Date: Fri, 20 Mar 2026 12:15:10 -0600 Subject: [PATCH] initial flutter android build --- android/app/build.gradle | 8 ++- android/app/src/main/AndroidManifest.xml | 2 +- flake.nix | 2 - hook/build.dart | 82 ++++++++++++++++++++++-- lib/main.dart | 18 +++--- 5 files changed, 96 insertions(+), 16 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index ce5f465..fd51ea0 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -39,6 +39,11 @@ android { targetCompatibility = JavaVersion.VERSION_17 } + kotlinOptions { + // do we want to update.. eventually? + jvmTarget = "17" + } + defaultConfig { applicationId = "nexus.federated.Nexus" minSdk = 29 @@ -50,7 +55,8 @@ android { signingConfigs { release { keyAlias "key" - storeFile keystoreProperties['path'] ? file(keystoreProperties['path']) : file(System.getenv("KEYSTORE_PATH")) + def storePath = keystoreProperties['path'] ?: System.getenv("KEYSTORE_PATH") + storeFile storePath ? file(storePath) : null keyPassword keystoreProperties['password'] ?: System.getenv("KEYSTORE_PASSWORD") storePassword keystoreProperties['password'] ?: System.getenv("KEYSTORE_PASSWORD") } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1c369c9..666977e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -10,7 +10,7 @@ android:label="Nexus" android:name="${applicationName}" android:icon="@mipmap/ic_launcher" - android:roundIcon="@mipmap/nexus_round" + android:roundIcon="@mipmap/ic_launcher" android:allowBackup="false" android:fullBackupContent="false"> main(List args) => build(args, (input, output) async { final buildDir = input.packageRoot.resolve("src/"); if (await File(buildDir.resolve("lock").toFilePath()).exists()) return; - final targetOS = input.config.code.targetOS; + final codeConfig = input.config.code; + final targetOS = codeConfig.targetOS; + final targetArch = codeConfig.targetArchitecture; + String libFileName; + Map env = {}; switch (targetOS) { case OS.linux: libFileName = "libgomuks.so"; @@ -18,20 +22,51 @@ Future main(List args) => build(args, (input, output) async { case OS.windows: libFileName = "libgomuks.dll"; break; + case OS.android: + libFileName = "libgomuks.so"; + + final targetNdkApi = codeConfig.android.targetNdkApi; + + final ndkHome = Platform.environment["ANDROID_NDK_HOME"] + ?? Platform.environment["ANDROID_NDK_ROOT"] + ?? Platform.environment["NDK_HOME"] + ?? await _findNdkFromSdk(); + if (ndkHome == null) { + throw Exception( + "Could not find Android NDK. Set ANDROID_NDK_HOME or install via sdkmanager.", + ); + } + + final hostTag = _ndkHostTag(); + final (goArch, ccTriple) = _androidArch(targetArch); + final cc = "$ndkHome/toolchains/llvm/prebuilt/$hostTag/bin/$ccTriple$targetNdkApi-clang"; + + env = { + "CGO_ENABLED": "1", + "GOOS": "android", + "GOARCH": goArch, + "CC": cc, + }; + break; default: throw UnsupportedError("Unsupported OS: $targetOS"); } final gomuksBuildDir = buildDir.resolve("gomuks/"); - final libFile = gomuksBuildDir.resolve(libFileName); + final libFile = gomuksBuildDir.resolve("${targetArch.name}/$libFileName"); - print("Building Gomuks shared library $libFileName from source..."); + // goheif/dav1d supported on Android would need to fix upstream + final tags = targetOS == OS.android ? "goolm,noheic" : "goolm"; + + print("Building Gomuks shared library $libFileName (${targetOS.name}/${targetArch.name}) from source..."); final result = await Process.run("go", [ "build", + "-tags", tags, "-o", libFile.path, "-buildmode=c-shared", - ], workingDirectory: gomuksBuildDir.resolve("source/pkg/ffi/").toFilePath()); + ], workingDirectory: gomuksBuildDir.resolve("source/pkg/ffi/").toFilePath(), + environment: env.isNotEmpty ? env : null); if (result.exitCode != 0) { throw Exception("Failed to build Gomuks shared library\n${result.stderr}"); @@ -52,3 +87,42 @@ Future main(List args) => build(args, (input, output) async { ..dependencies.add(gomuksBuildDir); print("Done!"); }); + +Future _findNdkFromSdk() async { + // pretty sure this wont be needed with nix, i'll get this removed + final androidHome = Platform.environment["ANDROID_HOME"] + ?? Platform.environment["ANDROID_SDK_ROOT"]; + if (androidHome == null) return null; + final ndkDir = Directory("$androidHome/ndk"); + if (!await ndkDir.exists()) return null; + final versions = await ndkDir.list().toList(); + if (versions.isEmpty) return null; + versions.sort((a, b) => a.path.compareTo(b.path)); + return versions.last.path; +} + +String _ndkHostTag() { + if (Platform.isMacOS) { + return "darwin-x86_64"; + } else if (Platform.isLinux) { + return "linux-x86_64"; + } else if (Platform.isWindows) { + return "windows-x86_64"; + } + throw UnsupportedError("Unsupported host platform for Android NDK"); +} + +(String goArch, String ccTriple) _androidArch(Architecture arch) { + switch (arch) { + case Architecture.arm64: + return ("arm64", "aarch64-linux-android"); + case Architecture.arm: + return ("arm", "armv7a-linux-androideabi"); + case Architecture.x64: + return ("amd64", "x86_64-linux-android"); + case Architecture.ia32: + return ("386", "i686-linux-android"); + default: + throw UnsupportedError("Unsupported Android architecture: $arch"); + } +} diff --git a/lib/main.dart b/lib/main.dart index 5ad6c24..ddba498 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -59,15 +59,17 @@ void showError(Object error, [StackTrace? stackTrace]) { void main() async { WidgetsFlutterBinding.ensureInitialized(); - await windowManager.ensureInitialized(); - await windowManager.waitUntilReadyToShow( - WindowOptions(titleBarStyle: TitleBarStyle.hidden), - ); + if (Platform.isLinux || Platform.isMacOS || Platform.isWindows) { + await windowManager.ensureInitialized(); + await windowManager.waitUntilReadyToShow( + WindowOptions(titleBarStyle: TitleBarStyle.hidden), + ); - if (Platform.isLinux) { - setWindowMinSize(const Size.square(500)); - } else { - await windowManager.setMinimumSize(Size.square(500)); + if (Platform.isLinux) { + setWindowMinSize(const Size.square(500)); + } else { + await windowManager.setMinimumSize(Size.square(500)); + } } FlutterError.onError = (FlutterErrorDetails details) => -- 2.53.0