
はじめに
こんにちは!ピヨコです。
今回は2025年10月末に発表された「Swift SDK for Android」を使ってSwift製のライブラリをAndroidアプリで試していきたいと思います。
www.swift.org
今回はSwift.orgが提供しているサンプルを利用します。
github.com
旧来のスマホアプリ開発において、SwiftではiOSアプリしか開発できませんでした。
そのため、iOSとAndroidのクロスプラットフォームを実現するためには、iOS/AndroidのそれぞれのNativeアプリを個別で開発する、もしくはFlutterやReact Nativeといったフレームワークを採用する必要がありました。
今回のSDKの発表によって、既存のSwiftで動作しているiOSアプリがあればAndroidアプリとしてもSwiftの資産を利用できる可能性が高まります。
現在はプレビュー版ですので、今後のアップデートや情報の追加に期待したいところです。
※記事公開時点ではプレビュー版のSDKです。今後のSDKのアップデートによって手順など変更の可能性があります。必ず最新の情報を確認してください。
「Swift SDK for Android」とは?
「Swift SDK for Android」はOSSのコミュニティであるSwift.orgのAndroid workgroupによって開発されたSDKです。
「Swift SDK for Android」の仕組みとしては、「Swift Java」を利用しています。
「Swift Java」は、SwiftのプログラムからJavaのコードやライブラリを呼び出したり、逆にJavaからSwiftのコードを呼び出したりできるようにするためのライブラリとツールセットです。
github.com
大きな特徴としては、WindowsやLinuxからも「Swift SDK for Android」を利用して開発可能ということです。
ただし、iOSアプリとして動作確認やストア公開するためには引き続きmacOSとXcodeが必要になります。
また、現時点ではSwiftとJavaの相互変換のみで、UIKitやSwiftUIなどのFrameworkには対応できていません。
つまり、Swiftで書かれたロジック部分はJavaに変換しての活用が可能ですが、Viewについては従来通りそれぞれのプラットフォームでコードを持つ必要があります。
記事の内容
説明しないこと
実行環境
- macOS Tahoe 26.0.1
- 空き容量が5GB以上必要
- ターミナルはzshを利用
- Swift 6.3-dev (main-snapshot-2025-10-17)
- Swift SDK for Android (DEVELOPMENT-SNAPSHOT-2025-10-17-a)
- Java Development Kit (JDK) 25.0.1
- Xcode 26.1.1
- Android Studio 2025.2.1 Patch 1
- 2025年11月時点で最新版ではないと正常に動作しないようです
導入
Getting Started with the Swift SDK for Androidに従って進めていきます。
2025-10-17のスナップショットが最新のようだったので、バージョンの「2025-10-16」を「2025-10-17」に置き換えて導入を行なっています。
手順はこの4ステップで進めていきます。
- Swiftlyの導入
- Host Toolchainの導入
- Swift SDK for Androidの導入
- Android NDKの導入
- Java Development Kit (JDK)の導入
Swiftlyの導入
Swiftly経由で特定バージョンのSwiftを利用する必要があるため、Swiftlyを導入します。
Xcodeが入っている場合はすでにSwiftがインストールされていますが、バージョンコントロールに必要なので必ず導入してください。
Install SwiftでOSごとの導入方法が書かれているので参考にしてください。
今回はMacなのでターミナルからこちらのコマンドを実行し、完了したらターミナルを再起動します。
% 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
Host Toolchainの導入
SDKに対応したバージョンのSwiftを導入するため、以下を順番に実行します。
% swiftly install main-snapshot-2025-10-17 % swiftly use main-snapshot-2025-10-17 % swiftly run swift --version
最後にこのような表示が出ればOKです。
Apple Swift version 6.3-dev (LLVM d8e7cc748ee6e7f, Swift a07ea37d0054945)
Swift SDK for Androidの導入
次にSDKを導入するため、以下を順番に実行します。
% swift sdk install https://download.swift.org/development/android-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-17-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-17-a_android-0.1.artifactbundle.tar.gz --checksum ba57d4663be0ebba2a22d8377a282a37d2d801aa25e5c5ed4b8d9b7769ae6782 % swiftly run swift sdk list
最後にこのような表示が出ればOKです。
swift-DEVELOPMENT-SNAPSHOT-2025-10-17-a-android-0.1
Android NDKの導入
次にAndroid NDKを導入します。Android NDKは、AndroidでCやC++のコードを利用するためのツールセットです。
以下を順番に実行します。
% mkdir ~/android-ndk % cd ~/android-ndk % curl -fSLO https://dl.google.com/android/repository/android-ndk-r27d-$(uname -s).zip % unzip -q android-ndk-r27d-*.zip % export ANDROID_NDK_HOME=$PWD/android-ndk-r27d % cd ~/Library/org.swift.swiftpm || cd ~/.swiftpm % ./swift-sdks/swift-DEVELOPMENT-SNAPSHOT-2025-10-17-a-android-0.1.artifactbundle/swift-android/scripts/setup-android-sdk.sh
最後にこのような表示が出ればOKです。
setup-android-sdk.sh: success: ndk-sysroot linked to Android NDK at /Users/hoge/android-ndk/android-ndk-r27d/toolchains/llvm/prebuilt
Java Development Kit (JDK)の導入
最後にJDKを導入します。すでにJDKを導入済みの場合はバージョンや環境変数JAVA_HOMEの設定を確認してください。
将来的には不要になるとのことですが、現時点ではJDK 25が推奨とのことです。
以下を順番に実行します。今回はbrewで導入しますが、miseやsdkmanなど普段お使いのものがあればそちらで構いません。
% brew install openjdk % sudo ln -sfn /opt/homebrew/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk % echo 'export PATH="/opt/homebrew/opt/openjdk/bin:$PATH"' >> ~/.zshrc % source ~/.zshrc % java --version
このような表示が出ればJDKの導入はOKです。ここで表示されたバージョンを控えておき、続けてJAVA_HOMEを設定します。
openjdk 25.0.1 2025-10-21 OpenJDK Runtime Environment Homebrew (build 25.0.1) OpenJDK 64-Bit Server VM Homebrew (build 25.0.1, mixed mode, sharing)
JAVA_HOMEのバージョンの25.0.1のところは適宜上記で控えたバージョンに差し替えて実行してください。
% echo 'export JAVA_HOME=$(/usr/libexec/java_home -v 25.0.1)' >> ~/.zshrc % source ~/.zshrc
サンプルを動かす
さて、実際に公開されているサンプルを動かしてみたいと思います。
https://github.com/swiftlang/swift-android-examples/
hello-swift-java/の配下には、Androidアプリとアプリに導入するSwiftのライブラリがそれぞれ配置されています。
swift-android-example ├── hello-swift-java │ ├── hashing-app // Androidアプリの実装 │ ├── hashing-lib // Swiftのライブラリ │ ├── README.md │ └── resources // READMEの画像
Swift製ライブラリをAndroidプロジェクトから利用可能にする
サンプルのソースをローカルにクローンもしくはダウンロードしたら、README.mdの「Publish swift-java packages locally」の通りに進めていきます。
JDK 25の導入とJAVA_HOMEの環境変数の設定は終わっているのでその次から進めます。
まずはhashing-libの依存関係のあるPackageを取得しておきます。
% cd hashing-lib % swift package resolve
取得したswift-javaをAndroidプロジェクトから利用できるようにローカルのMavenRepositoryに公開します。
% ./.build/checkouts/swift-java/gradlew --project-dir .build/checkouts/swift-java :SwiftKitCore:publishToMavenLocal
バージョンを導入時のものに合わせる
完了したら、swift-android-exampleをAndroid Studioで開きます。
このままだとSyncが失敗するため、バージョン関連を適宜変更します。
まず、Settings > Build, Execution, Deployment > Build Tools > Gradle からGradle JDKはJAVA_HOMEに変えておきます。
次にhello-swift-java/hashing-lib/build.gradleとswift-android.gradle.ktsのSwiftバージョンとSDKのバージョンをそれぞれ今回導入したものに変えておきます。
バージョン番号等は導入したものに適宜読み替えてください。
diff --git a/hello-swift-java/hashing-lib/build.gradle b/hello-swift-java/hashing-lib/build.gradle index f0170c9..b0fc4f6 100644 --- a/hello-swift-java/hashing-lib/build.gradle +++ b/hello-swift-java/hashing-lib/build.gradle @@ -99,8 +99,8 @@ def swiftRuntimeLibs = [ "swiftSynchronization" ] -def sdkName = "swift-DEVELOPMENT-SNAPSHOT-2025-10-16-a-android-0.1.artifactbundle" -def swiftVersion = "main-snapshot-2025-10-16" +def sdkName = "swift-DEVELOPMENT-SNAPSHOT-2025-10-17-a-android-0.1.artifactbundle" +def swiftVersion = "main-snapshot-2025-10-17" def minSdk = android.defaultConfig.minSdkVersion.apiLevel /** * Android ABIs and their Swift triple mappings
diff --git a/swift-android.gradle.kts b/swift-android.gradle.kts index aef7792..de12330 100644 --- a/swift-android.gradle.kts +++ b/swift-android.gradle.kts @@ -14,8 +14,8 @@ 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 = "main-snapshot-2025-10-16", // Swift version - var androidSdkVersion: String = "DEVELOPMENT-SNAPSHOT-2025-10-16-a-android-0.1" // SDK version + var swiftVersion: String = "main-snapshot-2025-10-17", // Swift version + var androidSdkVersion: String = "DEVELOPMENT-SNAPSHOT-2025-10-17-a-android-0.1" // SDK version )
Androidアプリを動かす
Syncが完了したら、実際にBuild、Runしていきます。
Configurationは「hello-swift-java-hashing-app」を指定します。

無事にアプリを動かすことができました🎉
Swift製のライブラリを作ってAndroidアプリで動かしてみる
hashing-libを参考に新しくライブラリを作ってみます。
inputに対して「こんにちは!{input}さん!」のような文字列を返す簡単な内容です。
Swiftライブラリの作成
まずはSwiftPackageを作成します。
hello-swift-java ├── hello-lib │ ├── build.gradle │ ├── gradle.properties │ ├── Package.swift │ ├── Sources │ │ └── SwiftHello │ │ ├── swift-java.config │ │ └── SwiftHello.swift │ └── Tests │ └── SwiftHelloTests
Package.swiftはhash-libのものからPackageの設定を書き換えます。
全て掲載すると長いので変更部分だけ抜粋します。
Package.swift
... ... let package = Package( name: "SwiftHello", platforms: [.macOS(.v15), .iOS(.v16)], products: [ .library( name: "SwiftHello", type: .dynamic, targets: ["SwiftHello"]) ], dependencies: [ .package(url: "https://github.com/swiftlang/swift-java", branch: "main"), .package(url: "https://github.com/apple/swift-crypto.git", "1.0.0"..), ], targets: [ .target( name: "SwiftHello", dependencies: [ .product(name: "Crypto", package: "swift-crypto"), .product(name: "SwiftJava", package: "swift-java"), .product(name: "CSwiftJavaJNI", package: "swift-java"), .product(name: "SwiftJavaRuntimeSupport", package: "swift-java"), ], swiftSettings: [ .swiftLanguageMode(.v5), .unsafeFlags(["-I\(javaIncludePath)", "-I\(javaPlatformIncludePath)"], .when(platforms: [.macOS, .linux, .windows])) ], plugins: [ .plugin(name: "JExtractSwiftPlugin", package: "swift-java") ] ), .testTarget( name: "SwiftHelloTests", dependencies: ["SwiftHello"] ), ] )
build.gradleはhash-libのものからnamespaceとソースのディレクトリのパスを書き換えます。
全て掲載すると長いのでこちらも変更部分だけ抜粋します。
build.gradle
... ... android { namespace "com.example.hellolib" compileSdkVersion 34 defaultConfig { minSdkVersion 28 } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } } ... ... def buildSwiftAll = tasks.register("buildSwiftAll") { group = "build" description = "Builds the Swift code for all Android ABIs." inputs.file(new File(projectDir, "Package.swift")) inputs.dir(new File(layout.projectDirectory.asFile, "Sources/SwiftHello".toString())) outputs.dir(layout.buildDirectory.dir("../.build/plugins/outputs/${layout.projectDirectory.asFile.getName().toLowerCase()}")) File baseSwiftPluginOutputsDir = layout.buildDirectory.dir("../.build/plugins/outputs/").get().asFile if (!baseSwiftPluginOutputsDir.exists()) { baseSwiftPluginOutputsDir.mkdirs() } Files.walk(layout.buildDirectory.dir("../.build/plugins/outputs/").get().asFile.toPath()).each { if (it.endsWith("JExtractSwiftPlugin/src/generated/java")) { outputs.dir(it) } } }
ライブラリの実装です。
実装後はswift build -vでビルドが通るか確認しておきます。
Sources/SwiftHello/SwiftHello.swift
#if canImport(FoundationEssentials) import FoundationEssentials #else import Foundation #endif public func hello(_ input: String) -> String { return "こんにちは!\(input)さん!" }
Javaから参照するパッケージ名の設定です。
hash-libのものからjavaPackageだけ書き換えます。
swift-java.config
{ "javaPackage": "com.example.swifthello", "mode": "jni" }
Swiftライブラリのビルド
一通り準備ができたら、ライブラリをAndroidアプリで使えるようビルドします。
サンプルソースのルートのsettings.gradle.ktsにAndroidアプリで参照するPackage名とパスを追加します。
diff --git a/settings.gradle.kts b/settings.gradle.kts index 0be2778..e758263 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,6 +28,8 @@ include(":hello-swift-java-hashing-lib") project(":hello-swift-java-hashing-lib").projectDir = file("hello-swift-java/hashing-lib") include(":hello-swift-java-hashing-app") project(":hello-swift-java-hashing-app").projectDir = file("hello-swift-java/hashing-app") +include(":hello-swift-java-hello-lib") +project(":hello-swift-java-hello-lib").projectDir = file("hello-swift-java/hello-lib")
サンプルソースのルート、にgradlewがあるのでそちらからビルドを実行します。
% cd swift-android-example % ./gradlew :hello-swift-java-hello-lib:assembleRelease
Androidアプリからの実行
サンプルのアプリのbuild.gradle.ktsにライブラリの依存関係を追加してSyncします。
diff --git a/hello-swift-java/hashing-app/build.gradle.kts b/hello-swift-java/hashing-app/build.gradle.kts index e087f09..87f86fc 100644 --- a/hello-swift-java/hashing-app/build.gradle.kts +++ b/hello-swift-java/hashing-app/build.gradle.kts @@ -50,6 +50,7 @@ dependencies { implementation(libs.androidx.material3) implementation("org.swift.swiftkit:swiftkit-core:1.0-SNAPSHOT") implementation(project(":hello-swift-java-hashing-lib")) + implementation(project(":hello-swift-java-hello-lib")) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core)
Syncが完了したら、Androidアプリ側のソースを書き換えます。
挙動を試したいだけなので、既存のhash値を表示する部分をそのまま書き換えてます。
... ... import com.example.swifthello.SwiftHello class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { HashingAppTheme { Surface ( modifier = Modifier.fillMaxSize().padding(top = 64.dp), color = MaterialTheme.colorScheme.background ) { HelloScreen() } } } } } @Composable fun HelloScreen() { val input = remember { mutableStateOf("") } val helloResult = remember { mutableStateOf("") } Column( modifier = Modifier .fillMaxSize() .padding(32.dp), verticalArrangement = Arrangement.spacedBy(12.dp) ) { TextField( value = input.value, onValueChange = { input.value = it }, label = { Text("Enter name") }, modifier = Modifier.fillMaxWidth() ) Button( colors = ButtonDefaults.buttonColors( containerColor = Color(0xFFF05138), contentColor = Color.White ), onClick = { helloResult.value = SwiftHello.hello(input.value) } ) { Text("Hello") } if (helloResult.value.isNotEmpty()) { Text( text = helloResult.value, style = MaterialTheme.typography.bodyMedium ) } } }
BuildしてRunします。
新しいSwiftライブラリでも無事にアプリを動かすことができました🎉
まとめ
今回は10月末に発表された「Swift SDK for Android」を実際に触ってみました。
現在はプレビュー版なのでやや環境構築の手間が多い印象でしたが、今後の開発で改善されるとのことです。
また、検証中にSwift→Javaの変換が上手くいかないことがありましたが、UIKitやSwiftUIも未対応のことから今後の改善に期待です。
(余談:DateFormatterが変換できず、Swiftライブラリを書き直してます。)
今回簡単な検証をしただけですが、今後の開発の進展によってはクロスプラットフォームアプリの開発のフレームワーク選択に大きな影響を及ぼすだろうことが予想できます。今後のアップデートや情報の追加が楽しみです。
スパイダープラスでは、エンジニアを募集しています。興味のある方はぜひ、カジュアル面談からでもお気軽にご応募ください!