-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[v2] Add support for Android builds #67
Conversation
* set user.home for Android Gradle Plugin * pass build inputs
Hi, I saw this PR when looking up how best to build android apps with nix and it looks super promising! Unfortunately when I tried to run that build on x86_64 linux I get the following error:
|
Ah, the root error is actually |
I believe that the diff --git a/CredentialManager/flake.nix b/CredentialManager/flake.nix
index bed4f5c..b6e35a7 100644
--- a/CredentialManager/flake.nix
+++ b/CredentialManager/flake.nix
@@ -57,5 +57,8 @@
echo Welcome to Android shell!
'';
};
+ devShells.gradle2nix = pkgs.mkShell {
+ packages = [gradle2nix.packages.${system}.default jdk android-sdk pkgs.aapt];
+ };
});
} that ends with this error:
|
diff --git a/CredentialManager/flake.nix b/CredentialManager/flake.nix
index bed4f5c..a91547e 100644
--- a/CredentialManager/flake.nix
+++ b/CredentialManager/flake.nix
@@ -37,7 +37,7 @@
gradleFlags = [ "build" "--stacktrace" "--info" ];
src = ./.;
extraBuildInputs = [
- android-sdk
+ android-sdk pkgs.aapt
];
postBuild = ''
mkdir -p $out
@@ -57,5 +57,14 @@
echo Welcome to Android shell!
'';
};
+ devShells.gradle2nix = pkgs.mkShell {
+ NIX_LD_LIBRARY_PATH = with pkgs; lib.makeLibraryPath [
+ stdenv.cc.cc
+ #openssl
+ # ...
+ ];
+ NIX_LD = with pkgs; lib.fileContents "${stdenv.cc}/nix-support/dynamic-linker";
+ packages = [gradle2nix.packages.${system}.default jdk android-sdk pkgs.aapt];
+ };
});
}
diff --git a/CredentialManager/gradle.lock b/CredentialManager/gradle.lock
index f1cd87f..4212d9e 100644
--- a/CredentialManager/gradle.lock
+++ b/CredentialManager/gradle.lock
@@ -1210,9 +1210,9 @@
}
},
"com.android.tools.build:aapt2:8.1.0-10154469": {
- "aapt2-8.1.0-10154469-osx.jar": {
- "url": "https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/8.1.0-10154469/aapt2-8.1.0-10154469-osx.jar",
- "hash": "sha256-w09cJqAUGZ2o6GyF9O0L++gE/Ah7mFOclIGt0j6uBeA="
+ "aapt2-8.1.0-10154469-linux.jar": {
+ "url": "https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/8.1.0-10154469/aapt2-8.1.0-10154469-linux.jar",
+ "hash": "sha256-CUCBg0GadMQF18WpZKgA2pFnWJiMvFxs/bscMJquoDw="
},
"aapt2-8.1.0-10154469.pom": {
"url": "https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/8.1.0-10154469/aapt2-8.1.0-10154469.pom", It still doesn't work yet:
This aapt2 thing seems like it's going to be a real pain point. I did see tadfisher/android-nixpkgs#49 but it seems like that might not help much. |
Hi @expenses , thank you for testing the build on Linux! I fixed the aapt problem using this example:
It fixed local builds on macOS inside Nix shell (without gradle2nix), might work on Linux too. |
It would help to have separate lock files per architecture, or to be able to easily merge lock files. |
As of the latest commit to V2, you can override dependencies with the overrides argument. To run with lib; let
gradleLock = builtins.fromJSON (builtins.readFile ./gradle.lock);
patchJars = moduleFilter: artifactFilter: args: f: let
modules =
filterAttrs
(name: _: moduleFilter name)
gradleLock;
artifacts = filterAttrs (name: _: artifactFilter name);
patch = src: runCommand src.name args (f src);
in
mapAttrs (
_: module:
mapAttrs (_: _: patch) (artifacts module)
)
modules;
aapt2LinuxJars = optionalAttrs stdenv.isLinux (patchJars
(hasPrefix "com.android.tools.build:aapt2:") # moduleFilter
(hasSuffix "-linux.jar") # artifactFilter
{ # args to runCommand
nativeBuildInputs = [jdk autoPatchelfHook];
buildInputs = [stdenv.cc.cc.lib];
dontAutoPatchelf = true;
}
(src: '' # function to make a runCommand script
cp ${src} aapt2.jar # src <- derivation to download source
jar xf aapt2.jar aapt2
chmod +x aapt2
autoPatchelf aapt2
jar uf aapt2.jar aapt2
cp aapt2.jar $out
echo $out
''));
in
buildGradlePackage {
# ...
overrides = aapt2LinuxJars;
} |
I'm not sure this should be gradle2nix's responsibility. Gradle resolves whatever dependencies are given to it by the build script, which is a Turing-complete program that generates dependencies to resolve, with full access to the Internet. To do this right, one would have to run Gradle on each architecture, each value of 4 Across on this week's New York Times crossword puzzles, or the the least significant 4 bits from a PRNG; in short, any condition in that build script that affects the resolved dependency set. This is why Gradle is bad and Nix is good. So if you want separate lock files, you can run
Hmm, we could add a let
lockFiles = [ ./gradle.aarch64-darwin.lock ./gradle.x86_64-linux.lock ];
dependencySets = map (f: builtins.fromJSON (builtins.readFile f)) lockFiles;
in
buildGradlePackage {
# ...
dependencies = foldl' lib.recursiveUpdate { } dependencySets;
} Of course, we can merge this and |
Thanks everyone for your advice! I think this PR can be closed as the latest V2 commit lets you set
Unfortunately this didn't help as that
This helped get my app building though! |
Also see #69. |
I tried using tadfisher/android-nixpkgs#104 and got a different error:
Patching the jar is the best solution at the moment. |
One thing that may be useful for anyone building Android apps that require jars with FHS envs to run in the sandbox is this: ElvishJerricco/nixpkgs@05742c1 My modified version looks like this: { lib, buildFHSEnvChroot }:
# Similar to runInLinuxVM, except we run under a FHS user env instead
# of a VM. This allows you to use build systems that depend on the FHS
# without any sort of patching. Resulting binaries may not work on
# NixOS without wrapping them in FHS though.
drv: envArgs: let
fhsWrapper = buildFHSEnvChroot ({
name = "${drv.name}-fhs-wrapper";
runScript = "$@";
} // envArgs);
in lib.overrideDerivation drv (old: {
builder = "${fhsWrapper}/bin/${fhsWrapper.name}";
args = [old.builder] ++ old.args;
}) I added an overlay in my flake (note that I use Flake Parts so the syntax is a little different): overlayAttrs = with pkgs; {
runInFHSEnvChroot = callPackage ./run-in-fhs.nix {};
}; Then you can simply do: runInFHSEnvChroot (buildGradlePackage {
# ... gradle derivation options go here ...
}) {
# ... FHS env options go here. For example, there was a prepackaged binary in my deps that required `zlib`:
targetPkgs = pkgs: with pkgs; [ zlib ];
} Other Gradle opts that help:
If you test with robolectric, you need to set:
Note that you may also need to provide testOptions {
unitTests.all {
def val = null
if ((val = System.getProperty('robolectric.offline'))) {
systemProperty 'robolectric.offline', val
}
if ((val = System.getProperty('robolectric.dependency.dir'))) {
systemProperty 'robolectric.dependency.dir', val
}
}
} |
Is this something that every (Android) project is meant to be doing? I am fairly new to Nix but could this be provided by |
Summary
This change improves gradle2nix's compatibility with Android builds.
/var/empty/.android
directory on macOS.Android Gradle Plugin uses
$HOME/.android
directory (see ANDROID_USER_HOME variable https://developer.android.com/tools/variables#envar) to store plugin preferences and signing keystores, among other things.However the directory becomes the read-only
/var/empty/.android
in Nix builds, and the plugin fails to write there.The PR fixes the problem by setting
user.home
Gradle parameter to a temporary directory. It is enough to produce an unsigned APK.extraBuildInputs
. For instance, it can be used to pass an environment with Android SDK set up.How to test
The change can be tested by building this Gradle project: