Reddit

Dropping Swift entirely from our Bevy iOS crates

Bevy iOS 크레이트에서 Swift 패키지를 없앴습니다

Bevy iOS 크레이트가 Swift 패키지와 수작업 브리지를 objc2 기반 Rust 바인딩으로 교체했습니다. 설치는 `cargo add`만으로 끝나고 GameKit·StoreKit 크레이트의 시뮬레이터 빌드도 다시 지원합니다. 단, Swift 전용인 StoreKit 2에는 작은 Swift 브리지를 남겼습니다.

AI 요약

Bevy iOS용 Rust 크레이트가 별도로 배포하던 Swift 패키지를 제거했습니다. 이전에는 Rust 크레이트와 Swift Package Manager(SPM) 패키지를 함께 Xcode 프로젝트에 추가해야 했지만, 이제 cargo add만 실행하면 됩니다. Rust와 iOS 플랫폼 사이의 언어 경계는 그대로지만, 프로젝트마다 직접 만들던 브리지와 패키지를 배포할 필요가 없어졌습니다.

브리지 네 종류를 objc2로 통합

기존 크레이트들은 서로 다른 방식으로 Rust와 플랫폼 코드를 연결했습니다. bevy_ios_safearea는 Swift 함수를 @_cdecl로 C 심볼에 노출했고, 알림과 리뷰 크레이트는 C 헤더 뒤에 Objective-C 코드를 두었습니다. 알림 크레이트는 protobuf 메시지를 C ABI로 직렬화했고, Game Center와 인앱 구매 크레이트는 swift-bridge와 사전 빌드한 .xcframework를 사용했습니다.

각 방식에는 관리 부담이 따랐습니다. 사용자는 README 안내에 따라 SPM 패키지를 추가해야 했고, Rust 크레이트와 Swift 패키지 버전도 맞춰야 했습니다. 버전이 어긋나면 링크 단계에서 문제가 드러났습니다. swift-bridge를 쓰는 크레이트는 매 릴리스마다 CI에서 .xcframework를 빌드하고, 압축·해시 처리한 뒤 GitHub 릴리스에 올렸습니다. 또 rust-bindgen이 aarch64-apple-ios-sim 빌드를 깨뜨려 시뮬레이터 빌드도 막혔습니다.

이제 Apple 프레임워크의 Objective-C 인터페이스를 objc2와 생성된 바인딩으로 호출합니다. objc2는 Objective-C 런타임의 셀렉터, 타입 인코딩, objc_msgSend를 이용합니다. 브리지를 각 크레이트가 따로 배포하는 대신 의존성으로 가져옵니다. 예를 들어 안전 영역 크레이트는 Swift 함수와 C 선언, Package.swift, SPM 설정을 거치지 않고 UIView를 받아 safeAreaInsets()를 호출합니다.

UIKit 콜백도 Rust에서 구현

플랫폼에서 Rust로 돌아오는 호출도 처리합니다. objc2의 define_class!로 Rust 안에 Objective-C 클래스를 정의한 뒤 UIKit의 델리게이트로 등록합니다. 알림 델리게이트 예시는 알림 식별자로 Bevy 이벤트를 만들고, 배너·목록·배지·사운드 표시 옵션을 완료 핸들러에 전달합니다. send_event가 플러그인에서 준비한 채널 송신자를 이용하므로 이벤트는 기존처럼 Bevy에 도착합니다.

이전 구현을 걷어내면서 bevy_ios_notifications에서는 2,809줄을 삭제했고, 그중 1,615줄은 생성된 Data.pb.swift 파일이었습니다. bevy_ios_gamecenter에서는 4,430줄이 줄었습니다. 푸시 알림 토큰 처리도 Swift의 메서드 스위즐링 대신 앱의 UIApplicationDelegate에 콜백을 추가하는 방식으로 바꿨습니다. 앱에 델리게이트가 없으면 크레이트가 만들고, bevy_ios_app_delegate가 이미 설정했다면 그 델리게이트를 연결해 사용합니다.

StoreKit 2에는 Swift 브리지를 유지

StoreKit 2는 Swift에서만 제공되고 Objective-C 런타임으로 바인딩할 수 없어 예외로 남았습니다. bevy_ios_iap은 작은 Swift 코드를 크레이트 내부에 두고, build.rs가 swiftc로 컴파일해 정적으로 링크합니다. 양쪽 코드는 직접 작성한 C ABI와 JSON으로 통신합니다. SPM 패키지나 .xcframework 릴리스는 필요하지 않지만, 이 버전은 글 작성 당시 아직 릴리스되지 않았습니다.

글에서 안내한 릴리스 버전은 alerts 0.9, gamecenter 0.7, notifications 0.8, review 0.7, safearea 0.7입니다. 기존 공개 API는 대부분 유지했지만 notifications는 변경 사항이 있으므로 변경 기록을 확인해야 합니다. 사용자는 Xcode 프로젝트에서 SPM 의존성을 지우고 Rust 크레이트 버전을 올리면 됩니다.

Reddit 반응

  • @u/teerre — Apple이 Objective-C를 전부 Swift로 바꾸려 한다고 생각했는데, Objective-C를 쓰는 건 과거로 돌아가는 것처럼 보입니다.
    • @u/annodomini — macOS와 iOS의 핵심 플랫폼 프레임워크는 모두 Objective-C로 작성됐고 Swift 바인딩을 제공합니다. Objective-C 런타임은 Rust에서 Swift보다 다루기 쉽습니다. Swift를 쓰려면 Swift 컴파일러가 필요하고, Swift를 감싸 C ABI 래퍼를 제공하는 스텁도 컴파일한 뒤 Rust에서 호출해야 합니다. 적절한 Objective-C 크레이트를 쓰면 별도의 Objective-C 컴파일러 없이 런타임을 바로 호출할 수 있습니다. Swift 패키지와 컴파일러 등을 관리하는 대신 Rust 크레이트만 빌드하고 실행하면 되므로 설정이 더 단순합니다.
    • @u/teerre — 알겠습니다, 감사합니다. 전환이 훨씬 많이 진행된 줄 알았습니다.
    • @u/heckingcomputernerd — macOS의 핵심 인프라에는 Swift가 아직 준비되지 않았다는 얘기를 자주 들었습니다. Reddit의 전 iOS 앱 Apollo를 만든 Christian도 Objective-C를 쓴 이유를 설명했던 기억이 납니다. 저는 이제 Apple 제품을 쓰지 않지만요.
    • @u/heckingcomputernerd — Rust로 Windows API를 다루면서 C#을 쓰려는 것과 비슷할 것 같습니다.

원문: rustunit.com / 번역·요약: Trawling