feat: Add flutter-build.sh
This commit is contained in:
commit
92687b6513
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# NixOS artifacts
|
||||||
|
result
|
22
LICENSE
Normal file
22
LICENSE
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Alexander "PapaTutuWawa"
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
12
README.md
Normal file
12
README.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# bits-and-bytes
|
||||||
|
|
||||||
|
A collection of small scripts (and other stuff) that I want to reuse across
|
||||||
|
my personal projects.
|
||||||
|
|
||||||
|
## Nix
|
||||||
|
|
||||||
|
For users of Nix, I also provide a Flake (see `flake.nix`).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
See `LICENSE`.
|
61
flake.lock
Normal file
61
flake.lock
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1689068808,
|
||||||
|
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1689935543,
|
||||||
|
"narHash": "sha256-6GQ9ib4dA/r1leC5VUpsBo0BmDvNxLjKrX1iyL+h8mc=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "e43e2448161c0a2c4928abec4e16eae1516571bc",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
36
flake.nix
Normal file
36
flake.nix
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
description = "A collection of reusable scripts for various use-cases";
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system: let
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
|
||||||
|
flutterBuildRaw = {stdenv}: stdenv.mkDerivation {
|
||||||
|
pname = "flutter-build";
|
||||||
|
version = "0.1.0";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
|
||||||
|
install --mode 555 src/flutter-build.sh $out/bin/flutter-build
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
flutter-build-raw = pkgs.callPackage flutterBuildRaw {};
|
||||||
|
in {
|
||||||
|
packages = {
|
||||||
|
# The raw flutter-build script
|
||||||
|
inherit flutter-build-raw;
|
||||||
|
|
||||||
|
# A wrapper around the script that already provides the notify-send option
|
||||||
|
flutter-build = pkgs.writeScriptBin "flutter-build" ''
|
||||||
|
${flutter-build-raw}/bin/flutter-build \
|
||||||
|
--notify-send ${pkgs.libnotify}/bin/notify-send \
|
||||||
|
$@
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
228
src/flutter-build.sh
Normal file
228
src/flutter-build.sh
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Parse CLI arguments
|
||||||
|
# (Thanks StackOverflow https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash)
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--name)
|
||||||
|
# The name of the application. Only useful for displaying in the script.
|
||||||
|
# If not specified, will use the "name: " attribute from the pubspec.yaml
|
||||||
|
NAME=$2
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--not-signed)
|
||||||
|
# Tells the script that the APKs are *NOT* signed and have to be manually
|
||||||
|
# signed.
|
||||||
|
ALREADY_SIGNED=n
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--zipalign)
|
||||||
|
# The path to the zipalign binary. If not specified, lets the shell resolve the path
|
||||||
|
# itself.
|
||||||
|
# Only useful with --not-signed.
|
||||||
|
ZIPALIGN=$2
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--apksigner)
|
||||||
|
# The path to the apksigner binary. If not specified, lets the shell resolve the path
|
||||||
|
# itself.
|
||||||
|
# Only useful with --not-signed.
|
||||||
|
APKSIGNER=$2
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--notify-send)
|
||||||
|
# The path to the notify-send binary. If not specified, lets the shell resolve the path
|
||||||
|
# itself.
|
||||||
|
# Only useful with --not-signed.
|
||||||
|
NOTIFY_SEND=$2
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--provider-config)
|
||||||
|
# The path to the provider config passed to apksigner via --provider-arg.
|
||||||
|
# Only useful with --not-signed.
|
||||||
|
PROVIDER_CONFIG=$2
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--no-clean)
|
||||||
|
# Does not run "flutter clean" before running the build.
|
||||||
|
CLEAN_BUILD=n
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--min-sdk-version)
|
||||||
|
# The minimum SDK version that should be able to validate the APK signature.
|
||||||
|
# Only useful with --not-signed.
|
||||||
|
MIN_SDK_VERSION=$2
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--check)
|
||||||
|
# Prints all parsed options and exits.
|
||||||
|
JUST_CHECK=y
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--skip-build)
|
||||||
|
# Skips the entire build but not the signing, if --not-signed is specified. If --not-signed
|
||||||
|
# is not specified, then the build is skipped, but the APKs are copied into the correct folder.
|
||||||
|
# This flag expects that the build has run at least once and the correct release directory
|
||||||
|
# already exists.
|
||||||
|
SKIP_BUILD=y
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--no-notification)
|
||||||
|
# Does not create a notification when asking for the PIN of the Yubikey.
|
||||||
|
# Only useful with --not-signed.
|
||||||
|
SEND_NOTIFICATION=n
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown argument: $1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Extract the name, if not passed
|
||||||
|
if [[ -z "$NAME" ]]; then
|
||||||
|
NAME=$(grep -E "^name: " pubspec.yaml | cut -b 6-)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
APKSIGNER=${APKSIGNER:-apksigner}
|
||||||
|
ZIPALIGN=${ZIPALIGN:-zipalign}
|
||||||
|
ALREADY_SIGNED=${ALREADY_SIGNED:-y}
|
||||||
|
MIN_SDK_VERSION=${MIN_SDK_VERSION:-24}
|
||||||
|
CLEAN_BUILD=${CLEAN_BUILD:-y}
|
||||||
|
SKIP_BUILD=${SKIP_BUILD:-n}
|
||||||
|
NOTIFY_SEND=${NOTIFY_SEND:-notify-send}
|
||||||
|
SEND_NOTIFICATION=${SEND_NOTIFICATION:-y}
|
||||||
|
|
||||||
|
# Parse version info
|
||||||
|
version=$(grep -E "^version: " pubspec.yaml | cut -b 10-)
|
||||||
|
IFS="+" read -ra version_parts <<< "$version"
|
||||||
|
version_code="${version_parts[1]}"
|
||||||
|
release_dir="./release-${version}"
|
||||||
|
|
||||||
|
# Print a header
|
||||||
|
echo "===== ${NAME} ====="
|
||||||
|
echo "Building version ${version}"
|
||||||
|
echo "Moving APKs into ${release_dir} after build"
|
||||||
|
echo "Clean build: ${CLEAN_BUILD}"
|
||||||
|
echo "Skipping build: ${SKIP_BUILD}"
|
||||||
|
echo "Sending notification: ${SEND_NOTIFICATION}"
|
||||||
|
echo "APKs already signed: ${ALREADY_SIGNED}"
|
||||||
|
if [[ "$ALREADY_SIGNED" = "n" ]]; then
|
||||||
|
echo "Used zipalign: ${ZIPALIGN}"
|
||||||
|
echo "Used apksigner: ${APKSIGNER}"
|
||||||
|
echo "Provider config: ${PROVIDER_CONFIG}"
|
||||||
|
echo "Minimum SDK verifiability: ${MIN_SDK_VERSION}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${JUST_CHECK}" = "y" ]]; then
|
||||||
|
echo
|
||||||
|
echo "Terminating here because --check was used"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For better readability, print an empty line
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Check if we have a changelog file for that version
|
||||||
|
if [[ ! -f "./fastlane/metadata/android/en-US/changelogs/$version_code.txt" ]]; then
|
||||||
|
echo "Warning: No changelog item for $version_code"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${SKIP_BUILD}" = "y" ]]; then
|
||||||
|
echo "Skipping build because of --skip-build"
|
||||||
|
else
|
||||||
|
# Create the directory
|
||||||
|
[[ -d "${release_dir}" ]] && echo "Warning: Release directory ${release_dir} already exists"
|
||||||
|
mkdir "${release_dir}" || true
|
||||||
|
|
||||||
|
if [[ "${CLEAN_BUILD}" = "y" ]]; then
|
||||||
|
# Clean flutter build
|
||||||
|
flutter clean
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get dependencies
|
||||||
|
flutter pub get
|
||||||
|
|
||||||
|
# Build everything again
|
||||||
|
flutter pub run build_runner build --delete-conflicting-outputs
|
||||||
|
|
||||||
|
# Build the release apk
|
||||||
|
flutter build apk \
|
||||||
|
--release \
|
||||||
|
--split-per-abi \
|
||||||
|
--split-debug-info="${release_dir}/debug-info"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If we have to sign, ask for the PIN upfront
|
||||||
|
if [[ "$ALREADY_SIGNED" = "n" ]]; then
|
||||||
|
[[ "${SEND_NOTIFICATION}" = "y" ]] && ${NOTIFY_SEND} \
|
||||||
|
--urgency normal \
|
||||||
|
--app-name "Flutter Build" \
|
||||||
|
--icon dialog-password \
|
||||||
|
"Signing PIN required" \
|
||||||
|
"The build is done and the PIN for manually signing the APKs must be entered"
|
||||||
|
|
||||||
|
# Thanks https://geoffreymetais.github.io/code/key-signing/#scripting
|
||||||
|
echo "Please enter Yubikey PIN code "
|
||||||
|
stty -echo
|
||||||
|
trap 'stty echo' EXIT
|
||||||
|
read -p 'PIN: ' YUBI_PIN
|
||||||
|
stty echo
|
||||||
|
trap - EXIT
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Move everything
|
||||||
|
for platform in arm64-v8a armeabi-v7a x86_64; do
|
||||||
|
echo "Processing the $platform release..."
|
||||||
|
|
||||||
|
raw_apk="build/app/outputs/flutter-apk/app-${platform}-release.apk"
|
||||||
|
if [[ "$ALREADY_SIGNED" = "y" ]]; then
|
||||||
|
# Simply copy artifacts
|
||||||
|
cp -f "$raw_apk" "${release_dir}/${NAME}-${platform}-release.apk"
|
||||||
|
else
|
||||||
|
# https://developer.android.com/build/building-cmdline#sign_cmdline
|
||||||
|
aligned_apk="${release_dir}/app-${platform}-release-aligned.apk"
|
||||||
|
signed_apk="${release_dir}/app-${platform}-release.apk"
|
||||||
|
${ZIPALIGN} -p 4 "$raw_apk" "${aligned_apk}"
|
||||||
|
|
||||||
|
# NOTE: "-J-add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED" tells the wrapper that is
|
||||||
|
# `apksigner` to append "--add-exports jdk.[...]" as a parameter to the Java CLI. It is in
|
||||||
|
# quotation marks such that it is passed with only one (1) dash (it would otherwise be "--add-exports -jdk.[...]",
|
||||||
|
# which is wrong).
|
||||||
|
# At least on NixOS, apksigner refuses to use the sun.security.pkcs11.SunPKCS11 provider because
|
||||||
|
# it is not exported for its unnamed class. So, we have to do a little trickery to "export" the
|
||||||
|
# class to apksigner.
|
||||||
|
${APKSIGNER} "-J-add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED" sign \
|
||||||
|
--ks NONE \
|
||||||
|
--ks-pass "pass:$YUBI_PIN" \
|
||||||
|
--provider-class sun.security.pkcs11.SunPKCS11 \
|
||||||
|
--provider-arg "${PROVIDER_CONFIG}" \
|
||||||
|
--ks-type PKCS11 \
|
||||||
|
--min-sdk-version "${MIN_SDK_VERSION}" \
|
||||||
|
--max-sdk-version 34 \
|
||||||
|
--in "${aligned_apk}" \
|
||||||
|
--out "${signed_apk}" \
|
||||||
|
--v1-signing-enabled \
|
||||||
|
--v2-signing-enabled \
|
||||||
|
--v3-signing-enabled \
|
||||||
|
--v4-signing-enabled
|
||||||
|
|
||||||
|
# Safety check
|
||||||
|
${APKSIGNER} verify --min-sdk-version "${MIN_SDK_VERSION}" "${signed_apk}"
|
||||||
|
|
||||||
|
# Remove temporary artifact
|
||||||
|
rm "${aligned_apk}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Prevent leaking the PIN
|
||||||
|
unset YUBI_PIN
|
Loading…
Reference in New Issue
Block a user