Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
137 changes: 137 additions & 0 deletions .github/scripts/run-ios-simulator.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#!/usr/bin/env bash
# Boot an iOS simulator, install a built app bundle, and launch it.
# This script is intended for macOS GitHub Actions runners.
set -euo pipefail

function usage() {
cat <<'USAGE'
Usage: run-ios-simulator.sh [--help]

Environment variables:
APP_BUNDLE Path to the .app bundle to install (required).
BUNDLE_ID Bundle identifier used to launch the app (required).
SIM_DEVICE_NAME Simulator name to create/use. Default: iPhone 15
SIM_RUNTIME Simulator runtime identifier. Default: iOS (auto-detect latest)
SIM_TIMEOUT Seconds to wait for boot and launch. Default: 180

The script will create the simulator if missing, boot it headlessly,
install APP_BUNDLE, and launch BUNDLE_ID while streaming device logs.
USAGE
}

if [[ ${1:-} == "--help" || ${1:-} == "-h" ]]; then
usage
exit 0
fi

if [[ -z ${APP_BUNDLE:-} || -z ${BUNDLE_ID:-} ]]; then
echo "APP_BUNDLE and BUNDLE_ID must be set" >&2
exit 1
fi

SIM_DEVICE_NAME=${SIM_DEVICE_NAME:-"iPhone 15"}
SIM_RUNTIME=${SIM_RUNTIME:-"iOS"}
SIM_TIMEOUT=${SIM_TIMEOUT:-180}

function info() {
echo "[ios-sim] $*" >&2
}

function ensure_device() {
# Try to find the exact runtime first, or fallback to the latest available iOS runtime
# We extract the last column which is the runtime identifier
local runtime_id
runtime_id=$(xcrun simctl list runtimes | awk -v r="$SIM_RUNTIME" '/com.apple.CoreSimulator.SimRuntime/ && $0 ~ r {print $NF}' | sort | tail -n 1)

if [[ -z $runtime_id && "$SIM_RUNTIME" == "iOS" ]]; then
runtime_id=$(xcrun simctl list runtimes | awk '/com.apple.CoreSimulator.SimRuntime.iOS/ {print $NF}' | sort | tail -n 1)
fi

if [[ -z $runtime_id ]]; then
echo "Simulator runtime matching '$SIM_RUNTIME' not found" >&2
echo "Available runtimes:" >&2
xcrun simctl list runtimes >&2
exit 1
fi

info "Selected runtime: $runtime_id"

local existing
# Safely extract UDID using grep and delimiter-based awk to avoid regex issues with parenthesis
existing=$(xcrun simctl list devices "$runtime_id" | grep -F "$SIM_DEVICE_NAME (" | head -n 1 | awk -F '[()]' '{print $2}')

if [[ -n $existing ]]; then
echo "$existing"
return
fi

# Create device
local device_type="com.apple.CoreSimulator.SimDeviceType.iPhone-15"
local udid
udid=$(xcrun simctl create "$SIM_DEVICE_NAME" "$device_type" "$runtime_id")
echo "$udid"
}

function boot_device() {
local udid=$1
info "Booting simulator $SIM_DEVICE_NAME ($udid)"
xcrun simctl boot "$udid" >/dev/null 2>&1 || true

# Wait for boot completion manually since --timeout might be unsupported on some versions
info "Waiting for boot status..."
local attempts=0
local booted="false"
while [[ "$booted" == "false" ]]; do
local state
state=$(xcrun simctl list devices | grep "$udid" | grep "(Booted)" || true)
if [[ -n "$state" ]]; then
booted="true"
else
sleep 5
((attempts+=5))
if (( attempts > SIM_TIMEOUT )); then
echo "Timeout waiting for simulator boot" >&2
exit 1
fi
fi
done
info "Simulator booted"
}

function install_and_launch() {
local udid=$1

# Check if APP_BUNDLE exists
if [[ ! -e "$APP_BUNDLE" ]]; then
echo "Error: APP_BUNDLE not found at $APP_BUNDLE" >&2
echo "Listing contents of target directory:" >&2
# Assume APP_BUNDLE is something like BTDemo/target/ios-sim/BTDemo.app
# Try to list the parent directory to see what's there
local parent_dir
parent_dir=$(dirname "$APP_BUNDLE")
if [[ -d "$parent_dir" ]]; then
ls -F "$parent_dir" >&2
elif [[ -d "$(dirname "$parent_dir")" ]]; then
echo "Parent $parent_dir not found, listing grandparent:" >&2
ls -F "$(dirname "$parent_dir")" >&2
else
echo "Grandparent directory not found either." >&2
find . -maxdepth 4 -name "*.app" >&2
fi
exit 1
fi

info "Installing $APP_BUNDLE"
xcrun simctl install "$udid" "$APP_BUNDLE"
info "Launching $BUNDLE_ID"
# Stream logs in the background to aid debugging
xcrun simctl spawn "$udid" log stream --style compact --predicate "processImagePath CONTAINS '$BUNDLE_ID'" >"/tmp/ios-sim-${udid}.log" 2>&1 &
xcrun simctl launch "$udid" "$BUNDLE_ID"
info "Recent simulator logs:"
tail -n 50 "/tmp/ios-sim-${udid}.log" || true
}

udid=$(ensure_device)
boot_device "$udid"
install_and_launch "$udid"
info "Simulator run complete"
135 changes: 132 additions & 3 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ on:

jobs:
build:

runs-on: ubuntu-latest

timeout-minutes: 15
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
Expand All @@ -23,4 +22,134 @@ jobs:
mkdir -p ~/.codenameone
wget https://github.com/codenameone/CodenameOne/raw/refs/heads/master/maven/CodeNameOneBuildClient.jar -O ~/.codenameone/CodeNameOneBuildClient.jar
- name: Build with Maven
run: mvn install
run: cd cn1-bluetooth && mvn install -DskipTests && cd ..

android:
runs-on: ubuntu-22.04
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Install Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- name: Set JAVA17_HOME
run: echo "JAVA17_HOME=$JAVA_HOME" >> $GITHUB_ENV
- name: Install Java 11
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '11'
- name: Setup Codename One Build Client
run: |
mkdir -p ~/.codenameone
wget https://github.com/codenameone/CodenameOne/raw/refs/heads/master/maven/CodeNameOneBuildClient.jar -O ~/.codenameone/CodeNameOneBuildClient.jar
- name: Install Libraries (JDK 11)
run: cd cn1-bluetooth && mvn install -DskipTests && cd ..
- name: Enable KVM for Android emulator
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Install Framebuffer
run: sudo apt-get update && sudo apt-get install xvfb
- name: Build BTDemo Source (JDK 11)
env:
APP_DIR: BTDemo
run: |
cd BTDemo
xvfb-run -a ./mvnw install
xvfb-run -a ./mvnw cn1:build -e -Dcodename1.platform=android -Dcodename1.buildTarget=android-source
cd ..
- name: Compile APK (Gradle)
env:
JAVA_HOME: ${{ env.JAVA17_HOME }}
run: |
# Locate the Gradle project root
GRADLE_ROOT=$(find BTDemo/android/target -name "gradlew" -type f -exec dirname {} \; | head -n 1)

if [[ -z "$GRADLE_ROOT" ]]; then
echo "Error: Gradle project not found in BTDemo/android/target"
echo "Listing directories recursively:"
ls -R .
exit 1
fi

echo "Found Gradle project at: $GRADLE_ROOT"
cd "$GRADLE_ROOT"
chmod +x gradlew
./gradlew assembleDebug

# Move artifact to a predictable location
mkdir -p ../../../../build/android
find . -name "*.apk" -exec cp {} ../../../../build/android/app-debug.apk \;

- name: Run Android Emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 31
arch: x86_64
target: google_apis
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: |
adb install -r build/android/app-debug.apk
adb shell am start -n com.codename1.btle/.BTDemoStub
adb logcat -d | tail -n 200

ios:
runs-on: macos-15
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Install Java 11
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '11'
- name: Setup Codename One Build Client
run: |
mkdir -p ~/.codenameone
wget https://github.com/codenameone/CodenameOne/raw/refs/heads/master/maven/CodeNameOneBuildClient.jar -O ~/.codenameone/CodeNameOneBuildClient.jar
- name: Install Libraries (JDK 11)
run: cd cn1-bluetooth && mvn install -DskipTests && cd ..
- name: Build BTDemo Source (Maven)
env:
APP_DIR: BTDemo
BUILD_TARGET: ios-source
run: |
cd BTDemo
./mvnw install
./mvnw cn1:build -Dcodename1.platform=ios -Dcodename1.buildTarget=ios-source
cd ..
- name: Compile iOS App (Xcode)
run: |
# Find the generated Xcode project
XCODE_PROJ=$(find BTDemo/ios/target -name "*.xcodeproj" -type d | head -n 1)

if [[ -z "$XCODE_PROJ" ]]; then
echo "Error: Xcode project not found in BTDemo/target"
echo "Listing BTDemo/ios/target recursively:"
ls -R BTDemo/ios/target
exit 1
fi

echo "Found Xcode project: $XCODE_PROJ"

# Build the app for the simulator
xcodebuild -project "$XCODE_PROJ" \
-scheme "BTDemo" \
-configuration Debug \
-sdk iphonesimulator \
-destination "generic/platform=iOS Simulator" \
CONFIGURATION_BUILD_DIR=build/ios-sim \
clean build

- name: Boot simulator, install, and launch
env:
APP_BUNDLE: build/ios-sim/BTDemo.app
BUNDLE_ID: com.codename1.btle
run: |
.github/scripts/run-ios-simulator.sh
Empty file added BTDemo/.mvn/jvm.config
Empty file.
Loading
Loading