Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
b9b0d7f
Build examples in CI
marcprux Apr 8, 2026
41f902a
Update swift_version in matrix
marcprux Apr 8, 2026
040c718
Install swiftly
marcprux Apr 8, 2026
0c20f0b
Update CI
marcprux Apr 8, 2026
37bf3da
Update CI
marcprux Apr 8, 2026
6466620
Update CI
marcprux Apr 8, 2026
49da231
Update CI
marcprux Apr 8, 2026
0fbc79f
Update CI
marcprux Apr 8, 2026
e10dd0d
Update CI
marcprux Apr 9, 2026
270fef1
Update CI
marcprux Apr 9, 2026
63f4b89
Update CI
marcprux Apr 9, 2026
7db51f6
Update CI
marcprux Apr 9, 2026
eb07553
Update CI
marcprux Apr 9, 2026
5b2f022
Update CI
marcprux Apr 9, 2026
571da46
Update CI
marcprux Apr 9, 2026
cfecb38
Update CI
marcprux Apr 9, 2026
f8ab14d
Update CI
marcprux Apr 9, 2026
9b4ba79
Update CI
marcprux Apr 9, 2026
6a59d5f
Update CI
marcprux Apr 9, 2026
e0258fa
Update build matrix
marcprux Apr 30, 2026
32dcffd
Merge branch 'swiftlang:main' into ci
marcprux May 6, 2026
75f826b
Add nightly-main to SDK matrix
marcprux May 6, 2026
6f7c435
Run CI on push
marcprux May 6, 2026
1f48004
Run apt-get update on Linux to ensure we can get libcurl4-openssl-dev
marcprux May 6, 2026
1e6c8ee
Enable --build-system native to work around https://github.com/swiftl…
marcprux May 6, 2026
6e2724d
Add ndk caching and remove unused sdk_triple
marcprux May 6, 2026
167291e
Add release build variants
marcprux May 6, 2026
85f163a
Add soundness checks
marcprux May 6, 2026
8fa1aac
Update formatting for soundness and disable format checks
marcprux May 6, 2026
0ae7fcb
Update soundness checks
marcprux May 6, 2026
262aef8
Update license headers for soundness license checks
marcprux May 6, 2026
c0471be
Update license headers for soundness license checks
marcprux May 6, 2026
6796614
Update license headers for soundness license checks
marcprux May 6, 2026
0b2a09c
Update license headers for soundness license checks
marcprux May 6, 2026
98a34bf
Enable format_check_enabled
marcprux May 7, 2026
ededcfb
Update swift code formatting to satisfy swift-format
marcprux May 7, 2026
7de27b9
Add swift_version nightly-6.3 and ndk_version r29
marcprux May 8, 2026
874cb5b
Separate soundness and ci into separate actions
marcprux May 8, 2026
a0f1132
Only run on push to main and update the cron schedule
marcprux May 8, 2026
c3a3862
Fix yaml formatting
marcprux May 8, 2026
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
241 changes: 241 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
name: ci
Comment thread
marcprux marked this conversation as resolved.

on:
push:
branches: [main]
pull_request:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
build-examples:
strategy:
fail-fast: false
matrix:
swift_version: ['6.3', 'nightly-6.3', 'nightly-main']
ndk_version: ['r27d', 'r29', 'r30-beta1']
os: ['ubuntu-latest', 'macos-latest']
configuration: ['Debug', 'Release']
runs-on: ${{ matrix.os }}
env:
NDK_VERSION: ${{ matrix.ndk_version }}
SWIFT_VERSION: ${{ matrix.swift_version }}
steps:
- uses: actions/checkout@v6

- name: Set up JDK 25
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '25'

- name: Install swiftly
run: |
set -euxo pipefail
if [[ "${RUNNER_OS}" == "Linux" ]]; then
sudo apt-get update
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"
./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

Comment thread
marcprux marked this conversation as resolved.
- name: Cache Android NDK
id: cache-ndk
uses: actions/cache@v5
with:
path: ~/android-ndk-${{ matrix.ndk_version }}
key: android-ndk-${{ runner.os }}-${{ runner.arch }}-${{ matrix.ndk_version }}

- name: Install Android NDK
Comment thread
marcprux marked this conversation as resolved.
if: steps.cache-ndk.outputs.cache-hit != 'true'
run: |
set -euxo pipefail
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

- name: Set ANDROID_NDK_HOME
run: echo "ANDROID_NDK_HOME=$HOME/android-ndk-${NDK_VERSION}" >> "$GITHUB_ENV"

- 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`.
run: |
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
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-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"
;;
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: $swift_install"
echo " url: $sdk_url"
echo " checksum: $sdk_checksum"
swiftly install "${swift_install}"
swift sdk install "$sdk_url" --checksum "$sdk_checksum"
swift sdk list

# 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
# 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.
if [[ -x "./swift-android/scripts/setup-android-sdk.sh" ]]; then
"./swift-android/scripts/setup-android-sdk.sh"
fi

- 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 package resolve
./.build/checkouts/swift-java/gradlew \
--project-dir .build/checkouts/swift-java \
:SwiftKitCore:publishToMavenLocal

- name: Build hello-swift-raw-jni APK
run: ./gradlew :hello-swift-raw-jni:assemble${{ matrix.configuration }} --stacktrace

- name: Build hello-swift-raw-jni-callback APK
run: ./gradlew :hello-swift-raw-jni-callback:assemble${{ matrix.configuration }} --stacktrace

- name: Build hello-swift-raw-jni-library
run: ./gradlew :hello-swift-raw-jni-library:assemble${{ matrix.configuration }} --stacktrace

- name: Build native-activity APK
run: ./gradlew :native-activity:assemble${{ matrix.configuration }} --stacktrace

- name: Build hello-swift-java APK
run: ./gradlew :hello-swift-java-hashing-app:assemble${{ matrix.configuration }} --stacktrace

- name: Build swift-java-weather-app APK
run: ./gradlew :swift-java-weather-app-weather-app:assemble${{ matrix.configuration }} --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: ./gradlew :hello-cpp-swift:app:assemble${{ matrix.configuration }} --stacktrace

- name: Summarize APK artifacts
if: always()
run: |
echo "## APK Artifacts (os:${{ matrix.os }} / swift:${{ matrix.swift_version }} / ndk:${{ matrix.ndk_version }}) / configuration:${{ matrix.configuration }}" >> "$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 (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
echo "| _(none)_ | — | — |" >> "$GITHUB_STEP_SUMMARY"
fi

- name: Upload APK artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: apks-${{ matrix.os }}-${{ matrix.swift_version }}-${{ matrix.ndk_version }}
path: '**/build/outputs/apk/**/*.apk'
if-no-files-found: warn
15 changes: 15 additions & 0 deletions .github/workflows/soundness.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: soundness

on:
push:
pull_request:

permissions:
contents: read

jobs:
soundness:
name: Soundness
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
with:
license_header_check_project_name: "Swift.org"
56 changes: 56 additions & 0 deletions .licenseignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.gitignore
**/.gitignore
.licenseignore
.unacceptablelanguageignore
.swiftformatignore
.gitattributes
.mailfilter
.mailmap
.spi.yml
.swift-format
.editorconfig
.github/*
.idea/icon.svg
gradle/libs.versions.toml
**/gradle-wrapper.properties
**/gradle.properties
gradle.properties
gradlew
gradlew.bat
**/proguard-rules.pro
*.xml
*.webp
*.png
*.config
*.jar
*.md
*.txt
*.yml
*.yaml
*.json
Package.swift
**/Package.swift
Package@-*.swift
**/Package@-*.swift
Package.resolved
**/Package.resolved
Makefile
*.modulemap
**/*.modulemap
**/*.docc/*
*.xcprivacy
**/*.xcprivacy
*.symlink
**/*.symlink
Dockerfile
**/Dockerfile
Snippets/*
dev/git.commit.template
*.crt
**/*.crt
*.pem
**/*.pem
*.der
**/*.der
native-app-glue/Sources/AndroidNativeAppGlue/android_native_app_glue.c
native-app-glue/Sources/AndroidNativeAppGlue/include/android_native_app_glue.h
6 changes: 6 additions & 0 deletions .spi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 1
external_links:
documentation: "https://docs.swift.org/android/documentation/android"
builder:
configs:
- documentation_targets: [SwiftAndroid]
5 changes: 5 additions & 0 deletions .swift-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"AlwaysUseLowerCamelCase": false
}
}
2 changes: 2 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import PackageDescription

// Note that this product exists purely to build documentation:
// swift package generate-documentation --target SwiftAndroid --transform-for-static-hosting --output-path dos
let package = Package(
name: "swift-android-examples",
products: [
Expand Down
14 changes: 14 additions & 0 deletions Sources/SwiftAndroid/Empty.swift
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2026 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

// This file is included so SwiftPM considers the target to be a Swift target.
16 changes: 15 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2026 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.android.library) apply false
}
}
14 changes: 14 additions & 0 deletions hello-cpp-swift/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2026 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
Expand Down
Loading