BookinglyTech News
Software

Bevy deja de enviar paquetes Swift en sus crates de iOS: ahora todo es Rust

rustunit reescribe los crates bevy_ios_* para hablar con los frameworks de Apple mediante objc2 y elimina el paquete Swift que había que añadir a Xcode.

3 min de lecturaLobsters0 vistas

Los crates bevy_ios_* ya no necesitan un paquete Swift en el proyecto de Xcode. rustunit los ha reescrito para que hablen con UIKit, GameKit y compañía a través de objc2 y sus bindings generados, así que instalar cualquiera de ellos vuelve a ser un cargo add y nada más. El puente entre Rust y la plataforma sigue existiendo, pero ahora es una dependencia más en lugar de algo que el crate tenga que compilar y publicar aparte.

Cuatro puentes distintos para el mismo problema

Hasta ahora cada crate viajaba en dos mitades: la de crates.io y un paquete SPM que había que añadir a mano en Xcode. El lado Swift o Objective-C vivía en ese paquete y Rust solo lo alcanzaba por símbolos C, así que cada proyecto se había fabricado su propio puente. Cuatro versiones distintas de lo mismo: @_cdecl en bevy_ios_safearea, Objective-C escrito a mano en alerts y review, protobuf cruzando el ABI de C en notifications, y swift-bridge con un .xcframework precompilado en gamecenter e iap.

Las consecuencias eran las de siempre. Cada README empezaba pidiendo el paso de SPM, la versión del crate y la del paquete tenían que coincidir (de ahí esos =0.6.0 en las instrucciones), y si no coincidían te enterabas al enlazar. Los crates con swift-bridge obligaban además a montar un pipeline que compilara el xcframework, lo comprimiera, lo hasheara y lo colgara de cada release. Y rust-bindgen rompía la compilación para aarch64-apple-ios-sim.

Objective-C tiene un runtime dinámico al que se puede apuntar de forma genérica —selectores, type encodings, objc_msgSend—, cosa que Swift no ofrece. Eso es lo que hace objc2 una vez, para todos los frameworks. El puente deja de ser algo que se envía.

La llamada de vuelta, la que antes justificaba todo el aparato de protobuf y swift-bridge, también se resuelve con objc2: se define una clase Objective-C en Rust con define_class! y se entrega a UIKit como delegado. En el ejemplo de las notificaciones, el delegado lanza el evento y llama al completion handler.

El ahorro en código: 2.809 líneas fuera de bevy_ios_notifications, 1.615 de ellas un Data.pb.swift generado, y 4.430 en bevy_ios_gamecenter.

Lo que cambia y la excepción

Para quien los use: no hay paquete SPM, no hay que enlazar GameKit o StoreKit a mano, y solo queda una versión que acertar en lugar de dos. gamecenter e iap vuelven a compilar para el simulador.

StoreKit 2 es la excepción. Es solo Swift, no hay runtime de Objective-C contra el que enlazar, así que bevy_ios_iap mantiene un pequeño shim Swift dentro del propio crate: build.rs lo compila con swiftc y lo enlaza estáticamente, y las dos partes hablan por un ABI de C con JSON. Sigue siendo un cargo add.

Las versiones publicadas son alerts 0.9, gamecenter 0.7, notifications 0.8, review 0.7 y safearea 0.7. iap va por la 0.11 y todavía no ha salido; está en main. No hay cambios grandes en las APIs públicas salvo en notifications, que sí conviene mirar antes de actualizar.