Environment & Swift Package Setup
Before writing Swift code for Android, you need to set up your development environment and create a Swift package. This segment covers the complete toolchain installation and introduces Swift Package Manager.
Getting Started
Access the starter project from the Materials section in the right sidebar. Open the Starter project in Android Studio.
The Starter project contains a fully functional Compose UI with:
- MainActivity.kt: Sets up the Compose UI
- TaskListScreen.kt: Displays the list of tasks
- TaskCard.kt: Shows individual task cards with priority badges
- CreateTaskDialog.kt: Form for creating new tasks
- Task.kt: Data class for tasks with Priority enum
- TaskRepository.kt: Repository that currently has no validation
Build and run the app. You’ll see an empty task list with a floating action button. Try creating a task with invalid input like a single-character title. It accepts anything! You’ll fix this by implementing validation in Swift.
Installing Swift SDK for Android
The Swift SDK for Android enables cross-compiling Swift code for Android devices. You’ll install the complete toolchain on your development machine.
Note: Swift SDK for Android is actively evolving. This lesson uses Swift 6.3 development snapshot (2026-01-16). Check swift.org/install for the latest versions. Snapshot versions may have breaking changes between releases. For production apps, when Swift 6.3 is officially released, update to the stable version.
Prerequisites
To follow along, you’ll need:
- macOS with Xcode installed
- Android Studio Ladybug or later
- Android NDK 27.2.12479018 (installed via Android Studio)
- Swift 6.3-snapshot-2026-01-16 (development snapshot)
- swiftly (Swift toolchain manager)
- JDK 21 (for building Swift and Android)
- JDK 25 (for one-time swift-java setup only)
- sdkman (Java version manager)
Note: You’ll need JDK 25 for a one-time setup step (publishing swift-java to local Maven), but all actual project builds use JDK 21. Android Studio’s bundled JDK works for Android compilation, but JDK 25 is required for Swift builds because it includes the JNI headers that swift-java needs.
Installing swiftly
swiftly is the official Swift toolchain manager. It allows you to install and switch between different Swift versions easily.
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
After installation, restart your terminal or source your profile:
source ~/.zshrc # if using zsh (default on macOS)
# OR
source ~/.bashrc # if using bash
Verify the installation:
swiftly --version
You should see the swiftly version number:
1.1.1
Installing Swift 6.3
Now install Swift itself using swiftly:
swiftly install 6.3-snapshot
swiftly use 6.3-snapshot
The first command downloads and installs the Swift 6.3 development snapshot. The second command sets it as your active Swift version.
Verify Swift is installed:
swift --version
You should see something like:
Apple Swift version 6.3-dev (LLVM 478f55c39d6bc2c, Swift a15423cb66d4749)
Target: arm64-apple-macosx15.0
Build config: +assertions
Installing Swift SDK for Android
This is the critical component that enables cross-compiling Swift code for Android devices.
swift sdk install https://download.swift.org/swift-6.3-branch/android-sdk/swift-6.3-DEVELOPMENT-SNAPSHOT-2026-01-16-a/swift-6.3-DEVELOPMENT-SNAPSHOT-2026-01-16-a_android.artifactbundle.tar.gz --checksum 080da5553cdd12d286f715d86527089e7c924093733f8f4e1195f2bd2137d45c
This command downloads and installs the Swift SDK for Android artifact bundle. The --checksum parameter verifies the download integrity.
Verify the installation:
swift sdk list
You should see output like:
swift-6.3-DEVELOPMENT-SNAPSHOT-2026-01-16-a_android (installed)
aarch64-unknown-linux-android28
armv7-unknown-linux-android28
x86_64-unknown-linux-android28
This shows that the Android SDK includes support for three Android architectures: ARM64, ARMv7, and x86_64.
Setting Up Android Studio and NDK
The Swift SDK for Android requires the Android Native Development Kit (NDK) to link against Android’s C++ libraries. You’ll install the NDK through Android Studio’s SDK Manager.
Note: If you don’t have Android Studio installed, download it from developer.android.com/studio before continuing.
Open Android Studio and install the required components:
- Open Android Studio → Settings/Preferences
- Navigate to Appearance & Behavior → System Settings → Android SDK
- In the SDK Platforms tab, ensure Android 14.0 (API Level 34) is installed
- Switch to the SDK Tools tab and install:
- Android NDK (check Show Package Details and select version 27.2.12479018)
- Android SDK Build-Tools 34.0.0
- Android SDK Command-line Tools
Note the NDK installation path (typically ~/Library/Android/sdk/ndk/27.2.12479018).
Set the environment variables by adding these lines to your ~/.zshrc:
export ANDROID_HOME=$HOME/Library/Android/sdk
export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/27.2.12479018
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
Reload your shell:
source ~/.zshrc # if using zsh (default on macOS)
# OR
source ~/.bashrc # if using bash
Verify the NDK installation:
echo $ANDROID_NDK_HOME
ls $ANDROID_NDK_HOME/toolchains/llvm/prebuilt/
You should see a directory like darwin-x86_64.
Linking NDK to Swift SDK
Critical: After installing both the Swift SDK and Android NDK, you need to run a setup script that links them together. This creates a symlink from the Swift SDK’s expected NDK path to your installed Android NDK.
Run the setup script:
cd ~/Library/org.swift.swiftpm || cd ~/.swiftpm
./swift-sdks/swift-6.3-DEVELOPMENT-SNAPSHOT-2026-01-16-a_android.artifactbundle/swift-android/scripts/setup-android-sdk.sh
You should see this success message:
setup-android-sdk.sh: success: ndk-sysroot linked to Android NDK at android-ndk-r27d/toolchains/llvm/prebuilt
What this does: The script creates a symlink that allows the Swift SDK to find the Android NDK’s C/C++ headers and libraries. Without this step, your Swift builds will fail with errors like:
ndk-sysroot not foundfatal error: 'semaphore.h' file not founderror: could not find system library
Understanding Swift Package Manager
Now that your toolchain is installed, you’ll learn about Swift Package Manager (SPM) which is the build system you’ll use to create your Swift library.
What is Swift Package Manager?
Swift Package Manager is Swift’s official build system and dependency manager. It provides:
- Cross-platform builds: Compile Swift code for iOS, macOS, and Android
- Dependency management: Automatically fetch and build external Swift packages
- Build configuration: Define products, targets, and compilation settings
- Plugin system: Extend builds with custom plugins (like JExtractSwiftPlugin)
For Android development, SPM allows you to create a dynamic library that Android loads at runtime through JNI.
Why Use SPM for Android?
You might wonder why you’re using Swift’s build system for Android development. Here’s why:
- Native Swift tooling: SPM is designed for Swift, understands Swift modules, and integrates with the Swift compiler
- Dependency resolution: Automatically manages Swift packages like swift-java
- Cross-compilation: Built-in support for cross-compiling to Android architectures from macOS
- Plugin integration: Supports build plugins like JExtractSwiftPlugin that generate Java bindings
Think of SPM as the Swift equivalent of Gradle. It manages your Swift code while Gradle manages your Kotlin/Java code. They work together in the build pipeline.
Creating Your Swift Package
Now you’ll create a Swift package for your task validation logic. This package will compile to a dynamic library that Android loads at runtime.
Creating the Package Directory
Navigate to your Starter project directory and create the package:
cd path/to/Starter
mkdir taskmanager-lib
cd taskmanager-lib
Note: The directory name
taskmanager-libmatches what Gradle expects. Later, you’ll configure Gradle to build this package and link it to your Android app.
Initializing the Swift Package
Run Swift Package Manager’s initialization command:
swift package init --type library --name TaskManagerKit
This command creates a new library package with the following structure:
taskmanager-lib/
├── Package.swift ← Package manifest (configuration)
├── Sources/
│ └── TaskManagerKit/ ← Your Swift code goes here
│ └── TaskManagerKit.swift ← Generated sample file
├── Tests/
│ └── TaskManagerKitTests/ ← Unit tests (optional)
└── .gitignore ← Git ignore rules
What each component does:
- Package.swift: The manifest file that describes your package such as the name, dependencies, targets, and build settings
- Sources/TaskManagerKit/: The directory containing your Swift source code
- Tests/: Unit test directory (you can delete this for now since we’re focusing on integration with Android)
-
.gitignore: Ignores build artifacts like the
.build/directory
Understanding Package.swift
Open Package.swift and examine its structure:
// swift-tools-version: 6.2
import PackageDescription
let package = Package(
name: "TaskManagerKit",
products: [
.library(
name: "TaskManagerKit",
targets: ["TaskManagerKit"])
],
targets: [
.target(
name: "TaskManagerKit"),
.testTarget(
name: "TaskManagerKitTests",
dependencies: ["TaskManagerKit"])
]
)
Key components:
- swift-tools-version: Specifies the minimum Swift version required (6.2)
- name: The package name (TaskManagerKit)
-
products: What you expose to consumers of your package
-
.library()creates a library that other code can link against
-
-
targets: Internal modules that make up your package
-
.target()is your main source code -
.testTarget()is for unit tests
-
For Android, the critical setting you’ll add later is .library(type: .dynamic), which creates a .so shared library that Android loads at runtime.
Verifying the Package
Build the package to ensure everything is configured correctly:
swift build
You should see output like:
Building for debugging...
[4/4] Compiling TaskManagerKit TaskManagerKit.swift
Build complete!
Check what was created:
find .build -name "TaskManagerKit.swiftmodule"
You’ll see something like:
.build/arm64-apple-macosx/debug/Modules/TaskManagerKit.swiftmodule
This Swift module interface proves your package compiled successfully! Right now, SPM only creates the module interface because you haven’t specified type: .dynamic. In the next segment, you’ll update Package.swift to create a dynamic library (.dylib on macOS, .so on Android) that Android can load at runtime via JNI.
Understanding the Build Output
The .build/ directory contains all build artifacts:
.build/
├── arm64-apple-macosx/ ← Architecture-specific build (or x86_64-apple-macosx)
│ └── debug/ ← Debug build products
│ ├── Modules/
│ │ └── TaskManagerKit.swiftmodule ← Swift module interface
│ ├── ModuleCache/ ← Cached standard library modules
│ ├── TaskManagerKit.build/ ← Intermediate build files (.o, .d, .swiftdeps)
│ └── ... ← Other build artifacts
└── checkouts/ ← Downloaded dependencies (empty for now)
Right now, SPM only creates the Swift module interface. Later, you’ll configure Package.swift to create dynamic libraries and generate Java bindings.
Project Structure Diagram
Here’s what your project looks like now:
Starter/
├── app/ ← Android app (Kotlin/Compose)
│ ├── src/main/kotlin/...
│ └── build.gradle.kts
├── taskmanager-lib/ ← NEW: Swift package
│ ├── Package.swift ← Package manifest
│ ├── Sources/
│ │ └── TaskManagerKit/ ← Swift source code
│ │ └── TaskManagerKit.swift
│ └── .build/ ← Build artifacts
│ └── arm64-apple-macosx/ ← Architecture-specific (or x86_64)
│ └── debug/
│ └── Modules/
│ └── TaskManagerKit.swiftmodule ← Swift module
├── build.gradle.kts ← Project-level Gradle
└── settings.gradle.kts ← Gradle modules (will update)
Your Swift package exists but isn’t connected to the Android app yet. In the next segment, you’ll add swift-java to automatically generate Java bindings.
What You’ve Accomplished
In this segment, you’ve:
- Installed swiftly, Swift 6.3, and Swift SDK for Android.
- Configured Android NDK and linked it to the Swift SDK.
- Learned what Swift Package Manager is and why it’s used for Android.
- Created your first Swift package with
swift package init. - Built the package and verified it compiles.
- Understood the Package.swift manifest structure.
Your development environment is now ready! In the next segment, you’ll configure swift-java to automatically generate Java bindings from your Swift code, eliminating manual JNI work.