近日,Swift 官方正式宣布成立 Android 的工作组,将 Android 列为官方支持的平台,该工作组的主要目标是为 Swift 语言添加并维护 Android 平台支持,让开发者能够使用 Swift 开发 Android 应用:
其实 Swift 语言跨平台支持也不是什么新鲜事,在之前我聊过的 Skip 用 Swift 写 Android App 的时候就聊过,只是不同的是 Skip 是将 Swift 翻译成 Kotlin,把 SwiftUI 翻译成 Compose 的形式来实现,这和 uni-app x 的跨平台实现殊途同归。
❝感兴趣的可以看 《2025 跨平台框架更新和发布对比》
但是 Swift 官方的方案则不同,它是通过 LLVM 进行适配的,我们之前聊过的 《为什么跨平台框架可以适配鸿蒙》 就聊过,LLVM 也是各大框架适配鸿蒙的重要基石,甚至一些方案适配鸿蒙是通过 Apple 的 LLVM 去先导出 IR 来完成前置工作。
而这次 Swift on Android 的实现,则是直接利用 Android 平台的构建工具:Android NDK 。
为什么这么说?因为 Swift 编译器从诞生之初就基于 LLVM ,而 Google 的 Android NDK 后来也使用基于 LLVM 的 Clang 作为其官方 C/C++ 编译器 :
❝说起 Clang 和苹果也是很有渊源,Clang 的设计初衷是提供一个可以替代 GCC 的前端编译器,因为 GCC 的发展不符合 Apple 的节奏和需要,同时受限于License,苹果公司无法使用 LLVM 在 GCC 基础上进一步提升代码生成质量,因此苹果公司决定从头编写 C、C++、Objective-C 语言的前端 Clang,以彻底替代GCC 。
而在编译上,比如 stdlib
里的 AddSwiftStdlib.cmake
可以看到, Swift 没有在 Android 上创造一套自己的 log 系统,它直接链接了 Android 的 Native 的日志 log 来实现,从而支持 Android Studio 的 Logcat :
所以基于 LLVM 的 Android NDK 是实现 Swift 跨平台编译的关键,它让 Swift 编译器能够被“重定向”,从而为 Android 支持的 CPU 架构(如 aarch64
、 armv7
、 x86_64
)生成相应的原生机器码 。
$ NDK_PATH=path/to/android-ndk-r27c
$ SWIFT_PATH=path/to/swift-DEVELOPMENT-SNAPSHOT-2024-11-09-a-ubuntu22.04/usr/bin
$ git checkout swift-DEVELOPMENT-SNAPSHOT-2024-11-09-a
$ utils/build-script
-R # Build in ReleaseAssert mode.
--android # Build for Android.
--android-ndk $NDK_PATH # Path to an Android NDK.
--android-arch aarch64 # Optionally specify Android architecture, alternately armv7 or x86_64
--android-api-level 21 # The Android API level to target. Swift only supports 21 or greater.
--stdlib-deployment-targets=android-aarch64 # Only cross-compile the stdlib for Android, ie don't build the native stdlib for Linux
--native-swift-tools-path=$SWIFT_PATH # Path to your prebuilt Swift compiler
--native-clang-tools-path=$SWIFT_PATH # Path to a prebuilt clang compiler, one comes with the Swift toolchain
--build-swift-tools=0 # Don't build the Swift compiler and other host tools
--build-llvm=0 # Don't build the LLVM libraries, but generate some CMake files needed by the Swift stdlib build
--skip-build-cmark # Don't build the CommonMark library that's only needed by the Swift compiler
❝简而言之,就是编译成 so 。
目前官方要求是在 Linux 环境下(官方推荐 Ubuntu 20.04/22.04)下,使用 Swift 官方提供的交叉编译工具链,将 .swift
源文件编译成原生可执行文件或共享库,之后将编译产物连同必需的 Swift 运行时库,通过 Android adb 推送到 Android 设备或模拟器上,最终这些原生代码可以在 Android 的 shell 环境中直接运行,或被一个标准的 Android 应用加载并调用 :
首先需要运行以下命令复制复制对应的 so :
$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftCore.so /data/local/tmp
$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftAndroid.so /data/local/tmp
$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftSwiftOnoneSupport.so /data/local/tmp
$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftRemoteMirror.so /data/local/tmp
$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswift_Concurrency.so /data/local/tmp
$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswift_RegexParser.so /data/local/tmp
$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswift_StringProcessing.so /data/local/tmp
$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libdispatch.so /data/local/tmp
$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libBlocksRuntime.so /data/local/tmp
然后还需要复制 Android NDK 的 libc++ :
$ adb push /path/to/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so /data/local/tmp
此外还需要复制在上一步中构建的 hello
可执行文件:
$ adb push hello /data/local/tmp
最终通过 adb shell
命令在 Android 设备上执行 hello
可执行文件:
$ adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/hello
而对于 Android 端来看,此时的 Swift 产物与 C/C++ 代码没什么区别 ,它必须作为一个标准的 .so
库被加载,并通过 JNI 规范暴露需要支持的能力。
目前 Swift 的核心标准库( stdlib
)已经可以成功在 Android 平台进行编译 ,也就是目前 String
、 Int
、 Array
和 Dictionary
等基础数据类型已经完成基本支持:
更高层次的核心库,比如 Foundation
( URLSession
、 JSONEncoder
)和 Dispatch
(提供并发支持),也正在被移植到 Android 平台。
而对于 UI 部分,目前 Swift 官方暂未提供任何支持 Android 的 UI 框架 ,官方文档目前表示:“ You’d need some sort of framework to build a user interface for your application, which the Swift stdlib does not provide ” 。
所以, 从这个层面看,它更像是 KMP 的存在 ,而如果需要类似 CMP 的支持,那么大概率需要 SwfitUI 的官方适配,毕竟 Skip 其实只是一个翻译框架。
而在互操作上,其实过去就有 swift-java 这个图的互操作方向的尝试,当时的目标是实现 Swift 与 Java 之间的双向互操作性,即支持 Swift 调用 Java 库,也支持 Java 调用 Swift 库 :
但是从官方描述来看, Swift on Android 似乎并没有直接使用类似桥接绑定,也就是你需要自己实现这部分,如果你需要的话:
而对于 Swift on Android 来说,要让一个 Swift 函数能被外部的 C 代码(以及遵循 C 调用约定的 JNI)所发现和调用,一般也就是通过 @_cdecl
属性,这个属性可以将函数编译成一个简单的、符合 C 语言标准的符号(Symbol)并暴露出去。
❝虽然没找到对应的 demo 或者实现,但是理论上如果想要不暴露接口,大概率还是通过
@_cdecl
。
所以目前 Swift on Android 给人的感觉确实很毛坯 ,在交互和 UI 上都很欠缺,看起来只是开源了一种可能,具体能达到什么效果暂时还看不出来,但是多少算是官方起了个头,也算是有了希望,对于 iOS 来说,这个春天还需要再等等。
那么,你觉得 Swift on Android 的存在多久可以达到生产标准?
没有回复内容