Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
21e6d25
Add Android app build to pipeline
shai-almog Sep 27, 2025
2b938b7
Improve workspace detection in Android app build script
shai-almog Sep 27, 2025
85a0173
Disable CSS generation in Android sample build
shai-almog Sep 27, 2025
a32b4cb
Re-enable CSS compilation in Android app build script
shai-almog Sep 29, 2025
b131270
Wrap archetype generation in xvfb
shai-almog Sep 29, 2025
1713e05
Fix workspace detection in Android app build script
shai-almog Sep 29, 2025
d0acdc1
Improve workspace tool logging in Android app build script
shai-almog Sep 29, 2025
f6d7996
Add workspace environment logging to android scripts
shai-almog Sep 29, 2025
75fd2f9
Harden workspace provisioning checks
shai-almog Sep 29, 2025
855fe0e
Improve workspace validation in Android port build
shai-almog Sep 29, 2025
710109e
Wrap Android port Maven builds with xvfb-run
shai-almog Sep 29, 2025
92add8e
Fix Java version detection patterns
shai-almog Sep 29, 2025
7552c08
Preload archetype plugin for Android app build
shai-almog Sep 29, 2025
d5ee06b
Preload archetype plugin in Android sample build
shai-almog Sep 29, 2025
b35b6c2
Use Codename One plugin to scaffold Android sample
shai-almog Sep 30, 2025
a93611e
Align archetype workspace version with local snapshot
shai-almog Sep 30, 2025
4c3680c
Default generate-app-project to local archetype catalog
shai-almog Sep 30, 2025
31d48ae
Adjust Android sample build to bootstrap from released plugin
shai-almog Sep 30, 2025
04422d6
Use local snapshot plugin for Android sample generation
shai-almog Sep 30, 2025
3722629
Bootstrap archetype generation from released version
shai-almog Sep 30, 2025
0571a80
Fix generate-app-project batch invocation for older Maven Invoker
shai-almog Sep 30, 2025
c8c3c42
Handle SampleMain.java when generating Android app
shai-almog Sep 30, 2025
09ec1ae
Use local Codename One version in sample build
shai-almog Sep 30, 2025
9952885
Remove offline Maven invocations from Android sample build
shai-almog Sep 30, 2025
51662ac
Rename Java 17 home variable to JAVA17_HOME
shai-almog Oct 1, 2025
6d7a4f1
Auto-provision workspace for Android app sample
shai-almog Oct 1, 2025
ef109fb
Revert "Auto-provision workspace for Android app sample"
shai-almog Oct 1, 2025
11a2d27
Trying to fix some of the codex mess
shai-almog Oct 1, 2025
a14f765
Added debugging information
shai-almog Oct 1, 2025
eac6995
Damn
shai-almog Oct 1, 2025
eeddd67
Fixed paths
shai-almog Oct 1, 2025
caad568
Reduced changes
shai-almog Oct 1, 2025
6e790e3
Moved out the java source file, restored CSS and removed python
shai-almog Oct 1, 2025
a85d66b
Testing CI works correctly
shai-almog Oct 1, 2025
649b679
Tuned iOS CI and added android build debug info
shai-almog Oct 1, 2025
8919eff
Reverted checks
shai-almog Oct 1, 2025
26a49aa
Fixing replace logic for pom files
shai-almog Oct 4, 2025
a1f464f
Another attempt at fixing versioning
shai-almog Oct 4, 2025
9235412
Added debugging printout
shai-almog Oct 4, 2025
7c34987
Another attempt at fixing the version
shai-almog Oct 4, 2025
6db52e7
Another attempt
shai-almog Oct 4, 2025
8f79013
Again
shai-almog Oct 4, 2025
f8d1467
Yet another attempt
shai-almog Oct 4, 2025
960de6a
Debugging code
shai-almog Oct 4, 2025
3adb8f7
Ugh
shai-almog Oct 4, 2025
ff8a463
Reverted code changes and made iOS CI timeout lenient
shai-almog Oct 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/scripts-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ jobs:
run: ./scripts/setup-workspace.sh -q -DskipTests
- name: Build Android port
run: ./scripts/build-android-port.sh -q -DskipTests
- name: Build Hello Codename One Android app
run: ./scripts/build-android-app.sh -q -DskipTests
18 changes: 13 additions & 5 deletions .github/workflows/scripts-ios.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
---
name: Test iOS build scripts

'on':
on:
pull_request:
paths:
- 'scripts/**'
- 'BUILDING.md'
push:
branches:
- master
branches: [ master ]
paths-ignore:
- '**/*.md'

jobs:
build-ios:
runs-on: macos-latest
runs-on: macos-15 # pinning macos-15 avoids surprises during the cutover window
timeout-minutes: 25 # hard-stop the job after 25 minutes
concurrency: # ensure only one mac build runs at once
group: mac-ci
cancel-in-progress: false # queue new ones instead of canceling in-flight

steps:
- uses: actions/checkout@v4

- name: Setup workspace
run: ./scripts/setup-workspace.sh -q -DskipTests
# per-step timeout
timeout-minutes: 15

- name: Build iOS port
run: ./scripts/build-ios-port.sh -q -DskipTests
timeout-minutes: 15
4 changes: 2 additions & 2 deletions BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export JAVA_HOME=$PWD/jdk-8.0.28+6
# JDK 17 (Linux x64; adjust `_x64_linux_` for your platform)
curl -L -o temurin17.tar.gz https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.16%2B8/OpenJDK17U-jdk_x64_linux_hotspot_17.0.16_8.tar.gz
tar xf temurin17.tar.gz
export JAVA_HOME_17=$PWD/jdk-17.0.16+8
export JAVA17_HOME=$PWD/jdk-17.0.16+8

export PATH="$JAVA_HOME/bin:$PATH"
```
Expand Down Expand Up @@ -54,7 +54,7 @@ Note that it's important that `$CN1_BINARIES` points at the locally cloned [cn1-

## Building the Android port

The Android port uses JDK 8 as well. However, it needs a `JAVA_HOME_17` environment variable that points at JDK 17.
The Android port uses JDK 8 as well. However, it needs a `JAVA17_HOME` environment variable that points at JDK 17.

```bash
./scripts/build-android-port.sh -DskipTests
Expand Down
2 changes: 1 addition & 1 deletion CodenameOne/src/com/codename1/ui/Form.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public class Form extends Container {
public Form() {
this(new FlowLayout());
}

/**
* Constructor that accepts a layout
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ private void generateProject() throws MojoExecutionException{

request.setGoals( Collections.singletonList( "archetype:generate" ) );

request.setBatchMode(true);

String[] propsArr = {
"interactiveMode=false",
"archetypeArtifactId=cn1app-archetype",
Expand Down
285 changes: 285 additions & 0 deletions scripts/build-android-app.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
#!/usr/bin/env bash
# Build a sample "Hello Codename One" Android application using the locally-built Codename One Android port
set -euo pipefail

ba_log() { echo "[build-android-app] $1"; }

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$REPO_ROOT"

TMPDIR="${TMPDIR:-/tmp}"; TMPDIR="${TMPDIR%/}"
DOWNLOAD_DIR="${TMPDIR%/}/codenameone-tools"
ENV_DIR="$DOWNLOAD_DIR/tools"
EXTRA_MVN_ARGS=("$@")

ENV_FILE="$ENV_DIR/env.sh"
ba_log "Loading workspace environment from $ENV_FILE"
if [ -f "$ENV_FILE" ]; then
ba_log "Workspace environment file metadata"
ls -l "$ENV_FILE" | while IFS= read -r line; do ba_log "$line"; done
ba_log "Workspace environment file contents"
sed 's/^/[build-android-app] ENV: /' "$ENV_FILE"
# shellcheck disable=SC1090
source "$ENV_FILE"
ba_log "Loaded environment: JAVA_HOME=${JAVA_HOME:-<unset>} JAVA17_HOME=${JAVA17_HOME:-<unset>} MAVEN_HOME=${MAVEN_HOME:-<unset>}"
else
ba_log "Workspace tools not found. Run scripts/setup-workspace.sh before this script." >&2
exit 1
fi

# --- Tool validations ---
if [ -z "${JAVA_HOME:-}" ] || [ ! -x "$JAVA_HOME/bin/java" ]; then
ba_log "JAVA_HOME validation failed. Current value: ${JAVA_HOME:-<unset>}" >&2
if [ -n "${JAVA_HOME:-}" ]; then
ba_log "Contents of JAVA_HOME directory"
if [ -d "$JAVA_HOME" ]; then ls -l "$JAVA_HOME" | while IFS= read -r line; do ba_log "$line"; done; else ba_log "JAVA_HOME directory does not exist"; fi
fi
ba_log "JAVA_HOME is not set correctly. Please run scripts/setup-workspace.sh first." >&2
exit 1
fi
if [ -z "${JAVA17_HOME:-}" ] || [ ! -x "$JAVA17_HOME/bin/java" ]; then
ba_log "JAVA17_HOME validation failed. Current value: ${JAVA17_HOME:-<unset>}" >&2
if [ -n "${JAVA17_HOME:-}" ]; then
ba_log "Contents of JAVA17_HOME directory"
if [ -d "$JAVA17_HOME" ]; then ls -l "$JAVA17_HOME" | while IFS= read -r line; do ba_log "$line"; done; else ba_log "JAVA17_HOME directory does not exist"; fi
fi
ba_log "JAVA17_HOME is not set correctly. Please run scripts/setup-workspace.sh first." >&2
exit 1
fi
if [ -z "${MAVEN_HOME:-}" ] || [ ! -x "$MAVEN_HOME/bin/mvn" ]; then
ba_log "MAVEN_HOME validation failed. Current value: ${MAVEN_HOME:-<unset>}" >&2
if [ -n "${MAVEN_HOME:-}" ]; then
ba_log "Contents of MAVEN_HOME directory"
if [ -d "$MAVEN_HOME" ]; then ls -l "$MAVEN_HOME" | while IFS= read -r line; do ba_log "$line"; done; else ba_log "MAVEN_HOME directory does not exist"; fi
fi
ba_log "Maven is not available. Please run scripts/setup-workspace.sh first." >&2
exit 1
fi

ba_log "Using JAVA_HOME at $JAVA_HOME"
ba_log "Using JAVA17_HOME at $JAVA17_HOME"
ba_log "Using Maven installation at $MAVEN_HOME"
export PATH="$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH"

ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}"
if [ -z "$ANDROID_SDK_ROOT" ]; then
if [ -d "/usr/local/lib/android/sdk" ]; then ANDROID_SDK_ROOT="/usr/local/lib/android/sdk"
elif [ -d "$HOME/Android/Sdk" ]; then ANDROID_SDK_ROOT="$HOME/Android/Sdk"; fi
fi
if [ -z "$ANDROID_SDK_ROOT" ] || [ ! -d "$ANDROID_SDK_ROOT" ]; then
ba_log "Android SDK not found. Set ANDROID_SDK_ROOT or ANDROID_HOME to a valid installation." >&2
exit 1
fi
export ANDROID_SDK_ROOT ANDROID_HOME="$ANDROID_SDK_ROOT"
ba_log "Using Android SDK at $ANDROID_SDK_ROOT"

CN1_VERSION=$(awk -F'[<>]' '/<version>/{print $3; exit}' maven/pom.xml)
ba_log "Detected Codename One version $CN1_VERSION"

WORK_DIR="$TMPDIR/cn1-hello-android"
rm -rf "$WORK_DIR"; mkdir -p "$WORK_DIR"

GROUP_ID="com.codenameone.examples"
ARTIFACT_ID="hello-codenameone"
MAIN_NAME="HelloCodenameOne"

SOURCE_PROJECT="$REPO_ROOT/Samples/SampleProjectTemplate"
if [ ! -d "$SOURCE_PROJECT" ]; then
ba_log "Source project template not found at $SOURCE_PROJECT" >&2
exit 1
fi
ba_log "Using source project template at $SOURCE_PROJECT"

LOCAL_MAVEN_REPO="${LOCAL_MAVEN_REPO:-$HOME/.m2/repository}"
ba_log "Using local Maven repository at $LOCAL_MAVEN_REPO"
mkdir -p "$LOCAL_MAVEN_REPO"
MAVEN_CMD=(
"$MAVEN_HOME/bin/mvn" -B -ntp
-Dmaven.repo.local="$LOCAL_MAVEN_REPO"
-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
)

# --- Generate app skeleton ---
ba_log "Generating Codename One application skeleton via codenameone-maven-plugin"
(
cd "$WORK_DIR"
xvfb-run -a "${MAVEN_CMD[@]}" -q \
com.codenameone:codenameone-maven-plugin:7.0.204:generate-app-project \
-DgroupId="$GROUP_ID" \
-DartifactId="$ARTIFACT_ID" \
-Dversion=1.0-SNAPSHOT \
-DsourceProject="$SOURCE_PROJECT" \
-Dcn1Version="7.0.204" \
"${EXTRA_MVN_ARGS[@]}"
)

APP_DIR="$WORK_DIR/$ARTIFACT_ID"

# --- Namespace-aware CN1 normalization (xmlstarlet) ---
ROOT_POM="$APP_DIR/pom.xml"
NS="mvn=http://maven.apache.org/POM/4.0.0"

if ! command -v xmlstarlet >/dev/null 2>&1; then
sudo apt-get update -y && sudo apt-get install -y xmlstarlet
fi

# Helper to run xmlstarlet with Maven namespace
x() { xmlstarlet ed -L -N "$NS" "$@"; }
q() { xmlstarlet sel -N "$NS" "$@"; }

# 1) Ensure <properties><codenameone.version> exists/updated (root pom)
if [ "$(q -t -v 'count(/mvn:project/mvn:properties)' "$ROOT_POM" 2>/dev/null || echo 0)" = "0" ]; then
x -s "/mvn:project" -t elem -n properties -v "" "$ROOT_POM"
fi
if [ "$(q -t -v 'count(/mvn:project/mvn:properties/mvn:codenameone.version)' "$ROOT_POM" 2>/dev/null || echo 0)" = "0" ]; then
x -s "/mvn:project/mvn:properties" -t elem -n codenameone.version -v "$CN1_VERSION" "$ROOT_POM"
else
x -u "/mvn:project/mvn:properties/mvn:codenameone.version" -v "$CN1_VERSION" "$ROOT_POM"
fi

# 2) Parent must be a LITERAL version (no property allowed)
while IFS= read -r -d '' P; do
x -u "/mvn:project[mvn:parent/mvn:groupId='com.codenameone' and mvn:parent/mvn:artifactId='codenameone-maven-parent']/mvn:parent/mvn:version" -v "$CN1_VERSION" "$P" || true
done < <(find "$APP_DIR" -type f -name pom.xml -print0)

# 3) Point com.codenameone deps/plugins to ${codenameone.version}
while IFS= read -r -d '' P; do
# Dependencies
x -u "/mvn:project//mvn:dependencies/mvn:dependency[starts-with(mvn:groupId,'com.codenameone')]/mvn:version" -v '${codenameone.version}' "$P" 2>/dev/null || true
# Plugins (regular)
x -u "/mvn:project//mvn:build/mvn:plugins/mvn:plugin[starts-with(mvn:groupId,'com.codenameone')]/mvn:version" -v '${codenameone.version}' "$P" 2>/dev/null || true
# Plugins (pluginManagement)
x -u "/mvn:project//mvn:build/mvn:pluginManagement/mvn:plugins/mvn:plugin[starts-with(mvn:groupId,'com.codenameone')]/mvn:version" -v '${codenameone.version}' "$P" 2>/dev/null || true
done < <(find "$APP_DIR" -type f -name pom.xml -print0)

# 4) Ensure common Maven plugins have a version (Maven requires it even if parent not yet resolved)
declare -A PIN=(
[org.apache.maven.plugins:maven-compiler-plugin]=3.11.0
[org.apache.maven.plugins:maven-resources-plugin]=3.3.1
[org.apache.maven.plugins:maven-surefire-plugin]=3.2.5
[org.apache.maven.plugins:maven-failsafe-plugin]=3.2.5
[org.apache.maven.plugins:maven-jar-plugin]=3.3.0
[org.apache.maven.plugins:maven-clean-plugin]=3.3.2
[org.apache.maven.plugins:maven-deploy-plugin]=3.1.2
[org.apache.maven.plugins:maven-install-plugin]=3.1.2
[org.apache.maven.plugins:maven-assembly-plugin]=3.6.0
[org.apache.maven.plugins:maven-site-plugin]=4.0.0-M15
[com.codenameone:codenameone-maven-plugin]='${codenameone.version}'
)

add_version_if_missing() {
local pom="$1" g="$2" a="$3" v="$4"
# build/plugins
if [ "$(q -t -v "count(/mvn:project/mvn:build/mvn:plugins/mvn:plugin[mvn:groupId='$g' and mvn:artifactId='$a']/mvn:version)" "$pom" 2>/dev/null || echo 0)" = "0" ] &&
[ "$(q -t -v "count(/mvn:project/mvn:build/mvn:plugins/mvn:plugin[mvn:groupId='$g' and mvn:artifactId='$a'])" "$pom" 2>/dev/null || echo 0)" != "0" ]; then
x -s "/mvn:project/mvn:build/mvn:plugins/mvn:plugin[mvn:groupId='$g' and mvn:artifactId='$a']" -t elem -n version -v "$v" "$pom" || true
fi
# pluginManagement/plugins
if [ "$(q -t -v "count(/mvn:project/mvn:build/mvn:pluginManagement/mvn:plugins/mvn:plugin[mvn:groupId='$g' and mvn:artifactId='$a']/mvn:version)" "$pom" 2>/dev/null || echo 0)" = "0" ] &&
[ "$(q -t -v "count(/mvn:project/mvn:build/mvn:pluginManagement/mvn:plugins/mvn:plugin[mvn:groupId='$g' and mvn:artifactId='$a'])" "$pom" 2>/dev/null || echo 0)" != "0" ]; then
x -s "/mvn:project/mvn:build/mvn:pluginManagement/mvn:plugins/mvn:plugin[mvn:groupId='$g' and mvn:artifactId='$a']" -t elem -n version -v "$v" "$pom" || true
fi
}

while IFS= read -r -d '' P; do
for ga in "${!PIN[@]}"; do
add_version_if_missing "$P" "${ga%%:*}" "${ga##*:}" "${PIN[$ga]}"
done
done < <(find "$APP_DIR" -type f -name pom.xml -print0)

# 5) Build with the property set so any lingering refs resolve to the local snapshot
EXTRA_MVN_ARGS+=("-Dcodenameone.version=${CN1_VERSION}")

# (Optional) quick non-fatal checks
xmlstarlet sel -N "$NS" -t -v "/mvn:project/mvn:properties/mvn:codenameone.version" -n "$ROOT_POM" || true
xmlstarlet sel -N "$NS" -t -c "/mvn:project/mvn:build/mvn:plugins" -n "$ROOT_POM" | head -n 60 || true



[ -d "$APP_DIR" ] || { ba_log "Failed to create Codename One application project" >&2; exit 1; }
[ -f "$APP_DIR/build.sh" ] && chmod +x "$APP_DIR/build.sh"

SETTINGS_FILE="$APP_DIR/common/codenameone_settings.properties"
[ -f "$SETTINGS_FILE" ] || { ba_log "codenameone_settings.properties not found at $SETTINGS_FILE" >&2; exit 1; }

# --- Read settings ---
read_prop() { grep -E "^$1=" "$SETTINGS_FILE" | head -n1 | cut -d'=' -f2- | sed 's/^[[:space:]]*//'; }

PACKAGE_NAME="$(read_prop 'codename1.packageName' || true)"
CURRENT_MAIN_NAME="$(read_prop 'codename1.mainName' || true)"

if [ -z "$PACKAGE_NAME" ]; then
PACKAGE_NAME="$GROUP_ID"
ba_log "Package name not found in settings. Falling back to groupId $PACKAGE_NAME"
fi
if [ -z "$CURRENT_MAIN_NAME" ]; then
CURRENT_MAIN_NAME="$MAIN_NAME"
ba_log "Main class name not found in settings. Falling back to target $CURRENT_MAIN_NAME"
fi

# --- Generate Java from external template ---
PACKAGE_PATH="${PACKAGE_NAME//.//}"
JAVA_DIR="$APP_DIR/common/src/main/java/${PACKAGE_PATH}"
mkdir -p "$JAVA_DIR"
MAIN_FILE="$JAVA_DIR/${MAIN_NAME}.java"

TEMPLATE="$SCRIPT_DIR/templates/HelloCodenameOne.java.tmpl"
if [ ! -f "$TEMPLATE" ]; then
ba_log "Template not found: $TEMPLATE" >&2
exit 1
fi

sed -e "s|@PACKAGE@|$PACKAGE_NAME|g" \
-e "s|@MAIN_NAME@|$MAIN_NAME|g" \
"$TEMPLATE" > "$MAIN_FILE"

# --- Ensure codename1.mainName is set ---
ba_log "Setting codename1.mainName to $MAIN_NAME"
if grep -q '^codename1.mainName=' "$SETTINGS_FILE"; then
# GNU sed in CI: in-place edit without backup
sed -E -i 's|^codename1\.mainName=.*$|codename1.mainName='"$MAIN_NAME"'|' "$SETTINGS_FILE"
else
printf '\ncodename1.mainName=%s\n' "$MAIN_NAME" >> "$SETTINGS_FILE"
fi
# Ensure trailing newline
tail -c1 "$SETTINGS_FILE" | read -r _ || echo >> "$SETTINGS_FILE"

# --- Normalize Codename One versions (use Maven Versions Plugin) ---
ba_log "Normalizing Codename One Maven coordinates to $CN1_VERSION"

# --- Build Android gradle project ---
ba_log "Building Android gradle project using Codename One port"
xvfb-run -a "${MAVEN_CMD[@]}" -q -f "$APP_DIR/pom.xml" package \
-DskipTests \
-Dcodename1.platform=android \
-Dcodename1.buildTarget=android-source \
-Dopen=false \
"${EXTRA_MVN_ARGS[@]}"

GRADLE_PROJECT_DIR=$(find "$APP_DIR/android/target" -maxdepth 2 -type d -name "*-android-source" | head -n 1 || true)
if [ -z "$GRADLE_PROJECT_DIR" ]; then
ba_log "Failed to locate generated Android project" >&2
ba_log "Contents of $APP_DIR/android/target:" >&2
ls -R "$APP_DIR/android/target" >&2 || ba_log "Unable to list $APP_DIR/android/target" >&2
exit 1
fi

ba_log "Invoking Gradle build in $GRADLE_PROJECT_DIR"
chmod +x "$GRADLE_PROJECT_DIR/gradlew"
ORIGINAL_JAVA_HOME="$JAVA_HOME"
export JAVA_HOME="$JAVA17_HOME"
(
cd "$GRADLE_PROJECT_DIR"
if command -v sdkmanager >/dev/null 2>&1; then
yes | sdkmanager --licenses >/dev/null 2>&1 || true
elif [ -x "$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" ]; then
yes | "$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" --licenses >/dev/null 2>&1 || true
fi
./gradlew --no-daemon assembleDebug
)
export JAVA_HOME="$ORIGINAL_JAVA_HOME"

APK_PATH=$(find "$GRADLE_PROJECT_DIR" -path "*/outputs/apk/debug/*.apk" | head -n 1 || true)
[ -n "$APK_PATH" ] || { ba_log "Gradle build completed but no APK was found" >&2; exit 1; }
ba_log "Successfully built Android APK at $APK_PATH"
Loading