Initial flutter android build #4

Open
zaaach wants to merge 1 commit from zaaach/nexus:android into main
5 changed files with 96 additions and 16 deletions
Showing only changes of commit 91516c2f20 - Show all commits

initial flutter android build

Zach Russell 2026-03-20 12:15:10 -06:00

View file

@ -39,6 +39,11 @@ android {
targetCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17
} }
kotlinOptions {
// do we want to update.. eventually?
jvmTarget = "17"
}
defaultConfig { defaultConfig {
applicationId = "nexus.federated.Nexus" applicationId = "nexus.federated.Nexus"
minSdk = 29 minSdk = 29
@ -50,7 +55,8 @@ android {
signingConfigs { signingConfigs {
release { release {
keyAlias "key" 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") keyPassword keystoreProperties['password'] ?: System.getenv("KEYSTORE_PASSWORD")
storePassword keystoreProperties['password'] ?: System.getenv("KEYSTORE_PASSWORD") storePassword keystoreProperties['password'] ?: System.getenv("KEYSTORE_PASSWORD")
} }

View file

@ -10,7 +10,7 @@
android:label="Nexus" android:label="Nexus"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/nexus_round" android:roundIcon="@mipmap/ic_launcher"
android:allowBackup="false" android:allowBackup="false"
android:fullBackupContent="false"> android:fullBackupContent="false">
<activity <activity

View file

@ -33,7 +33,6 @@
_module.args.pkgs = import nixpkgs { _module.args.pkgs = import nixpkgs {
inherit system; inherit system;
config = { config = {
permittedInsecurePackages = [ "olm-3.2.16" ];
android_sdk.accept_license = true; android_sdk.accept_license = true;
allowUnfree = true; allowUnfree = true;
}; };
@ -43,7 +42,6 @@
let let
packages = with pkgs; [ packages = with pkgs; [
go go
olm
git git
]; ];

View file

@ -6,8 +6,12 @@ Future<void> main(List<String> args) => build(args, (input, output) async {
final buildDir = input.packageRoot.resolve("src/"); final buildDir = input.packageRoot.resolve("src/");
if (await File(buildDir.resolve("lock").toFilePath()).exists()) return; 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; String libFileName;
Map<String, String> env = {};
switch (targetOS) { switch (targetOS) {
case OS.linux: case OS.linux:
libFileName = "libgomuks.so"; libFileName = "libgomuks.so";
@ -18,20 +22,51 @@ Future<void> main(List<String> args) => build(args, (input, output) async {
case OS.windows: case OS.windows:
libFileName = "libgomuks.dll"; libFileName = "libgomuks.dll";
break; 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: default:
throw UnsupportedError("Unsupported OS: $targetOS"); throw UnsupportedError("Unsupported OS: $targetOS");
} }
final gomuksBuildDir = buildDir.resolve("gomuks/"); 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", [ final result = await Process.run("go", [
"build", "build",
"-tags", tags,
"-o", "-o",
libFile.path, libFile.path,
"-buildmode=c-shared", "-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) { if (result.exitCode != 0) {
throw Exception("Failed to build Gomuks shared library\n${result.stderr}"); throw Exception("Failed to build Gomuks shared library\n${result.stderr}");
@ -52,3 +87,42 @@ Future<void> main(List<String> args) => build(args, (input, output) async {
..dependencies.add(gomuksBuildDir); ..dependencies.add(gomuksBuildDir);
print("Done!"); print("Done!");
}); });
Future<String?> _findNdkFromSdk() async {
// pretty sure this wont be needed with nix, i'll get this removed

Yeah, if this stuff could be removed that'd be great.

Yeah, if this stuff could be removed that'd be great.
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");
}
}

View file

@ -59,6 +59,7 @@ void showError(Object error, [StackTrace? stackTrace]) {
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
if (Platform.isLinux || Platform.isMacOS || Platform.isWindows) {
await windowManager.ensureInitialized(); await windowManager.ensureInitialized();

Changes may also be needed in widgets/appbar.dart, specifically the onPanStart callback, but it may just be ignored as is. We can test once launch works.

Changes may also be needed in `widgets/appbar.dart`, specifically the `onPanStart` callback, but it may just be ignored as is. We can test once launch works.
await windowManager.waitUntilReadyToShow( await windowManager.waitUntilReadyToShow(
WindowOptions(titleBarStyle: TitleBarStyle.hidden), WindowOptions(titleBarStyle: TitleBarStyle.hidden),
@ -69,6 +70,7 @@ void main() async {
} else { } else {
await windowManager.setMinimumSize(Size.square(500)); await windowManager.setMinimumSize(Size.square(500));
} }
}
FlutterError.onError = (FlutterErrorDetails details) => FlutterError.onError = (FlutterErrorDetails details) =>
showError(details.exception.toString(), details.stack); showError(details.exception.toString(), details.stack);