From b9b0d7f447c2b6e8d7cfa12629428005153a1467 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 17:25:18 -0400 Subject: [PATCH 01/20] Build examples in CI --- .github/workflows/ci.yml | 181 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0344ad8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,181 @@ +name: ci + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + build: + name: Build (swift:${{ matrix.swift_version }}) + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + swift_version: ['nightly-main', 'nightly-6.3', '6.3'] + sdk_triple: ['aarch64-unknown-linux-android28'] + ndk_version: ['r27d'] + env: + SDK_TRIPLE: ${{ matrix.sdk_triple }} + NDK_VERSION: ${{ matrix.ndk_version }} + SWIFT_VERSION: ${{ matrix.swift_version }} + steps: + - uses: actions/checkout@v6 + + - name: Set up JDK 25 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '25' + + - name: Install Swift toolchain and Android Swift SDK + # Mirrors the build-swift-android job from + # https://github.com/swiftlang/swift-java/blob/main/.github/workflows/pull_request.yml + # but uses ":" as a no-op build command because we want only the + # toolchain + Android Swift SDK installed, not a Swift package built. + run: | + set -euxo pipefail + sudo apt-get -q update + sudo apt-get -yq install curl jq gpg unzip + curl -L -O --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/install-and-build-with-sdk.sh + perl -pi -e "s#(download_and_extract_toolchain \".ANDROID_SDK_TAG\"\))#\1\n PATH=\\\$(dirname \\\$SWIFT_EXECUTABLE_FOR_ANDROID_SDK):\\\$PATH\n echo \"path is now \\\$PATH\"#" install-and-build-with-sdk.sh + chmod 500 install-and-build-with-sdk.sh + ./install-and-build-with-sdk.sh \ + --android \ + --build-command=":" \ + --android-sdk-triple="${SDK_TRIPLE}" \ + --android-ndk-version="${NDK_VERSION}" \ + "${SWIFT_VERSION}" + + - name: Locate installed Swift toolchain + run: | + set -euo pipefail + SWIFT_BIN=$(find "$HOME/.swift-toolchains" -type f -name swift -path '*/usr/bin/swift' | head -n1) + if [ -z "$SWIFT_BIN" ]; then + echo "Error: could not find swift binary under $HOME/.swift-toolchains" >&2 + exit 1 + fi + echo "Found Swift binary: $SWIFT_BIN" + "$SWIFT_BIN" --version + echo "SWIFT_BIN=$SWIFT_BIN" >> "$GITHUB_ENV" + dirname "$SWIFT_BIN" >> "$GITHUB_PATH" + + - name: Create swiftly shim + # The example projects' Gradle scripts invoke Swift via swiftly + # (e.g. `swiftly run +6.3 swift build ...`). Install a tiny shim that + # strips the swiftly-specific arguments and forwards to the swift + # binary that the install script downloaded. + run: | + set -euo pipefail + mkdir -p "$HOME/.swiftly/bin" + cat > "$HOME/.swiftly/bin/swiftly" <<'SHIM' + #!/usr/bin/env bash + set -e + if [ -z "${SWIFT_BIN:-}" ]; then + echo "swiftly shim: SWIFT_BIN is not set" >&2 + exit 1 + fi + # Drop a leading "run" subcommand + if [ "${1:-}" = "run" ]; then shift; fi + # Drop any "+" tokens + new_args=() + for arg in "$@"; do + case "$arg" in + +*) ;; + *) new_args+=("$arg") ;; + esac + done + # Drop a leading "swift" since we're calling the swift binary directly + if [ "${#new_args[@]}" -gt 0 ] && [ "${new_args[0]}" = "swift" ]; then + new_args=("${new_args[@]:1}") + fi + exec "$SWIFT_BIN" "${new_args[@]}" + SHIM + chmod +x "$HOME/.swiftly/bin/swiftly" + echo "SWIFTLY_PATH=$HOME/.swiftly/bin/swiftly" >> "$GITHUB_ENV" + + - name: Locate Swift Android SDK + # The per-library build.gradle scripts (hashing-lib, weather-lib, + # hello-cpp-swift/swift-lib) and swift-android.gradle.kts hardcode the + # artifactbundle directory name to "swift-6.3-RELEASE_android.artifactbundle". + # When we install a different snapshot, expose the actual bundle under + # that name via a symlink so the Gradle scripts can locate the runtime libs. + run: | + set -euo pipefail + SDK_BUNDLE="" + for d in "$HOME/.swiftpm/swift-sdks" "$HOME/.config/swiftpm/swift-sdks" "$HOME/Library/org.swift.swiftpm/swift-sdks"; do + if [ -d "$d" ]; then + found=$(find "$d" -maxdepth 1 -type d -name '*_android*.artifactbundle' | head -n1) + if [ -n "$found" ]; then + SDK_BUNDLE="$found" + break + fi + fi + done + if [ -z "$SDK_BUNDLE" ]; then + echo "Error: Android Swift SDK artifactbundle was not found" >&2 + find "$HOME/.swiftpm" "$HOME/.config/swiftpm" 2>/dev/null || true + exit 1 + fi + echo "Found Android SDK bundle: $SDK_BUNDLE" + SDK_DIR=$(dirname "$SDK_BUNDLE") + EXPECTED="$SDK_DIR/swift-6.3-RELEASE_android.artifactbundle" + if [ ! -e "$EXPECTED" ]; then + ln -s "$SDK_BUNDLE" "$EXPECTED" + echo "Symlinked $EXPECTED -> $SDK_BUNDLE" + fi + echo "SWIFT_SDK_PATH=$SDK_DIR" >> "$GITHUB_ENV" + + - name: Publish swift-java packages to local Maven + # The hashing-lib, weather-lib, and hello-cpp-swift/swift-lib modules + # depend on org.swift.swiftkit:swiftkit-core:1.0-SNAPSHOT, which is not + # published to a public Maven repo. The hashing-lib README documents + # publishing it to mavenLocal from the swift-java checkout that + # SwiftPM resolves into .build/checkouts/swift-java. + working-directory: hello-swift-java/hashing-lib + run: | + set -euxo pipefail + "$SWIFT_BIN" package resolve + ./.build/checkouts/swift-java/gradlew \ + --project-dir .build/checkouts/swift-java \ + :SwiftKitCore:publishToMavenLocal + continue-on-error: true + + - name: Build hello-swift-raw-jni APK + run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace + continue-on-error: true + + - name: Build hello-swift-raw-jni-callback APK + run: ./gradlew :hello-swift-raw-jni-callback:assembleDebug --stacktrace + continue-on-error: true + + - name: Build hello-swift-raw-jni-library + run: ./gradlew :hello-swift-raw-jni-library:assembleDebug --stacktrace + continue-on-error: true + + - name: Build native-activity APK + run: ./gradlew :native-activity:assembleDebug --stacktrace + continue-on-error: true + + - name: Build hello-swift-java APK + run: ./gradlew :hello-swift-java-hashing-app:assembleDebug --stacktrace + continue-on-error: true + + - name: Build swift-java-weather-app APK + run: ./gradlew :swift-java-weather-app-weather-app:assembleDebug --stacktrace + continue-on-error: true + + - name: Build hello-cpp-swift APK + run: ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace + continue-on-error: true + + - name: Upload APK artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: apks-${{ matrix.swift_version }} + path: '**/build/outputs/apk/**/*.apk' + if-no-files-found: warn From 41f902a64294463143de2423b8c130569a25a007 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 17:29:51 -0400 Subject: [PATCH 02/20] Update swift_version in matrix --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0344ad8..bc056bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - swift_version: ['nightly-main', 'nightly-6.3', '6.3'] + swift_version: ['nightly-main', 'nightly-6.3', '6.3.0'] sdk_triple: ['aarch64-unknown-linux-android28'] ndk_version: ['r27d'] env: From 040c718a04c598224e5e9c17f57568d0921747df Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 17:39:29 -0400 Subject: [PATCH 03/20] Install swiftly --- .github/workflows/ci.yml | 108 +++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc056bc..716100b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - swift_version: ['nightly-main', 'nightly-6.3', '6.3.0'] + swift_version: ['nightly-main', 'nightly-6.3', '6.3'] sdk_triple: ['aarch64-unknown-linux-android28'] ndk_version: ['r27d'] env: @@ -31,15 +31,62 @@ jobs: distribution: temurin java-version: '25' - - name: Install Swift toolchain and Android Swift SDK - # Mirrors the build-swift-android job from - # https://github.com/swiftlang/swift-java/blob/main/.github/workflows/pull_request.yml - # but uses ":" as a no-op build command because we want only the - # toolchain + Android Swift SDK installed, not a Swift package built. + - name: Install swiftly run: | set -euxo pipefail sudo apt-get -q update sudo apt-get -yq install curl jq gpg unzip + ARCH="$(uname -m)" + curl -L -O --retry 3 "https://download.swift.org/swiftly/linux/swiftly-${ARCH}.tar.gz" + tar -xzf "swiftly-${ARCH}.tar.gz" + ./swiftly init \ + --assume-yes \ + --skip-install \ + --no-modify-profile \ + --quiet-shell-followup + rm -f "swiftly-${ARCH}.tar.gz" swiftly + # The example projects' Gradle scripts look for swiftly under + # $HOME/.local/share/swiftly/bin, which is also where the official + # installer puts it. Add it to PATH for subsequent steps. + echo "$HOME/.local/share/swiftly/bin" >> "$GITHUB_PATH" + "$HOME/.local/share/swiftly/bin/swiftly" --version + + - name: Install Swift via swiftly + run: | + set -euxo pipefail + # Translate the matrix's swift_version into the form swiftly expects: + # nightly-main -> main-snapshot + # nightly-6.3 -> 6.3-snapshot + # 6.3 / 6.3.0 -> passed through as-is + case "$SWIFT_VERSION" in + nightly-main) SWIFTLY_VER="main-snapshot" ;; + nightly-*) SWIFTLY_VER="${SWIFT_VERSION#nightly-}-snapshot" ;; + *) SWIFTLY_VER="$SWIFT_VERSION" ;; + esac + POST_INSTALL_FILE="$(mktemp)" + swiftly install "$SWIFTLY_VER" \ + --use \ + --assume-yes \ + --post-install-file="$POST_INSTALL_FILE" + # Some toolchains print follow-up commands (e.g. apt-get install + # of missing system libs) to the post-install file. Run them if + # any were emitted. + if [ -s "$POST_INSTALL_FILE" ]; then + sudo bash "$POST_INSTALL_FILE" + fi + rm -f "$POST_INSTALL_FILE" + swift --version + + - name: Install Android Swift SDK and NDK + # Uses the build-swift-android mechanism from + # https://github.com/swiftlang/swift-java/blob/main/.github/workflows/pull_request.yml + # to install the Android Swift SDK and NDK and link them via the + # bundle's setup-android-sdk.sh script. The Swift toolchain itself + # was already installed in the previous step via swiftly. ":" is + # passed as a no-op build command because we don't want this script + # to also try to `swift build` anything. + run: | + set -euxo pipefail curl -L -O --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/install-and-build-with-sdk.sh perl -pi -e "s#(download_and_extract_toolchain \".ANDROID_SDK_TAG\"\))#\1\n PATH=\\\$(dirname \\\$SWIFT_EXECUTABLE_FOR_ANDROID_SDK):\\\$PATH\n echo \"path is now \\\$PATH\"#" install-and-build-with-sdk.sh chmod 500 install-and-build-with-sdk.sh @@ -50,53 +97,6 @@ jobs: --android-ndk-version="${NDK_VERSION}" \ "${SWIFT_VERSION}" - - name: Locate installed Swift toolchain - run: | - set -euo pipefail - SWIFT_BIN=$(find "$HOME/.swift-toolchains" -type f -name swift -path '*/usr/bin/swift' | head -n1) - if [ -z "$SWIFT_BIN" ]; then - echo "Error: could not find swift binary under $HOME/.swift-toolchains" >&2 - exit 1 - fi - echo "Found Swift binary: $SWIFT_BIN" - "$SWIFT_BIN" --version - echo "SWIFT_BIN=$SWIFT_BIN" >> "$GITHUB_ENV" - dirname "$SWIFT_BIN" >> "$GITHUB_PATH" - - - name: Create swiftly shim - # The example projects' Gradle scripts invoke Swift via swiftly - # (e.g. `swiftly run +6.3 swift build ...`). Install a tiny shim that - # strips the swiftly-specific arguments and forwards to the swift - # binary that the install script downloaded. - run: | - set -euo pipefail - mkdir -p "$HOME/.swiftly/bin" - cat > "$HOME/.swiftly/bin/swiftly" <<'SHIM' - #!/usr/bin/env bash - set -e - if [ -z "${SWIFT_BIN:-}" ]; then - echo "swiftly shim: SWIFT_BIN is not set" >&2 - exit 1 - fi - # Drop a leading "run" subcommand - if [ "${1:-}" = "run" ]; then shift; fi - # Drop any "+" tokens - new_args=() - for arg in "$@"; do - case "$arg" in - +*) ;; - *) new_args+=("$arg") ;; - esac - done - # Drop a leading "swift" since we're calling the swift binary directly - if [ "${#new_args[@]}" -gt 0 ] && [ "${new_args[0]}" = "swift" ]; then - new_args=("${new_args[@]:1}") - fi - exec "$SWIFT_BIN" "${new_args[@]}" - SHIM - chmod +x "$HOME/.swiftly/bin/swiftly" - echo "SWIFTLY_PATH=$HOME/.swiftly/bin/swiftly" >> "$GITHUB_ENV" - - name: Locate Swift Android SDK # The per-library build.gradle scripts (hashing-lib, weather-lib, # hello-cpp-swift/swift-lib) and swift-android.gradle.kts hardcode the @@ -138,7 +138,7 @@ jobs: working-directory: hello-swift-java/hashing-lib run: | set -euxo pipefail - "$SWIFT_BIN" package resolve + swift package resolve ./.build/checkouts/swift-java/gradlew \ --project-dir .build/checkouts/swift-java \ :SwiftKitCore:publishToMavenLocal From 0c20f0bb84361ca4e175d89c4c5b064a4bcf65d1 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 17:56:39 -0400 Subject: [PATCH 04/20] Update CI --- .github/workflows/ci.yml | 110 ++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 47 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 716100b..f415438 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,13 +11,14 @@ permissions: jobs: build: name: Build (swift:${{ matrix.swift_version }}) - runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: swift_version: ['nightly-main', 'nightly-6.3', '6.3'] sdk_triple: ['aarch64-unknown-linux-android28'] ndk_version: ['r27d'] + os: ['ubuntu-latest', 'macos-latest'] + runs-on: ${{ matrix.os }} env: SDK_TRIPLE: ${{ matrix.sdk_triple }} NDK_VERSION: ${{ matrix.ndk_version }} @@ -77,57 +78,72 @@ jobs: rm -f "$POST_INSTALL_FILE" swift --version - - name: Install Android Swift SDK and NDK - # Uses the build-swift-android mechanism from - # https://github.com/swiftlang/swift-java/blob/main/.github/workflows/pull_request.yml - # to install the Android Swift SDK and NDK and link them via the - # bundle's setup-android-sdk.sh script. The Swift toolchain itself - # was already installed in the previous step via swiftly. ":" is - # passed as a no-op build command because we don't want this script - # to also try to `swift build` anything. + - name: Install Android NDK run: | set -euxo pipefail - curl -L -O --retry 3 https://raw.githubusercontent.com/swiftlang/github-workflows/refs/heads/main/.github/workflows/scripts/install-and-build-with-sdk.sh - perl -pi -e "s#(download_and_extract_toolchain \".ANDROID_SDK_TAG\"\))#\1\n PATH=\\\$(dirname \\\$SWIFT_EXECUTABLE_FOR_ANDROID_SDK):\\\$PATH\n echo \"path is now \\\$PATH\"#" install-and-build-with-sdk.sh - chmod 500 install-and-build-with-sdk.sh - ./install-and-build-with-sdk.sh \ - --android \ - --build-command=":" \ - --android-sdk-triple="${SDK_TRIPLE}" \ - --android-ndk-version="${NDK_VERSION}" \ - "${SWIFT_VERSION}" - - - name: Locate Swift Android SDK - # The per-library build.gradle scripts (hashing-lib, weather-lib, - # hello-cpp-swift/swift-lib) and swift-android.gradle.kts hardcode the - # artifactbundle directory name to "swift-6.3-RELEASE_android.artifactbundle". - # When we install a different snapshot, expose the actual bundle under - # that name via a symlink so the Gradle scripts can locate the runtime libs. + curl -L -o ndk.zip --retry 3 "https://dl.google.com/android/repository/android-ndk-${NDK_VERSION}-linux.zip" + unzip -q ndk.zip -d "$HOME" + rm ndk.zip + echo "ANDROID_NDK_HOME=$HOME/android-ndk-${NDK_VERSION}" >> "$GITHUB_ENV" + + - name: Install Android Swift SDK + # Looks up the Android Swift SDK URL and checksum from the swift.org + # install API and installs it via `swift sdk install`. For releases + # we use https://www.swift.org/api/v1/install/releases.json (which + # gives us each platform's checksum, but not a download URL — we + # construct that from the version). For nightlies we query + # https://www.swift.org/api/v1/install/dev//android-sdk.json + # for the latest snapshot tag and checksum. run: | - set -euo pipefail - SDK_BUNDLE="" - for d in "$HOME/.swiftpm/swift-sdks" "$HOME/.config/swiftpm/swift-sdks" "$HOME/Library/org.swift.swiftpm/swift-sdks"; do - if [ -d "$d" ]; then - found=$(find "$d" -maxdepth 1 -type d -name '*_android*.artifactbundle' | head -n1) - if [ -n "$found" ]; then - SDK_BUNDLE="$found" - break + set -euxo pipefail + case "$SWIFT_VERSION" in + nightly-*) + nightly_version="${SWIFT_VERSION#nightly-}" + sdk_json=$(curl -fsSL "https://www.swift.org/api/v1/install/dev/${nightly_version}/android-sdk.json") + snapshot_tag=$(echo "$sdk_json" | jq -r '.[0].dir') + sdk_checksum=$(echo "$sdk_json" | jq -r '.[0].checksum') + if [ "$nightly_version" = "main" ]; then + branch="development" + else + branch="swift-${nightly_version}-branch" fi - fi - done - if [ -z "$SDK_BUNDLE" ]; then - echo "Error: Android Swift SDK artifactbundle was not found" >&2 - find "$HOME/.swiftpm" "$HOME/.config/swiftpm" 2>/dev/null || true - exit 1 - fi - echo "Found Android SDK bundle: $SDK_BUNDLE" - SDK_DIR=$(dirname "$SDK_BUNDLE") - EXPECTED="$SDK_DIR/swift-6.3-RELEASE_android.artifactbundle" - if [ ! -e "$EXPECTED" ]; then - ln -s "$SDK_BUNDLE" "$EXPECTED" - echo "Symlinked $EXPECTED -> $SDK_BUNDLE" + sdk_url="https://download.swift.org/${branch}/android-sdk/${snapshot_tag}/${snapshot_tag}_android.artifactbundle.tar.gz" + ;; + *) + releases_json=$(curl -fsSL "https://www.swift.org/api/v1/install/releases.json") + # Pick the highest patch release whose name starts with the + # requested version (e.g. "6.3" -> "6.3.1" if it exists). + latest_version=$(echo "$releases_json" | jq -r --arg v "$SWIFT_VERSION" \ + '[.[] | select(.name | startswith($v))] + | sort_by(.name | split(".") | map(tonumber? // 0)) + | last + | .name') + if [ -z "$latest_version" ] || [ "$latest_version" = "null" ]; then + echo "Error: no Swift release matching '$SWIFT_VERSION' found in releases.json" >&2 + exit 1 + fi + sdk_checksum=$(echo "$releases_json" | jq -r --arg v "$latest_version" \ + '.[] | select(.name == $v) | .platforms[] | select(.platform == "android") | .checksum') + snapshot_tag="swift-${latest_version}-RELEASE" + sdk_url="https://download.swift.org/swift-${latest_version}-release/android-sdk/${snapshot_tag}/${snapshot_tag}_android.artifactbundle.tar.gz" + ;; + esac + echo "Installing Android Swift SDK" + echo " url: $sdk_url" + echo " checksum: $sdk_checksum" + swift sdk install "$sdk_url" --checksum "$sdk_checksum" + swift sdk list + + - name: Configure Swift Android SDK + run: | + set -euo pipefail + cd $HOME/.swiftpm/swift-sdks/*android*.artifactbundle || cd $HOME/.config/swiftpm/swift-sdks/*android*.artifactbundle || cd $HOME/Library/org.swift.swiftpm/swift-sdks/*android*.artifactbundle + # Link the SDK against the NDK we installed in the previous step. + # Someday we might not need this script, so gracefully skip it + # if it does not exist. + if [[ -x "./swift-android/scripts/setup-android-sdk.sh" ]]; then + "./swift-android/scripts/setup-android-sdk.sh" fi - echo "SWIFT_SDK_PATH=$SDK_DIR" >> "$GITHUB_ENV" - name: Publish swift-java packages to local Maven # The hashing-lib, weather-lib, and hello-cpp-swift/swift-lib modules From 37bf3dabbe737f1eabe841a6169c3e4b7b6b7d3d Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 18:13:19 -0400 Subject: [PATCH 05/20] Update CI --- .github/workflows/ci.yml | 91 ++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 55 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f415438..2e9c448 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,8 +9,7 @@ permissions: contents: read jobs: - build: - name: Build (swift:${{ matrix.swift_version }}) + build-examples: strategy: fail-fast: false matrix: @@ -27,7 +26,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up JDK 25 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: '25' @@ -35,58 +34,46 @@ jobs: - name: Install swiftly run: | set -euxo pipefail - sudo apt-get -q update - sudo apt-get -yq install curl jq gpg unzip - ARCH="$(uname -m)" - curl -L -O --retry 3 "https://download.swift.org/swiftly/linux/swiftly-${ARCH}.tar.gz" - tar -xzf "swiftly-${ARCH}.tar.gz" - ./swiftly init \ - --assume-yes \ - --skip-install \ - --no-modify-profile \ - --quiet-shell-followup - rm -f "swiftly-${ARCH}.tar.gz" swiftly - # The example projects' Gradle scripts look for swiftly under - # $HOME/.local/share/swiftly/bin, which is also where the official - # installer puts it. Add it to PATH for subsequent steps. - echo "$HOME/.local/share/swiftly/bin" >> "$GITHUB_PATH" - "$HOME/.local/share/swiftly/bin/swiftly" --version - - - name: Install Swift via swiftly - run: | - set -euxo pipefail - # Translate the matrix's swift_version into the form swiftly expects: - # nightly-main -> main-snapshot - # nightly-6.3 -> 6.3-snapshot - # 6.3 / 6.3.0 -> passed through as-is - case "$SWIFT_VERSION" in - nightly-main) SWIFTLY_VER="main-snapshot" ;; - nightly-*) SWIFTLY_VER="${SWIFT_VERSION#nightly-}-snapshot" ;; - *) SWIFTLY_VER="$SWIFT_VERSION" ;; - esac - POST_INSTALL_FILE="$(mktemp)" - swiftly install "$SWIFTLY_VER" \ - --use \ - --assume-yes \ - --post-install-file="$POST_INSTALL_FILE" - # Some toolchains print follow-up commands (e.g. apt-get install - # of missing system libs) to the post-install file. Run them if - # any were emitted. - if [ -s "$POST_INSTALL_FILE" ]; then - sudo bash "$POST_INSTALL_FILE" + if [[ "${RUNNER_OS}" == "Linux" ]]; then + sudo apt-get -yq update install curl jq gpg unzip + ARCH="$(uname -m)" + curl -L -O --retry 3 "https://download.swift.org/swiftly/linux/swiftly-${ARCH}.tar.gz" + tar -xzf "swiftly-${ARCH}.tar.gz" + ./swiftly init \ + --assume-yes \ + --skip-install \ + --no-modify-profile \ + --quiet-shell-followup + rm -f "swiftly-${ARCH}.tar.gz" swiftly + # The example projects' Gradle scripts look for swiftly under + # $HOME/.local/share/swiftly/bin, which is also where the official + # installer puts it. Add it to PATH for subsequent steps. + echo "$HOME/.local/share/swiftly/bin" >> "$GITHUB_PATH" + "$HOME/.local/share/swiftly/bin/swiftly" --version + elif [[ "${RUNNER_OS}" == "macOS" ]]; then + curl -O https://download.swift.org/swiftly/darwin/swiftly.pkg && \ + installer -pkg swiftly.pkg -target CurrentUserHomeDirectory && \ + ~/.swiftly/bin/swiftly init --quiet-shell-followup && \ + . "${SWIFTLY_HOME_DIR:-$HOME/.swiftly}/env.sh" && \ + hash -r + + echo "$HOME/.swiftly/bin" >> "$GITHUB_PATH" + "$HOME/.swiftly/bin/swiftly" --version + else + echo "Unknown OS: ${RUNNER_OS}" + exit 1 fi - rm -f "$POST_INSTALL_FILE" - swift --version - name: Install Android NDK run: | set -euxo pipefail - curl -L -o ndk.zip --retry 3 "https://dl.google.com/android/repository/android-ndk-${NDK_VERSION}-linux.zip" + OS="$(uname -s | tr '[A-Z]' '[a-z]')" + curl -L -o ndk.zip --retry 3 "https://dl.google.com/android/repository/android-ndk-${NDK_VERSION}-${OS}.zip" unzip -q ndk.zip -d "$HOME" rm ndk.zip echo "ANDROID_NDK_HOME=$HOME/android-ndk-${NDK_VERSION}" >> "$GITHUB_ENV" - - name: Install Android Swift SDK + - name: Install Android Swift SDK and matching host toolchain # Looks up the Android Swift SDK URL and checksum from the swift.org # install API and installs it via `swift sdk install`. For releases # we use https://www.swift.org/api/v1/install/releases.json (which @@ -128,9 +115,11 @@ jobs: sdk_url="https://download.swift.org/swift-${latest_version}-release/android-sdk/${snapshot_tag}/${snapshot_tag}_android.artifactbundle.tar.gz" ;; esac - echo "Installing Android Swift SDK" + echo "Installing Android Swift SDK and host toolchain" + echo " tag: $snapshot_tag" echo " url: $sdk_url" echo " checksum: $sdk_checksum" + swiftly install ${snapshot_tag} swift sdk install "$sdk_url" --checksum "$sdk_checksum" swift sdk list @@ -158,35 +147,27 @@ jobs: ./.build/checkouts/swift-java/gradlew \ --project-dir .build/checkouts/swift-java \ :SwiftKitCore:publishToMavenLocal - continue-on-error: true - name: Build hello-swift-raw-jni APK run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace - continue-on-error: true - name: Build hello-swift-raw-jni-callback APK run: ./gradlew :hello-swift-raw-jni-callback:assembleDebug --stacktrace - continue-on-error: true - name: Build hello-swift-raw-jni-library run: ./gradlew :hello-swift-raw-jni-library:assembleDebug --stacktrace - continue-on-error: true - name: Build native-activity APK run: ./gradlew :native-activity:assembleDebug --stacktrace - continue-on-error: true - name: Build hello-swift-java APK run: ./gradlew :hello-swift-java-hashing-app:assembleDebug --stacktrace - continue-on-error: true - name: Build swift-java-weather-app APK run: ./gradlew :swift-java-weather-app-weather-app:assembleDebug --stacktrace - continue-on-error: true - name: Build hello-cpp-swift APK run: ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace - continue-on-error: true - name: Upload APK artifacts if: always() From 6466620aacc9e22572de13799f9b10429e4d0b0a Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 18:20:57 -0400 Subject: [PATCH 06/20] Update CI --- .github/workflows/ci.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e9c448..8d32453 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: run: | set -euxo pipefail if [[ "${RUNNER_OS}" == "Linux" ]]; then - sudo apt-get -yq update install curl jq gpg unzip + sudo apt-get -yq install curl jq gpg unzip ARCH="$(uname -m)" curl -L -O --retry 3 "https://download.swift.org/swiftly/linux/swiftly-${ARCH}.tar.gz" tar -xzf "swiftly-${ARCH}.tar.gz" @@ -119,7 +119,7 @@ jobs: echo " tag: $snapshot_tag" echo " url: $sdk_url" echo " checksum: $sdk_checksum" - swiftly install ${snapshot_tag} + swiftly install ${${snapshot_tag/swift-/}/-RELEASE/} swift sdk install "$sdk_url" --checksum "$sdk_checksum" swift sdk list @@ -149,7 +149,7 @@ jobs: :SwiftKitCore:publishToMavenLocal - name: Build hello-swift-raw-jni APK - run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace + run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace --verbose - name: Build hello-swift-raw-jni-callback APK run: ./gradlew :hello-swift-raw-jni-callback:assembleDebug --stacktrace @@ -176,3 +176,4 @@ jobs: name: apks-${{ matrix.swift_version }} path: '**/build/outputs/apk/**/*.apk' if-no-files-found: warn + From 49da23142e61e4487acf85928fcd802ef53a9bdd Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 18:44:40 -0400 Subject: [PATCH 07/20] Update CI --- .github/workflows/ci.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d32453..77f946a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -115,11 +115,17 @@ jobs: sdk_url="https://download.swift.org/swift-${latest_version}-release/android-sdk/${snapshot_tag}/${snapshot_tag}_android.artifactbundle.tar.gz" ;; esac + + swift_install=${snapshot_tag} + # trim leading "swift-" and trailing "-RELEASE" + swift_install=${swift_install/swift-/} + swift_install=${swift_install/-RELEASE/} + echo "Installing Android Swift SDK and host toolchain" - echo " tag: $snapshot_tag" + echo " tag: $swift_install" echo " url: $sdk_url" echo " checksum: $sdk_checksum" - swiftly install ${${snapshot_tag/swift-/}/-RELEASE/} + swiftly install "${swift_install}" swift sdk install "$sdk_url" --checksum "$sdk_checksum" swift sdk list From 0fbc79f7389e16a4e1135ca11aa104d23feaff65 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 18:54:21 -0400 Subject: [PATCH 08/20] Update CI --- .github/workflows/ci.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 77f946a..a99cf3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: run: | set -euxo pipefail if [[ "${RUNNER_OS}" == "Linux" ]]; then - sudo apt-get -yq install curl jq gpg unzip + sudo apt-get -yq install curl jq gpg unzip libcurl4-openssl-dev ARCH="$(uname -m)" curl -L -O --retry 3 "https://download.swift.org/swiftly/linux/swiftly-${ARCH}.tar.gz" tar -xzf "swiftly-${ARCH}.tar.gz" @@ -75,12 +75,7 @@ jobs: - name: Install Android Swift SDK and matching host toolchain # Looks up the Android Swift SDK URL and checksum from the swift.org - # install API and installs it via `swift sdk install`. For releases - # we use https://www.swift.org/api/v1/install/releases.json (which - # gives us each platform's checksum, but not a download URL — we - # construct that from the version). For nightlies we query - # https://www.swift.org/api/v1/install/dev//android-sdk.json - # for the latest snapshot tag and checksum. + # install API and installs it via `swift sdk install`. run: | set -euxo pipefail case "$SWIFT_VERSION" in @@ -155,7 +150,7 @@ jobs: :SwiftKitCore:publishToMavenLocal - name: Build hello-swift-raw-jni APK - run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace --verbose + run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace --debug - name: Build hello-swift-raw-jni-callback APK run: ./gradlew :hello-swift-raw-jni-callback:assembleDebug --stacktrace @@ -177,7 +172,7 @@ jobs: - name: Upload APK artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: apks-${{ matrix.swift_version }} path: '**/build/outputs/apk/**/*.apk' From e10dd0d6191946e0f5d20177442a112145b97ef3 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 22:51:02 -0400 Subject: [PATCH 09/20] Update CI --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a99cf3c..5abc3a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: swift_install=${snapshot_tag} # trim leading "swift-" and trailing "-RELEASE" - swift_install=${swift_install/swift-/} + swift_install=${swift_install#swift-} swift_install=${swift_install/-RELEASE/} echo "Installing Android Swift SDK and host toolchain" @@ -150,7 +150,7 @@ jobs: :SwiftKitCore:publishToMavenLocal - name: Build hello-swift-raw-jni APK - run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace --debug + run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace - name: Build hello-swift-raw-jni-callback APK run: ./gradlew :hello-swift-raw-jni-callback:assembleDebug --stacktrace From 270fef19d9156ad404b03e0950bed72c477a05d0 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 22:54:02 -0400 Subject: [PATCH 10/20] Update CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5abc3a5..8b7892f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,7 +105,7 @@ jobs: exit 1 fi sdk_checksum=$(echo "$releases_json" | jq -r --arg v "$latest_version" \ - '.[] | select(.name == $v) | .platforms[] | select(.platform == "android") | .checksum') + '.[] | select(.name == $v) | .platforms[] | select(.platform == "android-sdk") | .checksum') snapshot_tag="swift-${latest_version}-RELEASE" sdk_url="https://download.swift.org/swift-${latest_version}-release/android-sdk/${snapshot_tag}/${snapshot_tag}_android.artifactbundle.tar.gz" ;; From 63f4b89e32a8e01da04f607e5dcaf2bb68ed9fad Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 23:11:41 -0400 Subject: [PATCH 11/20] Update CI --- .github/workflows/ci.yml | 4 ++++ swift-android.gradle.kts | 12 +++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b7892f..b13f768 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -124,6 +124,10 @@ jobs: swift sdk install "$sdk_url" --checksum "$sdk_checksum" swift sdk list + # set environment variables used by swift-android.gradle.kts + echo "SWIFT_VERSION=${swift_install}" >> $GITHUB_ENV + echo "SWIFT_ANDROID_SDK_VERSION=${snapshot_tag}_android" >> $GITHUB_ENV + - name: Configure Swift Android SDK run: | set -euo pipefail diff --git a/swift-android.gradle.kts b/swift-android.gradle.kts index 37fa46a..08ca0fa 100644 --- a/swift-android.gradle.kts +++ b/swift-android.gradle.kts @@ -14,8 +14,14 @@ data class SwiftConfig( var releaseExtraBuildFlags: List = emptyList(), var swiftlyPath: String? = null, // Optional custom swiftly path var swiftSDKPath: String? = null, // Optional custom Swift SDK path - var swiftVersion: String = "6.3", // Swift version - var androidSdkVersion: String = "6.3-RELEASE_android" // SDK version + // Swift toolchain version passed to swiftly (e.g. "6.3", "main-snapshot"). + // Can be overridden via the SWIFT_VERSION environment variable, which is + // useful for CI matrices that test multiple toolchains. + var swiftVersion: String = System.getenv("SWIFT_VERSION")?.takeIf { it.isNotEmpty() } ?: "6.3", + // Android Swift SDK artifactbundle suffix. Substituted into the bundle + // directory name as "swift-${androidSdkVersion}.artifactbundle". Can be + // overridden via the SWIFT_ANDROID_SDK_VERSION environment variable. + var androidSdkVersion: String = System.getenv("SWIFT_ANDROID_SDK_VERSION")?.takeIf { it.isNotEmpty() } ?: "${swiftVersion}-RELEASE_android" ) // Architecture definitions @@ -296,4 +302,4 @@ project.afterEvaluate { } else { throw GradleException("Android extension not found. Make sure to apply this script after the Android plugin.") } -} \ No newline at end of file +} From 7db51f66c4905b796f86aa6183d0fa1e36f170f0 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 23:17:47 -0400 Subject: [PATCH 12/20] Update CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b13f768..8ab4a33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,7 +126,7 @@ jobs: # set environment variables used by swift-android.gradle.kts echo "SWIFT_VERSION=${swift_install}" >> $GITHUB_ENV - echo "SWIFT_ANDROID_SDK_VERSION=${snapshot_tag}_android" >> $GITHUB_ENV + echo "SWIFT_ANDROID_SDK_VERSION=${snapshot_tag#swift-}_android" >> $GITHUB_ENV - name: Configure Swift Android SDK run: | From eb07553a5fe3d94a6894de189c508b4dbac0fff6 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 23:23:59 -0400 Subject: [PATCH 13/20] Update CI --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ab4a33..0eb037a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -171,7 +171,9 @@ jobs: - name: Build swift-java-weather-app APK run: ./gradlew :swift-java-weather-app-weather-app:assembleDebug --stacktrace + # skipping due to: error: local binary target 'HelloWorldCpp' at '/Users/runner/work/swift-android-examples/swift-android-examples/hello-cpp-swift/cpp-lib/prebuilt/HelloWorldCpp.artifactbundle' does not contain a binary artifact. - name: Build hello-cpp-swift APK + if: false run: ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace - name: Upload APK artifacts From 5b2f0225b675a9401c287dba41d978b92acece2e Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 23:25:23 -0400 Subject: [PATCH 14/20] Update CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0eb037a..007069b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - swift_version: ['nightly-main', 'nightly-6.3', '6.3'] + swift_version: ['nightly-main', '6.3'] sdk_triple: ['aarch64-unknown-linux-android28'] ndk_version: ['r27d'] os: ['ubuntu-latest', 'macos-latest'] From 571da46f48ca6c79017d21c86d1a8fb31f2420e7 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 23:27:28 -0400 Subject: [PATCH 15/20] Update CI --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 007069b..ece4629 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,7 @@ permissions: jobs: build-examples: + name: Build ${{ matrix.os }} ${{ matrix.swift_version }} strategy: fail-fast: false matrix: From cfecb383a257f352fc99e7552e624109d9061919 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Wed, 8 Apr 2026 23:50:08 -0400 Subject: [PATCH 16/20] Update CI --- .github/workflows/ci.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ece4629..429bcbc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,6 +154,13 @@ jobs: --project-dir .build/checkouts/swift-java \ :SwiftKitCore:publishToMavenLocal + - name: Build hello-cpp-swift APK + run: | + cd hello-cpp-swift/cpp-lib + ./build-android-static.sh + cd - + ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace + - name: Build hello-swift-raw-jni APK run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace @@ -172,11 +179,6 @@ jobs: - name: Build swift-java-weather-app APK run: ./gradlew :swift-java-weather-app-weather-app:assembleDebug --stacktrace - # skipping due to: error: local binary target 'HelloWorldCpp' at '/Users/runner/work/swift-android-examples/swift-android-examples/hello-cpp-swift/cpp-lib/prebuilt/HelloWorldCpp.artifactbundle' does not contain a binary artifact. - - name: Build hello-cpp-swift APK - if: false - run: ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace - - name: Upload APK artifacts if: always() uses: actions/upload-artifact@v7 From f8ab14d649c9573e4fe92b2d8d8acb9bb5775f2f Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Thu, 9 Apr 2026 00:03:35 -0400 Subject: [PATCH 17/20] Update CI --- .github/workflows/ci.yml | 14 +++++++------- hello-cpp-swift/swift-lib/build.gradle | 11 +++++++++-- hello-swift-java/hashing-lib/build.gradle | 11 +++++++++-- swift-java-weather-app/weather-lib/build.gradle | 11 +++++++++-- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 429bcbc..cd33c0d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,13 +154,6 @@ jobs: --project-dir .build/checkouts/swift-java \ :SwiftKitCore:publishToMavenLocal - - name: Build hello-cpp-swift APK - run: | - cd hello-cpp-swift/cpp-lib - ./build-android-static.sh - cd - - ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace - - name: Build hello-swift-raw-jni APK run: ./gradlew :hello-swift-raw-jni:assembleDebug --stacktrace @@ -179,6 +172,13 @@ jobs: - name: Build swift-java-weather-app APK run: ./gradlew :swift-java-weather-app-weather-app:assembleDebug --stacktrace + - name: Build hello-cpp-swift APK + run: | + cd hello-cpp-swift/cpp-lib + ./build-android-static.sh + cd - + ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace + - name: Upload APK artifacts if: always() uses: actions/upload-artifact@v7 diff --git a/hello-cpp-swift/swift-lib/build.gradle b/hello-cpp-swift/swift-lib/build.gradle index 63b2fb8..cadc804 100644 --- a/hello-cpp-swift/swift-lib/build.gradle +++ b/hello-cpp-swift/swift-lib/build.gradle @@ -89,8 +89,15 @@ def swiftRuntimeLibs = [ "swiftSynchronization" ] -def sdkName = "swift-6.3-RELEASE_android.artifactbundle" -def swiftVersion = "6.3" +// Swift toolchain version passed to swiftly (e.g. "6.3", "main-snapshot"). +// Can be overridden via the SWIFT_VERSION environment variable, which is +// useful for CI matrices that test multiple toolchains. +def swiftVersion = System.getenv("SWIFT_VERSION") ?: "6.3" +// Android Swift SDK artifactbundle suffix. Substituted into the bundle +// directory name as "swift-${androidSdkVersion}.artifactbundle". Can be +// overridden via the SWIFT_ANDROID_SDK_VERSION environment variable. +def androidSdkVersion = System.getenv("SWIFT_ANDROID_SDK_VERSION") ?: "${swiftVersion}-RELEASE_android" +def sdkName = "swift-${androidSdkVersion}.artifactbundle" def minSdk = android.defaultConfig.minSdkVersion.apiLevel def abis = [ diff --git a/hello-swift-java/hashing-lib/build.gradle b/hello-swift-java/hashing-lib/build.gradle index 9fd45a7..da2d25d 100644 --- a/hello-swift-java/hashing-lib/build.gradle +++ b/hello-swift-java/hashing-lib/build.gradle @@ -99,8 +99,15 @@ def swiftRuntimeLibs = [ "swiftSynchronization" ] -def sdkName = "swift-6.3-RELEASE_android.artifactbundle" -def swiftVersion = "6.3" +// Swift toolchain version passed to swiftly (e.g. "6.3", "main-snapshot"). +// Can be overridden via the SWIFT_VERSION environment variable, which is +// useful for CI matrices that test multiple toolchains. +def swiftVersion = System.getenv("SWIFT_VERSION") ?: "6.3" +// Android Swift SDK artifactbundle suffix. Substituted into the bundle +// directory name as "swift-${androidSdkVersion}.artifactbundle". Can be +// overridden via the SWIFT_ANDROID_SDK_VERSION environment variable. +def androidSdkVersion = System.getenv("SWIFT_ANDROID_SDK_VERSION") ?: "${swiftVersion}-RELEASE_android" +def sdkName = "swift-${androidSdkVersion}.artifactbundle" def minSdk = android.defaultConfig.minSdkVersion.apiLevel /** * Android ABIs and their Swift triple mappings diff --git a/swift-java-weather-app/weather-lib/build.gradle b/swift-java-weather-app/weather-lib/build.gradle index db8a66d..38b7d53 100644 --- a/swift-java-weather-app/weather-lib/build.gradle +++ b/swift-java-weather-app/weather-lib/build.gradle @@ -98,8 +98,15 @@ def swiftRuntimeLibs = [ "_FoundationICU", "swiftSynchronization" ] -def sdkName = "swift-6.3-RELEASE_android.artifactbundle" -def swiftVersion = "6.3" +// Swift toolchain version passed to swiftly (e.g. "6.3", "main-snapshot"). +// Can be overridden via the SWIFT_VERSION environment variable, which is +// useful for CI matrices that test multiple toolchains. +def swiftVersion = System.getenv("SWIFT_VERSION") ?: "6.3" +// Android Swift SDK artifactbundle suffix. Substituted into the bundle +// directory name as "swift-${androidSdkVersion}.artifactbundle". Can be +// overridden via the SWIFT_ANDROID_SDK_VERSION environment variable. +def androidSdkVersion = System.getenv("SWIFT_ANDROID_SDK_VERSION") ?: "${swiftVersion}-RELEASE_android" +def sdkName = "swift-${androidSdkVersion}.artifactbundle" def minSdk = android.defaultConfig.minSdkVersion.apiLevel /** * Android ABIs and their Swift triple mappings From 9b4ba795caef196129bd75e3d950e1aa60da6be8 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Thu, 9 Apr 2026 00:30:43 -0400 Subject: [PATCH 18/20] Update CI --- .github/workflows/ci.yml | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd33c0d..a7540fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,8 @@ jobs: strategy: fail-fast: false matrix: - swift_version: ['nightly-main', '6.3'] + #swift_version: ['nightly-main', '6.3'] + swift_version: ['6.3'] sdk_triple: ['aarch64-unknown-linux-android28'] ndk_version: ['r27d'] os: ['ubuntu-latest', 'macos-latest'] @@ -179,11 +180,45 @@ jobs: cd - ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace + - name: Summarize APK artifacts + if: always() + run: | + echo "## APK Artifacts (${{ matrix.os }} / swift:${{ matrix.swift_version }} / ${{ matrix.sdk_triple }})" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + echo "| Project | APK | Size |" >> "$GITHUB_STEP_SUMMARY" + echo "|---------|-----|------|" >> "$GITHUB_STEP_SUMMARY" + found=0 + while IFS= read -r apk; do + found=1 + # Derive a human-readable project name from the path + project=$(echo "$apk" | sed -E 's#^\./##; s#/build/outputs/.*##') + name=$(basename "$apk") + # Human-readable size + if command -v numfmt >/dev/null 2>&1; then + size=$(stat --format='%s' "$apk" 2>/dev/null | numfmt --to=iec-i --suffix=B) + else + bytes=$(stat -f '%z' "$apk" 2>/dev/null || echo 0) + if [ "$bytes" -ge 1073741824 ]; then + size="$(awk "BEGIN {printf \"%.1f\", $bytes/1073741824}")GiB" + elif [ "$bytes" -ge 1048576 ]; then + size="$(awk "BEGIN {printf \"%.1f\", $bytes/1048576}")MiB" + elif [ "$bytes" -ge 1024 ]; then + size="$(awk "BEGIN {printf \"%.1f\", $bytes/1024}")KiB" + else + size="${bytes}B" + fi + fi + echo "| \`$project\` | \`$name\` | $size |" >> "$GITHUB_STEP_SUMMARY" + done < <(find . -path '*/build/outputs/apk/*.apk' -type f | sort) + if [ "$found" -eq 0 ]; then + echo "| _(none)_ | — | — |" >> "$GITHUB_STEP_SUMMARY" + fi + - name: Upload APK artifacts if: always() uses: actions/upload-artifact@v7 with: - name: apks-${{ matrix.swift_version }} + name: apks-${{ matrix.os }}-${{ matrix.swift_version }}-${{ matrix.sdk_triple }}-${{ matrix.ndk_version }} path: '**/build/outputs/apk/**/*.apk' if-no-files-found: warn From 6a59d5f3a6a0c31793d485d7fc07a719ce63fa33 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Thu, 9 Apr 2026 00:39:33 -0400 Subject: [PATCH 19/20] Update CI --- .github/workflows/ci.yml | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7540fb..667deb5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -193,21 +193,8 @@ jobs: # Derive a human-readable project name from the path project=$(echo "$apk" | sed -E 's#^\./##; s#/build/outputs/.*##') name=$(basename "$apk") - # Human-readable size - if command -v numfmt >/dev/null 2>&1; then - size=$(stat --format='%s' "$apk" 2>/dev/null | numfmt --to=iec-i --suffix=B) - else - bytes=$(stat -f '%z' "$apk" 2>/dev/null || echo 0) - if [ "$bytes" -ge 1073741824 ]; then - size="$(awk "BEGIN {printf \"%.1f\", $bytes/1073741824}")GiB" - elif [ "$bytes" -ge 1048576 ]; then - size="$(awk "BEGIN {printf \"%.1f\", $bytes/1048576}")MiB" - elif [ "$bytes" -ge 1024 ]; then - size="$(awk "BEGIN {printf \"%.1f\", $bytes/1024}")KiB" - else - size="${bytes}B" - fi - fi + # Human-readable size (du -h works on both Linux and macOS) + size=$(du -h "$apk" | cut -f1 | tr -d '[:space:]') echo "| \`$project\` | \`$name\` | $size |" >> "$GITHUB_STEP_SUMMARY" done < <(find . -path '*/build/outputs/apk/*.apk' -type f | sort) if [ "$found" -eq 0 ]; then From e0258fa2de0be9ef6ddae0f3a8d77da690f86da8 Mon Sep 17 00:00:00 2001 From: Marc Prud'hommeaux Date: Thu, 30 Apr 2026 12:06:13 -0400 Subject: [PATCH 20/20] Update build matrix --- .github/workflows/ci.yml | 57 +++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 667deb5..cbdaa1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,18 +4,27 @@ on: push: branches: [main] pull_request: + workflow_dispatch: + inputs: + swift_versions: + description: 'JSON array of Swift versions to test (e.g. ["6.3"], ["6.3", "nightly-main"])' + required: false + default: '["6.3"]' permissions: contents: read +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: build-examples: name: Build ${{ matrix.os }} ${{ matrix.swift_version }} strategy: fail-fast: false matrix: - #swift_version: ['nightly-main', '6.3'] - swift_version: ['6.3'] + swift_version: ${{ fromJSON(inputs.swift_versions || '["6.3"]') }} sdk_triple: ['aarch64-unknown-linux-android28'] ndk_version: ['r27d'] os: ['ubuntu-latest', 'macos-latest'] @@ -53,12 +62,11 @@ jobs: echo "$HOME/.local/share/swiftly/bin" >> "$GITHUB_PATH" "$HOME/.local/share/swiftly/bin/swiftly" --version elif [[ "${RUNNER_OS}" == "macOS" ]]; then - curl -O https://download.swift.org/swiftly/darwin/swiftly.pkg && \ - installer -pkg swiftly.pkg -target CurrentUserHomeDirectory && \ - ~/.swiftly/bin/swiftly init --quiet-shell-followup && \ - . "${SWIFTLY_HOME_DIR:-$HOME/.swiftly}/env.sh" && \ + curl -O https://download.swift.org/swiftly/darwin/swiftly.pkg + installer -pkg swiftly.pkg -target CurrentUserHomeDirectory + ~/.swiftly/bin/swiftly init --quiet-shell-followup + . "${SWIFTLY_HOME_DIR:-$HOME/.swiftly}/env.sh" hash -r - echo "$HOME/.swiftly/bin" >> "$GITHUB_PATH" "$HOME/.swiftly/bin/swiftly" --version else @@ -126,14 +134,31 @@ jobs: swift sdk install "$sdk_url" --checksum "$sdk_checksum" swift sdk list - # set environment variables used by swift-android.gradle.kts - echo "SWIFT_VERSION=${swift_install}" >> $GITHUB_ENV - echo "SWIFT_ANDROID_SDK_VERSION=${snapshot_tag#swift-}_android" >> $GITHUB_ENV + # Override the matrix-supplied SWIFT_VERSION (e.g. "6.3") with the + # resolved patch version (e.g. "6.3.1") so the gradle scripts pick up + # the actual artifactbundle directory name produced by `swift sdk + # install`. SWIFT_ANDROID_SDK_VERSION pins the bundle suffix for the + # same reason. + echo "SWIFT_VERSION=${swift_install}" >> "$GITHUB_ENV" + echo "SWIFT_ANDROID_SDK_VERSION=${snapshot_tag#swift-}_android" >> "$GITHUB_ENV" - name: Configure Swift Android SDK run: | set -euo pipefail - cd $HOME/.swiftpm/swift-sdks/*android*.artifactbundle || cd $HOME/.config/swiftpm/swift-sdks/*android*.artifactbundle || cd $HOME/Library/org.swift.swiftpm/swift-sdks/*android*.artifactbundle + # Locate the installed Android SDK artifactbundle. Its parent + # directory varies by OS / swiftpm version, so try the known + # candidates and pick the first one that actually matches. + shopt -s nullglob + candidates=( + "$HOME"/.swiftpm/swift-sdks/*android*.artifactbundle + "$HOME"/.config/swiftpm/swift-sdks/*android*.artifactbundle + "$HOME"/Library/org.swift.swiftpm/swift-sdks/*android*.artifactbundle + ) + if [[ ${#candidates[@]} -eq 0 ]]; then + echo "No android SDK artifactbundle found in any known location" >&2 + exit 1 + fi + cd "${candidates[0]}" # Link the SDK against the NDK we installed in the previous step. # Someday we might not need this script, so gracefully skip it # if it does not exist. @@ -173,12 +198,12 @@ jobs: - name: Build swift-java-weather-app APK run: ./gradlew :swift-java-weather-app-weather-app:assembleDebug --stacktrace + - name: Build hello-cpp-swift cpp-lib + working-directory: hello-cpp-swift/cpp-lib + run: ./build-android-static.sh + - name: Build hello-cpp-swift APK - run: | - cd hello-cpp-swift/cpp-lib - ./build-android-static.sh - cd - - ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace + run: ./gradlew :hello-cpp-swift:app:assembleDebug --stacktrace - name: Summarize APK artifacts if: always()