diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f91c3d9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,241 @@ +name: ci + +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 + + - 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 + 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 diff --git a/.github/workflows/soundness.yml b/.github/workflows/soundness.yml new file mode 100644 index 0000000..3822fb6 --- /dev/null +++ b/.github/workflows/soundness.yml @@ -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" diff --git a/.licenseignore b/.licenseignore new file mode 100644 index 0000000..fdc5728 --- /dev/null +++ b/.licenseignore @@ -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 diff --git a/.spi.yml b/.spi.yml new file mode 100644 index 0000000..589a5d4 --- /dev/null +++ b/.spi.yml @@ -0,0 +1,6 @@ +version: 1 +external_links: + documentation: "https://docs.swift.org/android/documentation/android" +builder: + configs: + - documentation_targets: [SwiftAndroid] diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..fafb52b --- /dev/null +++ b/.swift-format @@ -0,0 +1,5 @@ +{ + "rules": { + "AlwaysUseLowerCamelCase": false + } +} diff --git a/Package.swift b/Package.swift index 5b071ee..77c4246 100644 --- a/Package.swift +++ b/Package.swift @@ -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: [ diff --git a/Sources/SwiftAndroid/Empty.swift b/Sources/SwiftAndroid/Empty.swift index 114df8d..e64de9d 100644 --- a/Sources/SwiftAndroid/Empty.swift +++ b/Sources/SwiftAndroid/Empty.swift @@ -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. diff --git a/build.gradle.kts b/build.gradle.kts index ecf7a23..24598f0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -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 -} \ No newline at end of file +} diff --git a/hello-cpp-swift/app/build.gradle.kts b/hello-cpp-swift/app/build.gradle.kts index ec92bcb..fb58dc6 100644 --- a/hello-cpp-swift/app/build.gradle.kts +++ b/hello-cpp-swift/app/build.gradle.kts @@ -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) diff --git a/hello-cpp-swift/app/src/main/java/com/example/hellocppswift/MainActivity.kt b/hello-cpp-swift/app/src/main/java/com/example/hellocppswift/MainActivity.kt index 63d5356..a064d95 100644 --- a/hello-cpp-swift/app/src/main/java/com/example/hellocppswift/MainActivity.kt +++ b/hello-cpp-swift/app/src/main/java/com/example/hellocppswift/MainActivity.kt @@ -1,3 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// package com.example.hellocppswift import android.os.Bundle diff --git a/hello-cpp-swift/cpp-lib/build-android-static.sh b/hello-cpp-swift/cpp-lib/build-android-static.sh index cb75c4a..499e23a 100755 --- a/hello-cpp-swift/cpp-lib/build-android-static.sh +++ b/hello-cpp-swift/cpp-lib/build-android-static.sh @@ -1,4 +1,17 @@ #!/bin/bash +##===----------------------------------------------------------------------===## +## +## 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 +## +##===----------------------------------------------------------------------===## set -e diff --git a/hello-cpp-swift/cpp-lib/include/calculator.h b/hello-cpp-swift/cpp-lib/include/calculator.h index c84b9ae..4464cb6 100644 --- a/hello-cpp-swift/cpp-lib/include/calculator.h +++ b/hello-cpp-swift/cpp-lib/include/calculator.h @@ -1,3 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// #ifndef CALCULATOR_H #define CALCULATOR_H diff --git a/hello-cpp-swift/cpp-lib/src/calculator.cpp b/hello-cpp-swift/cpp-lib/src/calculator.cpp index ec000c3..bf1665c 100644 --- a/hello-cpp-swift/cpp-lib/src/calculator.cpp +++ b/hello-cpp-swift/cpp-lib/src/calculator.cpp @@ -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 +// +//===----------------------------------------------------------------------===// + #include "calculator.h" int add(int a, int b) { diff --git a/hello-cpp-swift/swift-lib/Package.swift b/hello-cpp-swift/swift-lib/Package.swift index b58d4cf..681b9aa 100644 --- a/hello-cpp-swift/swift-lib/Package.swift +++ b/hello-cpp-swift/swift-lib/Package.swift @@ -13,7 +13,7 @@ let package = Package( targets: ["HelloCppSwift"]) ], dependencies: [ - .package(url: "https://github.com/swiftlang/swift-java", from: "0.1.2"), + .package(url: "https://github.com/swiftlang/swift-java", from: "0.1.2") ], targets: [ .binaryTarget( @@ -27,7 +27,7 @@ let package = Package( .product(name: "SwiftJava", package: "swift-java"), ], swiftSettings: [ - .swiftLanguageMode(.v5), + .swiftLanguageMode(.v5) ], plugins: [ .plugin(name: "JExtractSwiftPlugin", package: "swift-java") diff --git a/hello-cpp-swift/swift-lib/Sources/HelloCppSwift/Calculator.swift b/hello-cpp-swift/swift-lib/Sources/HelloCppSwift/Calculator.swift index 494ad99..fb8b7a5 100644 --- a/hello-cpp-swift/swift-lib/Sources/HelloCppSwift/Calculator.swift +++ b/hello-cpp-swift/swift-lib/Sources/HelloCppSwift/Calculator.swift @@ -1,14 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// #if canImport(FoundationEssentials) -import FoundationEssentials + import FoundationEssentials #else -import Foundation + import Foundation #endif import HelloWorldCpp public func addNumbers(_ a: Int32, _ b: Int32) -> Int32 { - return add(a, b) + return add(a, b) } public func multiplyNumbers(_ a: Int32, _ b: Int32) -> Int32 { - return multiply(a, b) + return multiply(a, b) } diff --git a/hello-cpp-swift/swift-lib/build.gradle b/hello-cpp-swift/swift-lib/build.gradle index 63b2fb8..2d75bb4 100644 --- a/hello-cpp-swift/swift-lib/build.gradle +++ b/hello-cpp-swift/swift-lib/build.gradle @@ -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 +// +//===----------------------------------------------------------------------===// + import java.nio.file.* plugins { @@ -89,8 +103,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 = [ @@ -125,7 +146,7 @@ abis.each { abi, info -> workingDir = layout.projectDirectory executable(getSwiftlyPath()) - args("run", "swift", "build", "+${swiftVersion}", "--swift-sdk", info.triple) + args("run", "swift", "build", "+${swiftVersion}", "--swift-sdk", info.triple, "--build-system", "native") } buildSwiftAll.configure { dependsOn(task) } diff --git a/hello-swift-java/hashing-app/build.gradle.kts b/hello-swift-java/hashing-app/build.gradle.kts index e087f09..d45d66f 100644 --- a/hello-swift-java/hashing-app/build.gradle.kts +++ b/hello-swift-java/hashing-app/build.gradle.kts @@ -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) diff --git a/hello-swift-java/hashing-app/src/androidTest/java/com/example/hashingapp/ExampleInstrumentedTest.kt b/hello-swift-java/hashing-app/src/androidTest/java/com/example/hashingapp/ExampleInstrumentedTest.kt index 1bcc13c..4ab5ebb 100644 --- a/hello-swift-java/hashing-app/src/androidTest/java/com/example/hashingapp/ExampleInstrumentedTest.kt +++ b/hello-swift-java/hashing-app/src/androidTest/java/com/example/hashingapp/ExampleInstrumentedTest.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -33,4 +35,4 @@ class ExampleInstrumentedTest { val appContext = InstrumentationRegistry.getInstrumentation().targetContext assertEquals("com.example.hashingapp", appContext.packageName) } -} \ No newline at end of file +} diff --git a/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/MainActivity.kt b/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/MainActivity.kt index 24cd5c8..a9f343a 100644 --- a/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/MainActivity.kt +++ b/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/MainActivity.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -91,4 +93,4 @@ fun HashScreen() { ) } } -} \ No newline at end of file +} diff --git a/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Color.kt b/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Color.kt index f5705ba..2128565 100644 --- a/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Color.kt +++ b/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Color.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -20,4 +22,4 @@ val Pink80 = Color(0xFFEFB8C8) val Purple40 = Color(0xFF6650a4) val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file +val Pink40 = Color(0xFF7D5260) diff --git a/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Theme.kt b/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Theme.kt index 8c20865..b87b288 100644 --- a/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Theme.kt +++ b/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Theme.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -67,4 +69,4 @@ fun HashingAppTheme( typography = Typography, content = content ) -} \ No newline at end of file +} diff --git a/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Type.kt b/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Type.kt index 336c677..8634ed4 100644 --- a/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Type.kt +++ b/hello-swift-java/hashing-app/src/main/java/com/example/hashingapp/ui/theme/Type.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -43,4 +45,4 @@ val Typography = Typography( letterSpacing = 0.5.sp ) */ -) \ No newline at end of file +) diff --git a/hello-swift-java/hashing-app/src/test/java/com/example/hashingapp/ExampleUnitTest.kt b/hello-swift-java/hashing-app/src/test/java/com/example/hashingapp/ExampleUnitTest.kt index 1c94d5d..cf1079c 100644 --- a/hello-swift-java/hashing-app/src/test/java/com/example/hashingapp/ExampleUnitTest.kt +++ b/hello-swift-java/hashing-app/src/test/java/com/example/hashingapp/ExampleUnitTest.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -26,4 +28,4 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } -} \ No newline at end of file +} diff --git a/hello-swift-java/hashing-lib/Package.swift b/hello-swift-java/hashing-lib/Package.swift index 9719605..d2c36ba 100644 --- a/hello-swift-java/hashing-lib/Package.swift +++ b/hello-swift-java/hashing-lib/Package.swift @@ -23,10 +23,10 @@ let package = Package( name: "SwiftHashing", dependencies: [ .product(name: "Crypto", package: "swift-crypto"), - .product(name: "SwiftJava", package: "swift-java") + .product(name: "SwiftJava", package: "swift-java"), ], swiftSettings: [ - .swiftLanguageMode(.v5), + .swiftLanguageMode(.v5) ], plugins: [ .plugin(name: "JExtractSwiftPlugin", package: "swift-java") diff --git a/hello-swift-java/hashing-lib/Sources/SwiftHashing/SwiftHashing.swift b/hello-swift-java/hashing-lib/Sources/SwiftHashing/SwiftHashing.swift index f6565b1..f38ae2e 100644 --- a/hello-swift-java/hashing-lib/Sources/SwiftHashing/SwiftHashing.swift +++ b/hello-swift-java/hashing-lib/Sources/SwiftHashing/SwiftHashing.swift @@ -2,21 +2,23 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// import Crypto #if canImport(FoundationEssentials) -import FoundationEssentials + import FoundationEssentials #else -import Foundation + import Foundation #endif public func hash(_ input: String) -> String { - SHA256.hash(data: Data(input.utf8)).description + SHA256.hash(data: Data(input.utf8)).description } diff --git a/hello-swift-java/hashing-lib/Tests/SwiftHashingTests/SwiftHashingTests.swift b/hello-swift-java/hashing-lib/Tests/SwiftHashingTests/SwiftHashingTests.swift index 6a4b429..908cc06 100644 --- a/hello-swift-java/hashing-lib/Tests/SwiftHashingTests/SwiftHashingTests.swift +++ b/hello-swift-java/hashing-lib/Tests/SwiftHashingTests/SwiftHashingTests.swift @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -14,5 +16,7 @@ import Testing @testable import SwiftHashing @Test func hashing() throws { - #expect(hash("Hello from Swift!") == "SHA256 digest: a642e7aa389325056cdf5e54a2b6e0a0214b4810fe87e1370063d9e17f8d6ed6") + #expect( + hash("Hello from Swift!") + == "SHA256 digest: a642e7aa389325056cdf5e54a2b6e0a0214b4810fe87e1370063d9e17f8d6ed6") } diff --git a/hello-swift-java/hashing-lib/build.gradle b/hello-swift-java/hashing-lib/build.gradle index 9fd45a7..29f75bc 100644 --- a/hello-swift-java/hashing-lib/build.gradle +++ b/hello-swift-java/hashing-lib/build.gradle @@ -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 +// +//===----------------------------------------------------------------------===// + import java.nio.file.* import org.gradle.internal.os.OperatingSystem import groovy.json.JsonSlurper @@ -99,8 +113,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 @@ -138,7 +159,7 @@ abis.each { abi, info -> workingDir = layout.projectDirectory executable(getSwiftlyPath()) - args("run", "swift", "build", "+${swiftVersion}", "--swift-sdk", info.triple) + args("run", "swift", "build", "+${swiftVersion}", "--swift-sdk", info.triple, "--build-system", "native") } buildSwiftAll.configure { dependsOn(task) } @@ -190,4 +211,4 @@ android { } // Make sure we run our tasks before build -preBuild.dependsOn(copyJniLibs) \ No newline at end of file +preBuild.dependsOn(copyJniLibs) diff --git a/hello-swift-raw-jni-callback/build.gradle.kts b/hello-swift-raw-jni-callback/build.gradle.kts index 4ff1f49..5b189a7 100644 --- a/hello-swift-raw-jni-callback/build.gradle.kts +++ b/hello-swift-raw-jni-callback/build.gradle.kts @@ -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) @@ -45,4 +59,4 @@ dependencies { implementation(libs.androidx.appcompat) implementation(libs.material) implementation(libs.androidx.constraintlayout) -} \ No newline at end of file +} diff --git a/hello-swift-raw-jni-callback/src/main/java/org/example/helloswift/MainActivity.kt b/hello-swift-raw-jni-callback/src/main/java/org/example/helloswift/MainActivity.kt index 69a49a1..bf9471e 100644 --- a/hello-swift-raw-jni-callback/src/main/java/org/example/helloswift/MainActivity.kt +++ b/hello-swift-raw-jni-callback/src/main/java/org/example/helloswift/MainActivity.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// diff --git a/hello-swift-raw-jni-callback/src/main/swift/Package.swift b/hello-swift-raw-jni-callback/src/main/swift/Package.swift index 84c2b44..806417b 100644 --- a/hello-swift-raw-jni-callback/src/main/swift/Package.swift +++ b/hello-swift-raw-jni-callback/src/main/swift/Package.swift @@ -4,11 +4,13 @@ import PackageDescription let package = Package( - name: "hello-swift-raw-jni-callback", - products: [ - .library(name: "hello-swift-raw-jni-callback", type: .dynamic, targets: ["hello-swift-raw-jni-callback"]), - ], - targets: [ - .target(name: "hello-swift-raw-jni-callback") - ] + name: "hello-swift-raw-jni-callback", + products: [ + .library( + name: "hello-swift-raw-jni-callback", type: .dynamic, + targets: ["hello-swift-raw-jni-callback"]) + ], + targets: [ + .target(name: "hello-swift-raw-jni-callback") + ] ) diff --git a/hello-swift-raw-jni-callback/src/main/swift/Sources/hello-swift-callback/hello-swift-callback.swift b/hello-swift-raw-jni-callback/src/main/swift/Sources/hello-swift-callback/hello-swift-callback.swift index 2e76e4f..76fe075 100644 --- a/hello-swift-raw-jni-callback/src/main/swift/Sources/hello-swift-callback/hello-swift-callback.swift +++ b/hello-swift-raw-jni-callback/src/main/swift/Sources/hello-swift-callback/hello-swift-callback.swift @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -17,17 +19,19 @@ import Dispatch private var gJavaVM: UnsafeMutablePointer? @_cdecl("JNI_OnLoad") -public func JNI_OnLoad(vm: UnsafeMutablePointer, reserved: UnsafeMutableRawPointer?) -> jint { - gJavaVM = vm - return jint(JNI_VERSION_1_6) +public func JNI_OnLoad(vm: UnsafeMutablePointer, reserved: UnsafeMutableRawPointer?) + -> jint +{ + gJavaVM = vm + return jint(JNI_VERSION_1_6) } struct JGlobalObject: @unchecked Sendable { - let ref: jobject + let ref: jobject } struct JMethodID: @unchecked Sendable { - let id: jmethodID + let id: jmethodID } let queue = DispatchQueue(label: "hello-swift-raw-jni-callback") @@ -35,46 +39,46 @@ var workItem: DispatchWorkItem? = nil var activityRef: jobject? = nil private func getEnvForCurrentThread(block: (UnsafeMutablePointer?) -> Void) { - var env: UnsafeMutablePointer? - let attachCode = gJavaVM!.pointee!.pointee.AttachCurrentThread(gJavaVM, &env, nil) - guard attachCode == 0 else { return } - block(env) - _ = gJavaVM!.pointee!.pointee.DetachCurrentThread(gJavaVM) + var env: UnsafeMutablePointer? + let attachCode = gJavaVM!.pointee!.pointee.AttachCurrentThread(gJavaVM, &env, nil) + guard attachCode == 0 else { return } + block(env) + _ = gJavaVM!.pointee!.pointee.DetachCurrentThread(gJavaVM) } @_cdecl("Java_org_example_helloswift_MainActivity_startTicks") public func MainActivity_startTicks(env: UnsafeMutablePointer, thiz: jobject) { - guard let globalRef = env.pointee!.pointee.NewGlobalRef(env, thiz) else { return } - guard let cls = env.pointee!.pointee.GetObjectClass(env, thiz) else { return } - defer { env.pointee!.pointee.DeleteLocalRef(env, cls) } - guard let mid = env.pointee!.pointee.GetMethodID(env, cls, "updateTimer", "()V") else { return } + guard let globalRef = env.pointee!.pointee.NewGlobalRef(env, thiz) else { return } + guard let cls = env.pointee!.pointee.GetObjectClass(env, thiz) else { return } + defer { env.pointee!.pointee.DeleteLocalRef(env, cls) } + guard let mid = env.pointee!.pointee.GetMethodID(env, cls, "updateTimer", "()V") else { return } - let activityHandle = JGlobalObject(ref: globalRef) - let methodHandle = JMethodID(id: mid) + let activityHandle = JGlobalObject(ref: globalRef) + let methodHandle = JMethodID(id: mid) - queue.async { - workItem?.cancel() - workItem = DispatchWorkItem { - getEnvForCurrentThread { env in - env?.pointee!.pointee.CallVoidMethodA(env, activityHandle.ref, methodHandle.id, nil) - } - if let workItem = workItem, workItem.isCancelled == false { - queue.asyncAfter(deadline: .now() + 1, execute: workItem) - } - } - queue.async(execute: workItem!) + queue.async { + workItem?.cancel() + workItem = DispatchWorkItem { + getEnvForCurrentThread { env in + env?.pointee!.pointee.CallVoidMethodA(env, activityHandle.ref, methodHandle.id, nil) + } + if let workItem = workItem, workItem.isCancelled == false { + queue.asyncAfter(deadline: .now() + 1, execute: workItem) + } } + queue.async(execute: workItem!) + } } @_cdecl("Java_org_example_helloswift_MainActivity_stopTicks") public func MainActivity_stopTicks(env: UnsafeMutablePointer, jthis: jobject) { - queue.async { - workItem?.cancel() - workItem = nil - if let activityRef = activityRef { - getEnvForCurrentThread { env in - env?.pointee!.pointee.DeleteGlobalRef(env, activityRef) - } - } + queue.async { + workItem?.cancel() + workItem = nil + if let activityRef = activityRef { + getEnvForCurrentThread { env in + env?.pointee!.pointee.DeleteGlobalRef(env, activityRef) + } } + } } diff --git a/hello-swift-raw-jni-library/build.gradle.kts b/hello-swift-raw-jni-library/build.gradle.kts index d81a9f1..ef33d31 100644 --- a/hello-swift-raw-jni-library/build.gradle.kts +++ b/hello-swift-raw-jni-library/build.gradle.kts @@ -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.library) alias(libs.plugins.kotlin.android) @@ -42,4 +56,4 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) -} \ No newline at end of file +} diff --git a/hello-swift-raw-jni-library/src/androidTest/java/org/example/swiftlibrary/SwiftLibraryTest.kt b/hello-swift-raw-jni-library/src/androidTest/java/org/example/swiftlibrary/SwiftLibraryTest.kt index a70905f..a437a8c 100644 --- a/hello-swift-raw-jni-library/src/androidTest/java/org/example/swiftlibrary/SwiftLibraryTest.kt +++ b/hello-swift-raw-jni-library/src/androidTest/java/org/example/swiftlibrary/SwiftLibraryTest.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// diff --git a/hello-swift-raw-jni-library/src/main/java/org/example/swiftlibrary/SwiftLibrary.kt b/hello-swift-raw-jni-library/src/main/java/org/example/swiftlibrary/SwiftLibrary.kt index 4298b84..5db93e6 100644 --- a/hello-swift-raw-jni-library/src/main/java/org/example/swiftlibrary/SwiftLibrary.kt +++ b/hello-swift-raw-jni-library/src/main/java/org/example/swiftlibrary/SwiftLibrary.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// diff --git a/hello-swift-raw-jni-library/src/main/swift/Package.swift b/hello-swift-raw-jni-library/src/main/swift/Package.swift index ad9d3b4..ce70ef2 100644 --- a/hello-swift-raw-jni-library/src/main/swift/Package.swift +++ b/hello-swift-raw-jni-library/src/main/swift/Package.swift @@ -4,11 +4,12 @@ import PackageDescription let package = Package( - name: "hello-swift-raw-jni-library", - products: [ - .library(name: "hello-swift-raw-jni-library", type: .dynamic, targets: ["hello-swift-raw-jni-library"]), - ], - targets: [ - .target(name: "hello-swift-raw-jni-library") - ] + name: "hello-swift-raw-jni-library", + products: [ + .library( + name: "hello-swift-raw-jni-library", type: .dynamic, targets: ["hello-swift-raw-jni-library"]) + ], + targets: [ + .target(name: "hello-swift-raw-jni-library") + ] ) diff --git a/hello-swift-raw-jni-library/src/main/swift/Sources/helloswift/helloswift.swift b/hello-swift-raw-jni-library/src/main/swift/Sources/helloswift/helloswift.swift index d943e8e..b63f108 100644 --- a/hello-swift-raw-jni-library/src/main/swift/Sources/helloswift/helloswift.swift +++ b/hello-swift-raw-jni-library/src/main/swift/Sources/helloswift/helloswift.swift @@ -2,20 +2,24 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// import Android @_cdecl("Java_org_example_swiftlibrary_SwiftLibrary_stringFromSwift") -public func SwiftLibrary_stringFromSwift(env: UnsafeMutablePointer, clazz: jclass) -> jstring { - let hello = "Hello from Swift" - return hello.withCString { ptr in - env.pointee!.pointee.NewStringUTF(env, ptr)! - } +public func SwiftLibrary_stringFromSwift(env: UnsafeMutablePointer, clazz: jclass) + -> jstring +{ + let hello = "Hello from Swift" + return hello.withCString { ptr in + env.pointee!.pointee.NewStringUTF(env, ptr)! + } } diff --git a/hello-swift-raw-jni/build.gradle.kts b/hello-swift-raw-jni/build.gradle.kts index 2eb9582..96c6582 100644 --- a/hello-swift-raw-jni/build.gradle.kts +++ b/hello-swift-raw-jni/build.gradle.kts @@ -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) @@ -47,4 +61,4 @@ dependencies { implementation(libs.androidx.appcompat) implementation(libs.material) implementation(libs.androidx.constraintlayout) -} \ No newline at end of file +} diff --git a/hello-swift-raw-jni/src/main/java/org/example/helloswift/MainActivity.kt b/hello-swift-raw-jni/src/main/java/org/example/helloswift/MainActivity.kt index c864dbf..4b5d374 100644 --- a/hello-swift-raw-jni/src/main/java/org/example/helloswift/MainActivity.kt +++ b/hello-swift-raw-jni/src/main/java/org/example/helloswift/MainActivity.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// diff --git a/hello-swift-raw-jni/src/main/swift/Package.swift b/hello-swift-raw-jni/src/main/swift/Package.swift index a039d87..a46960e 100644 --- a/hello-swift-raw-jni/src/main/swift/Package.swift +++ b/hello-swift-raw-jni/src/main/swift/Package.swift @@ -4,11 +4,11 @@ import PackageDescription let package = Package( - name: "helloswift", - products: [ - .library(name: "helloswift", type: .dynamic, targets: ["helloswift"]), - ], - targets: [ - .target(name: "helloswift") - ] + name: "helloswift", + products: [ + .library(name: "helloswift", type: .dynamic, targets: ["helloswift"]) + ], + targets: [ + .target(name: "helloswift") + ] ) diff --git a/hello-swift-raw-jni/src/main/swift/Sources/helloswift/helloswift.swift b/hello-swift-raw-jni/src/main/swift/Sources/helloswift/helloswift.swift index b7cd274..968af5e 100644 --- a/hello-swift-raw-jni/src/main/swift/Sources/helloswift/helloswift.swift +++ b/hello-swift-raw-jni/src/main/swift/Sources/helloswift/helloswift.swift @@ -2,20 +2,24 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// import Android @_cdecl("Java_org_example_helloswift_MainActivity_stringFromSwift") -public func MainActivity_stringFromSwift(env: UnsafeMutablePointer, clazz: jclass) -> jstring { - let hello = ["Hello", "from", "Swift", "❤️"].joined(separator: " ") - return hello.withCString { ptr in - env.pointee!.pointee.NewStringUTF(env, ptr)! - } +public func MainActivity_stringFromSwift(env: UnsafeMutablePointer, clazz: jclass) + -> jstring +{ + let hello = ["Hello", "from", "Swift", "❤️"].joined(separator: " ") + return hello.withCString { ptr in + env.pointee!.pointee.NewStringUTF(env, ptr)! + } } diff --git a/native-activity/build.gradle.kts b/native-activity/build.gradle.kts index a1c439a..5bb8cde 100644 --- a/native-activity/build.gradle.kts +++ b/native-activity/build.gradle.kts @@ -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) @@ -26,4 +40,4 @@ android { isJniDebuggable = false } } -} \ No newline at end of file +} diff --git a/native-activity/src/main/swift/Package.swift b/native-activity/src/main/swift/Package.swift index eab71ff..62ca26d 100644 --- a/native-activity/src/main/swift/Package.swift +++ b/native-activity/src/main/swift/Package.swift @@ -4,26 +4,26 @@ import PackageDescription let package = Package( - name: "native-activity", - products: [ - .library(name: "native-activity", type: .dynamic, targets: ["native-activity"]), - ], - dependencies: [ - .package(path: "../../../../native-app-glue") - ], - targets: [ - .target( - name: "native-activity", - dependencies: [ - .product(name: "AndroidNativeAppGlue", package: "native-app-glue"), - .product(name: "AndroidOpenGL", package: "native-app-glue") - ], - linkerSettings: [ - .linkedLibrary("android"), - .linkedLibrary("EGL"), - .linkedLibrary("GLESv1_CM"), - .linkedLibrary("log") - ] - ) - ] + name: "native-activity", + products: [ + .library(name: "native-activity", type: .dynamic, targets: ["native-activity"]) + ], + dependencies: [ + .package(path: "../../../../native-app-glue") + ], + targets: [ + .target( + name: "native-activity", + dependencies: [ + .product(name: "AndroidNativeAppGlue", package: "native-app-glue"), + .product(name: "AndroidOpenGL", package: "native-app-glue"), + ], + linkerSettings: [ + .linkedLibrary("android"), + .linkedLibrary("EGL"), + .linkedLibrary("GLESv1_CM"), + .linkedLibrary("log"), + ] + ) + ] ) diff --git a/native-activity/src/main/swift/Sources/native-activity/native-activity.swift b/native-activity/src/main/swift/Sources/native-activity/native-activity.swift index 1dc27d0..3677d71 100644 --- a/native-activity/src/main/swift/Sources/native-activity/native-activity.swift +++ b/native-activity/src/main/swift/Sources/native-activity/native-activity.swift @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -15,247 +17,248 @@ import AndroidNativeAppGlue import AndroidOpenGL public struct SavedState { - public var angle: Float = 0 - public var x: Int32 = 0 - public var y: Int32 = 0 + public var angle: Float = 0 + public var x: Int32 = 0 + public var y: Int32 = 0 } public final class Engine { - public var app: UnsafeMutablePointer? - - public var display: EGLDisplay? - public var surface: EGLSurface? - public var context: EGLContext? - public var width: Int32 = 0 - public var height: Int32 = 0 - public var state = SavedState() - - private var running_ = false - - public init(app: UnsafeMutablePointer?) { - self.app = app - } - - /** - * Initialize an EGL context for the current display. + public var app: UnsafeMutablePointer? + + public var display: EGLDisplay? + public var surface: EGLSurface? + public var context: EGLContext? + public var width: Int32 = 0 + public var height: Int32 = 0 + public var state = SavedState() + + private var running_ = false + + public init(app: UnsafeMutablePointer?) { + self.app = app + } + + /** + * Initialize an EGL context for the current display. + */ + public func initDisplay() -> Int32 { + guard let win = app?.pointee.window else { return -1 } + // initialize OpenGL ES and EGL + + /* + * Here specify the attributes of the desired configuration. + * Below, we select an EGLConfig with at least 8 bits per color + * component compatible with on-screen windows */ - public func initDisplay() -> Int32 { - guard let win = app?.pointee.window else { return -1 } - // initialize OpenGL ES and EGL - - /* - * Here specify the attributes of the desired configuration. - * Below, we select an EGLConfig with at least 8 bits per color - * component compatible with on-screen windows - */ - let attribs: [EGLint] = [ - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_BLUE_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_RED_SIZE, 8, - EGL_NONE - ] - - let display: EGLDisplay! = eglGetDisplay(nil) - _ = eglInitialize(display, nil, nil) - - var numConfigs: EGLint = 0 - _ = eglChooseConfig(display, attribs, nil, 0, &numConfigs) - if numConfigs <= 0 { return -1 } - let cfgBuf = UnsafeMutablePointer.allocate(capacity: Int(numConfigs)) - defer { cfgBuf.deallocate() } - - /* Here, the application chooses the configuration it desires. - * find the best match if possible, otherwise use the very first one - */ - _ = eglChooseConfig(display, attribs, cfgBuf, numConfigs, &numConfigs) - - // Pick the best match: R=G=B=8, DEPTH=0 - var chosen: EGLConfig? = nil - for i in 0...allocate(capacity: Int(numConfigs)) + defer { cfgBuf.deallocate() } + + /* Here, the application chooses the configuration it desires. + * find the best match if possible, otherwise use the very first one + */ + _ = eglChooseConfig(display, attribs, cfgBuf, numConfigs, &numConfigs) + + // Pick the best match: R=G=B=8, DEPTH=0 + var chosen: EGLConfig? = nil + for i in 0.. 1 { - state.angle = 0 - } + } + + /// Pauses ticking the application (Choreographer). + public func pause() { + running_ = false + } + + /** + * Tear down the EGL context currently associated with the display. + */ + public func termDisplay() { + if let dpy = self.display { + _ = eglMakeCurrent(dpy, nil, nil, nil) + if let ctx = self.context { + _ = eglDestroyContext(dpy, ctx) + } + if let surf = self.surface { + _ = eglDestroySurface(dpy, surf) + } + _ = eglTerminate(dpy) + } + self.pause() + self.display = nil + self.context = nil + self.surface = nil + } + + private func scheduleNextTick() { + let choreo = AChoreographer_getInstance() + AChoreographer_postFrameCallback(choreo, Engine_Tick, Unmanaged.passUnretained(self).toOpaque()) + } + + fileprivate func doTick() { + guard running_ else { return } + + // Choreographer does not continuously schedule the callback. We have to re- + // register the callback each time we're ticked. + scheduleNextTick() + update() + drawFrame() + } + + private func update() { + state.angle += 0.01 + if state.angle > 1 { + state.angle = 0 } + } - private func drawFrame() { - guard display != nil, surface != nil else { - // No display/surface yet. - return - } + private func drawFrame() { + guard display != nil, surface != nil else { + // No display/surface yet. + return + } - // Just fill the screen with a color - let r = Float(state.x) / Float(max(1, width)) - let g = Float(state.y) / Float(max(1, height)) - let b = state.angle + // Just fill the screen with a color + let r = Float(state.x) / Float(max(1, width)) + let g = Float(state.y) / Float(max(1, height)) + let b = state.angle - glClearColor(r, g, b, 1) - glClear(GLbitfield(GL_COLOR_BUFFER_BIT)) + glClearColor(r, g, b, 1) + glClear(GLbitfield(GL_COLOR_BUFFER_BIT)) - _ = eglSwapBuffers(display, surface) - } + _ = eglSwapBuffers(display, surface) + } } @_cdecl("Engine_Tick") public func Engine_Tick(_ frameTimeNanos: Int, _ data: UnsafeMutableRawPointer?) { - guard let data else { return } - let engine = Unmanaged.fromOpaque(data).takeUnretainedValue() - engine.doTick() + guard let data else { return } + let engine = Unmanaged.fromOpaque(data).takeUnretainedValue() + engine.doTick() } @_silgen_name("android_main") public func android_main(_ app: UnsafeMutablePointer) { - let engine = Engine(app: app) - app.pointee.userData = Unmanaged.passRetained(engine).toOpaque() - - app.pointee.onAppCmd = { app, cmd in - // unwrap the optional android_app* and userData - guard let opaque = app?.pointee.userData else { return } - - // turn void* back into Engine - let engine = Unmanaged.fromOpaque(opaque).takeUnretainedValue() - - switch Int(cmd) { - case APP_CMD_INIT_WINDOW: - _ = engine.initDisplay() - case APP_CMD_TERM_WINDOW: - engine.termDisplay() - case APP_CMD_GAINED_FOCUS: - engine.resume() - case APP_CMD_LOST_FOCUS: - engine.pause() - default: - print("Unsupported command \(cmd)") - } + let engine = Engine(app: app) + app.pointee.userData = Unmanaged.passRetained(engine).toOpaque() + + app.pointee.onAppCmd = { app, cmd in + // unwrap the optional android_app* and userData + guard let opaque = app?.pointee.userData else { return } + + // turn void* back into Engine + let engine = Unmanaged.fromOpaque(opaque).takeUnretainedValue() + + switch Int(cmd) { + case APP_CMD_INIT_WINDOW: + _ = engine.initDisplay() + case APP_CMD_TERM_WINDOW: + engine.termDisplay() + case APP_CMD_GAINED_FOCUS: + engine.resume() + case APP_CMD_LOST_FOCUS: + engine.pause() + default: + print("Unsupported command \(cmd)") } + } - while app.pointee.destroyRequested == 0 { - var outData: UnsafeMutableRawPointer? = nil + while app.pointee.destroyRequested == 0 { + var outData: UnsafeMutableRawPointer? = nil - let r = ALooper_pollOnce(-1, nil, nil, &outData) - if r == ALOOPER_POLL_ERROR { - fatalError("ALooper_pollOnce returned an error") - } + let r = ALooper_pollOnce(-1, nil, nil, &outData) + if r == ALOOPER_POLL_ERROR { + fatalError("ALooper_pollOnce returned an error") + } - if let outData { - let source = outData.assumingMemoryBound(to: android_poll_source.self) - source.pointee.process(app, source) - } + if let outData { + let source = outData.assumingMemoryBound(to: android_poll_source.self) + source.pointee.process(app, source) } + } - engine.termDisplay() + engine.termDisplay() } diff --git a/native-app-glue/Package.swift b/native-app-glue/Package.swift index 7a96a86..5c9f120 100644 --- a/native-app-glue/Package.swift +++ b/native-app-glue/Package.swift @@ -4,14 +4,14 @@ import PackageDescription let package = Package( - name: "AndroidNativeAppGlue", - products: [ - .library(name: "AndroidNativeAppGlue", targets: ["AndroidNativeAppGlue"]), - .library(name: "AndroidOpenGL", targets: ["AndroidOpenGL"]) - ], - targets: [ - .target(name: "AndroidNativeAppGlue"), - .target(name: "AndroidOpenGL") - ], - cxxLanguageStandard: .cxx98 + name: "AndroidNativeAppGlue", + products: [ + .library(name: "AndroidNativeAppGlue", targets: ["AndroidNativeAppGlue"]), + .library(name: "AndroidOpenGL", targets: ["AndroidOpenGL"]), + ], + targets: [ + .target(name: "AndroidNativeAppGlue"), + .target(name: "AndroidOpenGL"), + ], + cxxLanguageStandard: .cxx98 ) diff --git a/native-app-glue/Sources/AndroidOpenGL/include/umbrella.h b/native-app-glue/Sources/AndroidOpenGL/include/umbrella.h index cff1295..5bc8c05 100644 --- a/native-app-glue/Sources/AndroidOpenGL/include/umbrella.h +++ b/native-app-glue/Sources/AndroidOpenGL/include/umbrella.h @@ -1,3 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 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 +// +//===----------------------------------------------------------------------===// + #include #include -#include \ No newline at end of file +#include diff --git a/settings.gradle.kts b/settings.gradle.kts index 74ae8b6..a4f557b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -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 +// +//===----------------------------------------------------------------------===// + pluginManagement { repositories { mavenLocal() diff --git a/swift-android.gradle.kts b/swift-android.gradle.kts index 37fa46a..f67b271 100644 --- a/swift-android.gradle.kts +++ b/swift-android.gradle.kts @@ -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 +// +//===----------------------------------------------------------------------===// + // File: swift-android.gradle.kts // Swift build script for Android projects using swiftly @@ -14,8 +28,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 @@ -134,6 +154,7 @@ fun createSwiftBuildTask( val defaultArgs = listOf( "run", "+${swiftVersion}", "swift", "build", "--swift-sdk", sdkName, + "--build-system", "native", // old build system until we can sort out the output paths "-Xswiftc", "-static-stdlib", "-Xswiftc", "-resource-dir", "-Xswiftc", resourcesPath @@ -296,4 +317,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 +} diff --git a/swift-java-weather-app/weather-app/build.gradle.kts b/swift-java-weather-app/weather-app/build.gradle.kts index 61d00b0..8c7d976 100644 --- a/swift-java-weather-app/weather-app/build.gradle.kts +++ b/swift-java-weather-app/weather-app/build.gradle.kts @@ -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) diff --git a/swift-java-weather-app/weather-app/src/androidTest/java/com/example/weatherapp/ExampleInstrumentedTest.kt b/swift-java-weather-app/weather-app/src/androidTest/java/com/example/weatherapp/ExampleInstrumentedTest.kt index 94455b3..04bfc50 100644 --- a/swift-java-weather-app/weather-app/src/androidTest/java/com/example/weatherapp/ExampleInstrumentedTest.kt +++ b/swift-java-weather-app/weather-app/src/androidTest/java/com/example/weatherapp/ExampleInstrumentedTest.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -33,4 +35,4 @@ class ExampleInstrumentedTest { val appContext = InstrumentationRegistry.getInstrumentation().targetContext assertEquals("com.example.weatherapp", appContext.packageName) } -} \ No newline at end of file +} diff --git a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/MainActivity.kt b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/MainActivity.kt index c773b4d..e7a520e 100644 --- a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/MainActivity.kt +++ b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/MainActivity.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -90,4 +92,4 @@ fun WeatherScreen(viewModel: WeatherViewModel, onFetchWeatherClick: () -> Unit) Text("Error: $it", color = MaterialTheme.colorScheme.error) } } -} \ No newline at end of file +} diff --git a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/services/LocationService.kt b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/services/LocationService.kt index 56ee7ca..b453ad4 100644 --- a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/services/LocationService.kt +++ b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/services/LocationService.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// diff --git a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Color.kt b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Color.kt index f9c0931..d161657 100644 --- a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Color.kt +++ b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Color.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -20,4 +22,4 @@ val Pink80 = Color(0xFFEFB8C8) val Purple40 = Color(0xFF6650a4) val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file +val Pink40 = Color(0xFF7D5260) diff --git a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Theme.kt b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Theme.kt index 61ed15c..1c9a2ba 100644 --- a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Theme.kt +++ b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Theme.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -67,4 +69,4 @@ fun WeatherAppTheme( typography = Typography, content = content ) -} \ No newline at end of file +} diff --git a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Type.kt b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Type.kt index 318c6f2..1893c2e 100644 --- a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Type.kt +++ b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/ui/theme/Type.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -43,4 +45,4 @@ val Typography = Typography( letterSpacing = 0.5.sp ) */ -) \ No newline at end of file +) diff --git a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/viewmodel/WeatherViewModel.kt b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/viewmodel/WeatherViewModel.kt index ec05e31..64d2f1e 100644 --- a/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/viewmodel/WeatherViewModel.kt +++ b/swift-java-weather-app/weather-app/src/main/java/com/example/weatherapp/viewmodel/WeatherViewModel.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// diff --git a/swift-java-weather-app/weather-app/src/test/java/com/example/weatherapp/ExampleUnitTest.kt b/swift-java-weather-app/weather-app/src/test/java/com/example/weatherapp/ExampleUnitTest.kt index 70b33de..1eec944 100644 --- a/swift-java-weather-app/weather-app/src/test/java/com/example/weatherapp/ExampleUnitTest.kt +++ b/swift-java-weather-app/weather-app/src/test/java/com/example/weatherapp/ExampleUnitTest.kt @@ -2,11 +2,13 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// @@ -26,4 +28,4 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } -} \ No newline at end of file +} diff --git a/swift-java-weather-app/weather-lib/Package.swift b/swift-java-weather-app/weather-lib/Package.swift index 0675e72..44ebee0 100644 --- a/swift-java-weather-app/weather-lib/Package.swift +++ b/swift-java-weather-app/weather-lib/Package.swift @@ -23,20 +23,24 @@ let package = Package( ], targets: [ .target( - name: "WeatherLibrary", - dependencies: [ - .product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"), - .product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession", condition: .when(platforms: [.macOS, .iOS])), - .product(name: "OpenAPIAsyncHTTPClient", package: "swift-openapi-async-http-client", condition: .when(platforms: [.android])), - .product(name: "SwiftJava", package: "swift-java") - ], - swiftSettings: [ - .swiftLanguageMode(.v5) - ], - plugins: [ - .plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator"), - .plugin(name: "JExtractSwiftPlugin", package: "swift-java") - ] + name: "WeatherLibrary", + dependencies: [ + .product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"), + .product( + name: "OpenAPIURLSession", package: "swift-openapi-urlsession", + condition: .when(platforms: [.macOS, .iOS])), + .product( + name: "OpenAPIAsyncHTTPClient", package: "swift-openapi-async-http-client", + condition: .when(platforms: [.android])), + .product(name: "SwiftJava", package: "swift-java"), + ], + swiftSettings: [ + .swiftLanguageMode(.v5) + ], + plugins: [ + .plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator"), + .plugin(name: "JExtractSwiftPlugin", package: "swift-java"), + ] ) ] ) diff --git a/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/LocationFetcher.swift b/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/LocationFetcher.swift index f7fcbcd..395daad 100644 --- a/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/LocationFetcher.swift +++ b/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/LocationFetcher.swift @@ -2,25 +2,27 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// public struct Location { - public let latitude: Double - public let longitude: Double + public let latitude: Double + public let longitude: Double - public init(latitude: Double, longitude: Double) { - self.latitude = latitude - self.longitude = longitude - } + public init(latitude: Double, longitude: Double) { + self.latitude = latitude + self.longitude = longitude + } } /// Responsible for fetching GPS locations public protocol LocationFetcher { - func currentLocation() -> Location + func currentLocation() -> Location } diff --git a/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherClient.swift b/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherClient.swift index a2cca67..9f4944d 100644 --- a/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherClient.swift +++ b/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherClient.swift @@ -2,68 +2,73 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// #if os(Android) -import OpenAPIAsyncHTTPClient + import OpenAPIAsyncHTTPClient #else -import OpenAPIURLSession + import OpenAPIURLSession #endif import OpenAPIRuntime import Foundation public final class WeatherClient { - private let client: Client - private let locationFetcher: any LocationFetcher - - public init(locationFetcher: any LocationFetcher) { - guard let serverURL = URL(string: "https://api.open-meteo.com") else { - fatalError("Could not create server URL.") - } + private let client: Client + private let locationFetcher: any LocationFetcher - self.locationFetcher = locationFetcher - self.client = Client( - serverURL: serverURL, - transport: WeatherClient.makeTransport() - ) + public init(locationFetcher: any LocationFetcher) { + guard let serverURL = URL(string: "https://api.open-meteo.com") else { + fatalError("Could not create server URL.") } - /// Fetches the current weather for a specific geographic location. - public func getWeather() async throws -> WeatherData { - let location = self.locationFetcher.currentLocation() - let response = try await client.getV1Forecast(.init(query: .init(latitude: location.latitude, longitude: location.longitude, currentWeather: true))) - - switch response { - case .ok(let okResponse): - switch okResponse.body { - case .json(let forecast): - guard let current = forecast.currentWeather else { - throw WeatherError.unexpectedResponse - } + self.locationFetcher = locationFetcher + self.client = Client( + serverURL: serverURL, + transport: WeatherClient.makeTransport() + ) + } - return WeatherData( - temperature: current.temperature, - windSpeed: current.windspeed, - windDirection: current.winddirection - ) - } + /// Fetches the current weather for a specific geographic location. + public func getWeather() async throws -> WeatherData { + let location = self.locationFetcher.currentLocation() + let response = try await client.getV1Forecast( + .init( + query: .init( + latitude: location.latitude, longitude: location.longitude, currentWeather: true))) - default: - throw WeatherError.apiError("Received an API error: \(response)") + switch response { + case .ok(let okResponse): + switch okResponse.body { + case .json(let forecast): + guard let current = forecast.currentWeather else { + throw WeatherError.unexpectedResponse } - } - private static func makeTransport() -> some ClientTransport { -#if os(Android) - return AsyncHTTPClientTransport(configuration: .init()) -#else - return URLSessionTransport() -#endif + return WeatherData( + temperature: current.temperature, + windSpeed: current.windspeed, + windDirection: current.winddirection + ) + } + + default: + throw WeatherError.apiError("Received an API error: \(response)") } + } + + private static func makeTransport() -> some ClientTransport { + #if os(Android) + return AsyncHTTPClientTransport(configuration: .init()) + #else + return URLSessionTransport() + #endif + } } diff --git a/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherData.swift b/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherData.swift index aae7946..76447ef 100644 --- a/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherData.swift +++ b/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherData.swift @@ -2,17 +2,19 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// /// Represents the current weather conditions for a specific location. public struct WeatherData: Hashable { - public let temperature: Double - public let windSpeed: Double - public let windDirection: Double + public let temperature: Double + public let windSpeed: Double + public let windDirection: Double } diff --git a/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherError.swift b/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherError.swift index 2659c47..64225c8 100644 --- a/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherError.swift +++ b/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/WeatherError.swift @@ -2,24 +2,26 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2025 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Copyright (c) 2025 Apple Inc. and the Swift.org project authors +// Licensed under Apache License v2.0 // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift.org project authors +// +// SPDX-License-Identifier: Apache-2.0 // //===----------------------------------------------------------------------===// public enum WeatherError: Error { - case apiError(String) - case unexpectedResponse + case apiError(String) + case unexpectedResponse - public var description: String { - switch self { - case .apiError(let message): - return "API Error: \(message)" - case .unexpectedResponse: - return "The server returned an invalid or unexpected response." - } + public var description: String { + switch self { + case .apiError(let message): + return "API Error: \(message)" + case .unexpectedResponse: + return "The server returned an invalid or unexpected response." } + } } diff --git a/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/openapi.yaml b/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/openapi.yaml index 2b4034f..b1a0595 100644 --- a/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/openapi.yaml +++ b/swift-java-weather-app/weather-lib/Sources/WeatherLibrary/openapi.yaml @@ -17,136 +17,136 @@ paths: - url: https://api.open-meteo.com get: tags: - - Weather Forecast APIs + - Weather Forecast APIs summary: 7 day weather forecast for coordinates description: 7 day weather variables in hourly and daily resolution for given WGS84 latitude and longitude coordinates. Available worldwide. parameters: - - name: hourly - in: query - explode: false - schema: - type: array - items: + - name: hourly + in: query + explode: false + schema: + type: array + items: + type: string + enum: + - temperature_2m + - relative_humidity_2m + - dew_point_2m + - apparent_temperature + - pressure_msl + - cloud_cover + - cloud_cover_low + - cloud_cover_mid + - cloud_cover_high + - wind_speed_10m + - wind_speed_80m + - wind_speed_120m + - wind_speed_180m + - wind_direction_10m + - wind_direction_80m + - wind_direction_120m + - wind_direction_180m + - wind_gusts_10m + - shortwave_radiation + - direct_radiation + - direct_normal_irradiance + - diffuse_radiation + - vapour_pressure_deficit + - evapotranspiration + - precipitation + - weather_code + - snow_height + - freezing_level_height + - soil_temperature_0cm + - soil_temperature_6cm + - soil_temperature_18cm + - soil_temperature_54cm + - soil_moisture_0_1cm + - soil_moisture_1_3cm + - soil_moisture_3_9cm + - soil_moisture_9_27cm + - soil_moisture_27_81cm + - name: daily + in: query + schema: + type: array + items: + type: string + enum: + - temperature_2m_max + - temperature_2m_min + - apparent_temperature_max + - apparent_temperature_min + - precipitation_sum + - precipitation_hours + - weather_code + - sunrise + - sunset + - wind_speed_10m_max + - wind_gusts_10m_max + - wind_direction_10m_dominant + - shortwave_radiation_sum + - uv_index_max + - uv_index_clear_sky_max + - et0_fao_evapotranspiration + - name: latitude + in: query + required: true + description: "WGS84 coordinate" + schema: + type: number + format: double + - name: longitude + in: query + required: true + description: "WGS84 coordinate" + schema: + type: number + format: double + - name: current_weather + in: query + schema: + type: boolean + - name: temperature_unit + in: query + schema: type: string + default: celsius enum: - - temperature_2m - - relative_humidity_2m - - dew_point_2m - - apparent_temperature - - pressure_msl - - cloud_cover - - cloud_cover_low - - cloud_cover_mid - - cloud_cover_high - - wind_speed_10m - - wind_speed_80m - - wind_speed_120m - - wind_speed_180m - - wind_direction_10m - - wind_direction_80m - - wind_direction_120m - - wind_direction_180m - - wind_gusts_10m - - shortwave_radiation - - direct_radiation - - direct_normal_irradiance - - diffuse_radiation - - vapour_pressure_deficit - - evapotranspiration - - precipitation - - weather_code - - snow_height - - freezing_level_height - - soil_temperature_0cm - - soil_temperature_6cm - - soil_temperature_18cm - - soil_temperature_54cm - - soil_moisture_0_1cm - - soil_moisture_1_3cm - - soil_moisture_3_9cm - - soil_moisture_9_27cm - - soil_moisture_27_81cm - - name: daily - in: query - schema: - type: array - items: + - celsius + - fahrenheit + - name: wind_speed_unit + in: query + schema: type: string + default: kmh enum: - - temperature_2m_max - - temperature_2m_min - - apparent_temperature_max - - apparent_temperature_min - - precipitation_sum - - precipitation_hours - - weather_code - - sunrise - - sunset - - wind_speed_10m_max - - wind_gusts_10m_max - - wind_direction_10m_dominant - - shortwave_radiation_sum - - uv_index_max - - uv_index_clear_sky_max - - et0_fao_evapotranspiration - - name: latitude - in: query - required: true - description: "WGS84 coordinate" - schema: - type: number - format: double - - name: longitude - in: query - required: true - description: "WGS84 coordinate" - schema: - type: number - format: double - - name: current_weather - in: query - schema: - type: boolean - - name: temperature_unit - in: query - schema: - type: string - default: celsius - enum: - - celsius - - fahrenheit - - name: wind_speed_unit - in: query - schema: - type: string - default: kmh - enum: - - kmh - - ms - - mph - - kn - - name: timeformat - in: query - description: If format `unixtime` is selected, all time values are returned in UNIX epoch time in seconds. Please not that all time is then in GMT+0! For daily values with unix timestamp, please apply `utc_offset_seconds` again to get the correct date. - schema: - type: string - default: iso8601 - enum: - - iso8601 - - unixtime - - name: timezone - in: query - description: If `timezone` is set, all timestamps are returned as local-time and data is returned starting at 0:00 local-time. Any time zone name from the [time zone database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) is supported. - schema: - type: string - - name: past_days - in: query - description: If `past_days` is set, yesterdays or the day before yesterdays data are also returned. - schema: - type: integer - enum: - - 1 - - 2 + - kmh + - ms + - mph + - kn + - name: timeformat + in: query + description: If format `unixtime` is selected, all time values are returned in UNIX epoch time in seconds. Please not that all time is then in GMT+0! For daily values with unix timestamp, please apply `utc_offset_seconds` again to get the correct date. + schema: + type: string + default: iso8601 + enum: + - iso8601 + - unixtime + - name: timezone + in: query + description: If `timezone` is set, all timestamps are returned as local-time and data is returned starting at 0:00 local-time. Any time zone name from the [time zone database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) is supported. + schema: + type: string + - name: past_days + in: query + description: If `past_days` is set, yesterdays or the day before yesterdays data are also returned. + schema: + type: integer + enum: + - 1 + - 2 responses: "200": description: OK diff --git a/swift-java-weather-app/weather-lib/build.gradle b/swift-java-weather-app/weather-lib/build.gradle index db8a66d..3a12500 100644 --- a/swift-java-weather-app/weather-lib/build.gradle +++ b/swift-java-weather-app/weather-lib/build.gradle @@ -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 +// +//===----------------------------------------------------------------------===// + import java.nio.file.* import org.gradle.internal.os.OperatingSystem import groovy.json.JsonSlurper @@ -98,8 +112,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 @@ -140,7 +161,7 @@ abis.each { abi, info -> // We must disable sandbox, because we use the `enableJavaCallbacks` feature // of swift-java. - args("run", "swift", "build", "+${swiftVersion}", "--swift-sdk", info.triple, "--disable-sandbox") + args("run", "swift", "build", "+${swiftVersion}", "--swift-sdk", info.triple, "--build-system", "native", "--disable-sandbox") } buildSwiftAll.configure { dependsOn(task) } @@ -192,4 +213,4 @@ android { } // Make sure we run our tasks before build -preBuild.dependsOn(copyJniLibs) \ No newline at end of file +preBuild.dependsOn(copyJniLibs)