先日の Recap イベント で知った SwiftJava について。
話されているこの方、try! Swift 2025 でもご登壇されていた。あいにく筆者はスタッフをしていたので聴講できなかったが、会場で何度もお見かけしていたので、サムネからすぐにピンときた。
0:00 – Introduction & Agenda
- SwiftとJavaの相互運用(インターオペラビリティ)を紹介
- Swiftを他言語の既存コードベースに段階的に導入できるメリット
- 書き換えずそのままに、Swiftでの新しい機能追加や置き換えが可能
- Swiftで多言語のライブラリ、多言語でSwiftのライブラリを利用可能
- Swiftと他言語の連携は言語だけでなく、CMakeやGradleなど各エコシステムのビルドツールとも統合
- SwiftのC言語はじめ多言語との相互運用の歴史
- 相互運用の方向性:Java interoperability は両方向に対応
- Call Java from Swift
- Call Swift from Java
2:41 – Runtime differences
- JavaとSwiftのランタイムの違いを解説
- 両言語ともクラス継承、メモリ管理、ジェネリクス、例外処理など多くの共通点がある
- 違いを意識しつつAPIを設計すれば、相互運用が可能
3:31 – Java Native methods
- Java Native Interface(JNI)を使ったJavaからネイティブコード(Swift)呼び出しの仕組み
- Java のネイティブメソッドは JNI API に含まれている
- JNIは歴史が長く、パフォーマンス向上や既存ネイティブライブラリ利用のために使われる
- ライブラリやツールを使わない従来手順で JNI を使うデモ
- Java でネイティブ関数を定義、ネイティブコードを浸かって実装
- 例では、Java オブジェクトである Integer を引数・戻り値に使用
- Java コンパイラを使用:-h フラグ → Cヘッダーファイルが生成
- JVM が呼び出すファイル
- インターフェイスの命名が長い
- これを Swift で実装
- JNIの利用は手順が多く、Cヘッダーやシグネチャの一致などミスが起きやすい
- オブジェクトのライフタイム管理も難しい
6:29 – SwiftJava
- Swift と Java の相互運用を支援する新プロジェクト「SwiftJava」を紹介
- Swift パッケージ(JavaKit)
- Javaライブラリ(SwiftKit)
- コマンドラインツール (
swift-java
) で構成
swift-java
コマンドによる生成結果(Swift ファイル)
- インポートされたJavaクラスの定義が含まれている
@JavaMethod
マクロで示される Java 型のメンバーメソッド経由で、Swift コードからアクセスできる
JNIExampleNativeMethods
プロトコル:C ヘッダの代わり
@JavaImplementation
でネイティブ関数を実装。必要な関数シグネチャはコンパイラが実装
@JavaMethod
マクロの関数定義内で、Swift コード/Swift ライブラリを利用した実装が可能
- JNI の煩雑さを解消し、ボイラープレートを削減し、安全かつ効率的な連携を実現
- SwiftJava を使うことで、型安全なコード生成やオブジェクト管理が容易に
10:13 – Call Java from Swift
- Swift から Java ライブラリを利用する方法
- Gradle 連携で Java の依存解決も自動化
- 依存関係の3つの要素:Artifact ID, Group ID, Version をコロンで繋ぎ、 swift-java.config の
dependencies
に追加
- Swift Package Manager プラグインやコマンドラインツールで Java ライブラリを Swift から簡単に呼び出せる(トレードオフあり)
swift build --disable-sandbox
: セキュリティサンドボックス無効化が必要
swift-java resolve --module-name <module_name>
: 依存関係の解決を手動起動する必要あり
- JavaKit による JDK ラッパー型やオブジェクトのライフタイム管理もサポート
- Swift プロセスで JVM 起動
let jvm = try JavaVirtualMachine.shared()
14:01 – Call Swift from Java
- Java から Swift ライブラリを利用する方法
- Swift の型や関数を Java クラスとして自動生成し、Java からシームレスに呼び出し可能
- JNIではなく、Java 22 以降の Foreign Function and Memory API を活用
- 例:
struct SwiftyBusiness
– 構造体定義で、プロパティ、イニシャライザ、メソッドを持つ
struct
は値型で、安定したオブジェクトIDがない → Java オブジェクトで表現不可
swift-java
コマンド:Swift 型ヘのアクセサである .java ファイル(Java クラス)生成
- .swift も含めた .jar ファイルが生成
- 構造体が Java クラスとして実装され、メソッドも Java シグネチャで定義される
- 内部的に Foreign Function API でネイティブ呼び出しされる
- Confined な
SwiftArena
(メモリ管理、有効期限管理)の使用で、安全かつ効率的なリソース解放を実現
SwiftArena.ofConfined()
による、try-with-resource を使用したメモリ管理
- GCに依存せず最善のパフォーマンスを実現可能
おまけ
ChatGPT が案出ししてくれた、SwiftJava の実験案10選。
iOS兼Androidアプリエンジニアとしては、Android 開発と連動できれば嬉しいが、、Kotlin が主流な昨今において果たして。Jetpack Compose のコード生成はできないと思う、、
1. “書いた Swift をそのまま Android でも”
- ドメインロジックやアルゴリズムを Swift で実装し、SwiftJava CLI で Java ラッパを吐き出して Android に組み込む。Gradle が依存解決・ビルドを面倒見てくれるので iOS ⇄ Android の 100 % 共有コード が現実的に。
2. Java ライブラリをサクッと呼ぶ Swift サーバー
- Vapor や Hummingbird など Swift サーバーアプリから Apache Lucene/Kafka/Spark まで JAR ごとインポート。swift-java resolve がトランジティブ依存を丸ごと解決し、Swift 側は import JavaLucene で即検索エンジン化。
3. Swift 製暗号モジュールを Java へ“輸出”
- セキュアかつ GC フリーな Swift ライブラリを生成し、JVM とは Java 22 の Foreign Function & Memory API で橋渡し。Java 側は try-with-resources で自動メモリ管理、Swift 側は Arena で安全――金融/ブロックチェーン案件に映える。
4. Jetpack Compose コンポーネントを Swift マクロで自動生成
- SwiftUI ライクな DSL → マクロ展開で Compose UI を吐くツールチェインを自作。デザイナーが SwiftUI プレビューで確認 → ボタン一発で Android 版 UI を生成、という“プラットフォーム超えデザインシステム”を実現。
5. JVM 大規模データ処理をローカル ML 推論に転用
- Java の Deeplearning4j モデルを iOS アプリに同梱し、Swift から呼び出して 完全オフラインの画像分類。モバイルでも GDPR/個人情報保護の要件をクリアしつつ高精度推論。
6. Minecraft/IntelliJ プラグインを Swift で書く
- プラグイン API は Java だが、Swift 側でコアロジックを書くことで Swift Concurrency で並列 AI/Result Builders で DSL などモダン機能をプラグインにも注入。
7. Spring Boot × Swift で“二刀流”マイクロサービス
- コントローラ層は Java(Spring)、ドメイン層を Swift で実装。Swift の値型 & 不変データでビジネスロジックを堅牢にしつつ、既存の Spring インフラ(Actuator/Observability)をそのまま享受。
8. JUnit ↔︎ XCTest 相互呼び出しでクロスプラットフォーム CI
- SwiftJava で JUnit テストから Swift の XCTest を直接呼び出し、“片方落ちたら両方真っ赤”な 一体化テストレポート を生成。モノレポの CI をシンプルに。
9. SwiftArena × Project Loom で“協調コルーチン”
- Java 側の仮想スレッド(Loom)と Swift の Structured Concurrency を相互ラップし、クロスランタイムの高スループット IO を研究。フルスタック並列処理オタク歓喜。
10. “Swift 製 DSL→JVM バイトコード”コンパイラ
- Swift Macro で DSL を解析、SwiftJava で ASM(Java バイトコード生成ライブラリ)を呼び出して ネイティブに JVM バイトコードを吐く。Swift 製ビルドツールやスクリプトエンジンだって夢じゃない。