paint-brush
Cómo crear un proyecto Xcode para múltiples plataformas en el ecosistema de Applepor@darrylbayliss
165 lecturas Nueva Historia

Cómo crear un proyecto Xcode para múltiples plataformas en el ecosistema de Apple

por Darryl Bayliss9m2025/02/12
Read on Terminal Reader

Demasiado Largo; Para Leer

Aprenda a crear su proyecto Xcode para múltiples plataformas en el ecosistema de Apple.
featured image - Cómo crear un proyecto Xcode para múltiples plataformas en el ecosistema de Apple
Darryl Bayliss HackerNoon profile picture
0-item
1-item

En junio de 2023, cuando Apple anunció Vision Pro, tuve una idea que podría funcionar bien en el auricular: una colección de videos en bucle que se reproduzcan junto con el uso diario. Ya tenía una aplicación que podía hacer esto llamada Christmas Chill , algo que creé cuando se lanzó el primer Apple TV compatible con una App Store. Incluye una colección de videos en bucle que puedes usar como fondo festivo.


Cada año, durante el invierno, dedico un par de días a mejorarlo, a añadir contenido nuevo y a mejorar el código base. Uno de los cambios más importantes que se realizaron en el proyecto se produjo en diciembre de 2023, cuando se migró la interfaz de usuario de UIKit y Storyboards a SwiftUI.


Bueno, ya casi he migrado. Necesitaba una vista respaldada por AVPlayer envuelta en un UIViewRepresentable . Una API excelente que proporciona interoperabilidad entre UIKit y SwiftUI, si alguna vez la necesitas.


Había dudado un poco en migrar antes, ya que tenía un buen conocimiento de la interfaz de usuario declarativa y sus conceptos gracias a otros trabajos con React y Jetpack Compose . Eso cambió para mí con la introducción de Apple Vision Pro y su compatibilidad con SwiftUI. Christmas Chill ha sido un buen proyecto para mantener actualizados mis conocimientos de desarrollo de Apple y estaba ansioso por adquirir experiencia ampliando la aplicación a diferentes dispositivos.


Una vez que se completó la migración de 2023 a SwiftUI para la temporada navideña, me propuse agregar compatibilidad con Vision Pro en 2024. A continuación, se muestra cómo lo hice y lo que recomiendo si está tratando de hacer lo mismo con sus propias aplicaciones.

Agregar una nueva plataforma

Para comenzar, el proyecto debe poder compilarse para Vision Pro como destino. ¡Hacerlo es sorprendentemente fácil! Dentro de Xcode, seleccione el archivo .xcodeproj y, en el menú desplegable Destinos admitidos , haga clic en el botón más.


Destinos admitidos



Aparecerá un menú desplegable con todas las plataformas de Apple disponibles. Pase el cursor sobre la plataforma que desee agregar como destino (en este caso, Apple Vision) y luego haga clic en Apple Vision en la sección que aparece.


Agregar destino de Apple Vision Pro



Aparecerá una pequeña ventana emergente para informarle sobre los cambios que Xcode debe realizar en el destino. Haga clic en Habilitar .


Habilitar soporte de destino


A continuación, crea la aplicación con el simulador de visionOS. Si tienes un Vision Pro a mano, puedes encontrar instrucciones sobre cómo instalarlo en tu dispositivo aquí .


Durante la compilación, es probable que Xcode encuentre errores de compilación o que la aplicación se bloquee. Esto es algo que se espera y es una práctica que se debe practicar con paciencia. A partir de este punto, debes corregir los errores en tu proyecto hasta que la aplicación se compile y ya no se bloquee.


En mi caso, esto tomó alrededor de 30 minutos, ¡en parte gracias al arduo trabajo de migrar la aplicación de UIKit a SwiftUI previamente!

Bloques de compilación condicional

SwiftUI, en esencia, es un marco multiplataforma, lo que significa que con solo compilar el código de SwiftUI para una plataforma diferente, se modificará su apariencia, teniendo en cuenta el estilo de la plataforma y varios métodos de interacción.


Si bien esto ayuda a avanzar rápidamente durante el desarrollo, es posible que desee tener más control sobre cómo se ve la aplicación y aprovechar las fortalezas de cada plataforma individual. Un buen ejemplo son las capacidades de inmersión de Vision Pro; SwiftUI proporciona una API para esto a través de ImmersiveSpace , una API solo disponible para visionOS.


Si intentaste usar esta API mientras compilabas el proyecto para Apple TV, Xcode arrojará un error informando que esta API no está disponible.


Entonces, ¿cuál es la solución para evitar esta situación? La respuesta viene del uso de bloques de compilación condicional . Los bloques de compilación son secciones de código que proporcionan instrucciones sobre cuándo el compilador debe compilar el código dentro del bloque.


Si bien admiten una variedad de condiciones, la más útil para nuestras necesidades es detectar para qué plataforma se está compilando el código. Puedes hacer esto con solo unas pocas líneas de código:


 var body: some Scene { #if os(tvOS) WindowGroup { HStack { Text("I am running on tvOS!") } } #elseif os(visionOS) ImmersiveSpace(id: "MyImmersiveSpace") { } #endif }


Una característica interesante de Xcode para admitir bloques de compilación condicional es que deja en claro qué código se compilará según la plataforma seleccionada para la compilación. También difumina ligeramente el código que no se compilará.


Bloques de compilación condicional

Inyección de dependencias mediante fases de compilación

Uno de los trucos más útiles que he encontrado es usar las fases de compilación Compilar fuentes y Copiar recursos del paquete como una forma de inyección de dependencia. Estos procesos se ejecutan cuando se compila la aplicación y se pueden encontrar en la pestaña Fases de compilación en el Proyecto Xcode.


Fases de construcción


Compile Sources se encarga de la tarea pesada de compilar el código fuente en código de máquina, ya sea Swift, Objective-C o incluso C/C++.

Copiar recursos del paquete copia todos los recursos relacionados con el destino de la aplicación en el paquete de aplicaciones . Una especie de contenedor para todo el código y los recursos de la aplicación, incluidas imágenes, videos, cadenas localizables y más.


Estas dos fases de desarrollo brindan mucha flexibilidad a las aplicaciones, ya que cada nuevo objetivo proporciona sus propias fases de desarrollo, incluidos los dos pasos anteriores. Las aplicaciones de marca blanca que brindan a las empresas una forma de personalizar su contenido utilizan esta técnica, entre otras.


Es posible que desees proporcionar contenido diferente para tus propias aplicaciones, según la plataforma en la que se ejecuten. Usemos estas fases de compilación a nuestro favor y proporcionemos dos fuentes de contenido diferentes para lograrlo.


Primero, usemos unprotocolo Swift para proporcionar un contrato que espera ser cumplido por una estructura o clase.


 protocol ContentManager { var content: [Content] { get } }


A continuación, echemos un vistazo a dos implementadores del protocolo. Aquí está el primero:


 class TargetAppAContentManager : ContentManager { var content: [Content] { return [ Content(name: TargetAppAContentIdentifier.videoOneName.rawValue, image: TargetAppAImagePreviewIdentifier.videoOnePreview.rawValue, video: TargetAppAImageVideoIdentifier.videoOneVideo.rawValue), Content(name: TargetAppAContentIdentifier.videoTwoName.rawValue, image: TargetAppAImagePreviewIdentifier.videoTwoPreview.rawValue, video: TargetAppAImageVideoIdentifier.videoTwoVideo.rawValue), Content(name: TargetAppAContentIdentifier.videoThreeName.rawValue, image: TargetAppAImagePreviewIdentifier.videoThreePreview.rawValue, video: TargetAppAImageVideoIdentifier.videoThreeVideo.rawValue), ] return contentToShow } }


TargetAppAContentManager es la implementación concreta que se utiliza para el primer objetivo de la aplicación. Proporciona una matriz de Content que hace referencia a los nombres de recursos que se encuentran en el paquete de la aplicación para el objetivo.


 class TargetAppBContentManager : ContentManager { var content: [Content] { return [ Content(name: TargetAppBContentIdentifier.videoOneName.rawValue, image: TargetAppBImagePreviewIdentifier.videoOnePreview.rawValue, video: TargetAppBImageVideoIdentifier.videoOneVideo.rawValue), Content(name: TargetAppBContentIdentifier.videoTwoName.rawValue, image: TargetAppBImagePreviewIdentifier.videoTwoPreview.rawValue, video: TargetAppBImageVideoIdentifier.videoTwoVideo.rawValue), Content(name: TargetAppBContentIdentifier.videoThreeName.rawValue, image: TargetAppBImagePreviewIdentifier.videoThreePreview.rawValue, video: TargetAppBImageVideoIdentifier.videoThreeVideo.rawValue), ] } }


A continuación, se encuentra TargetAppBContentManager , la implementación concreta utilizada para el segundo objetivo de la aplicación. Parece muy similar a la primera implementación, excepto que para la aplicación B los identificadores son diferentes.


Una vez creadas ambas implementaciones, puedes hacer referencia a ellas indirectamente en tu código estableciendo el tipo de objeto en ContentManager . Consulta el siguiente ejemplo de ViewModel:


 @Observable class VideoListViewModel { var contentManager: ContentManager init(contentManager: ContentManager) { self.contentManager = contentManager } }


ViewModel espera que se pase un tipo de ContentManager a través de su inicializador. ViewModel puede ser transferido por cualquier tipo de ContentManager y continuar funcionando como se espera. Esto también significa que ViewModel puede reutilizarse en ambos destinos de la aplicación.


Lo último que hay que hacer es asegurarse de que se agregue el ContentManager correcto a la fase de compilación de fuentes. En este caso, a la aplicación A se le pasa TargetAppAContentMananger como parte de sus fuentes y a la aplicación B se le pasa TargetAppBContentManager .


Añadir el administrador de contenido a la fase de compilación de fuentes

Cómo agregar recursos de App Bundle

Lo último que queda por hacer es asegurarse de que cada paquete de aplicaciones contenga recursos con nombres que coincidan con los identificadores utilizados por la aplicación. La forma más sencilla es comprobar la fase de compilación Copy Bundle Resources de cada destino de la aplicación y asegurarse de que el administrador de contenido haga referencia a los recursos. Si no es así, arrástrelos desde su proyecto de Xcode a la fase de copia de recursos.


Esto requiere un poco de tiempo y cuidado para probarlo, ya que no recibirá un error en tiempo de compilación si un recurso al que se hace referencia no está disponible en el paquete. Durante el tiempo de ejecución, se producirá un bloqueo.


Una buena forma de automatizar la comprobación es escribir una prueba unitaria para confirmar que todos los recursos a los que hace referencia ContentManager están almacenados en el paquete. Si la prueba falla al ejecutarse, sabrá que falta un recurso en el paquete.

¿A dónde ir después?

Si has llegado hasta aquí, deberías tener una buena idea de cómo llevar tu aplicación a otras plataformas de Apple.


Para finalizar este post os dejo un par de consejos y recursos que recomiendo:


  1. Si agrega compatibilidad con Apple Vision a una aplicación existente, primero migre la mayor cantidad posible de código de UIKit a SwiftUI. Después de ver la velocidad de una aplicación existente que funciona en Vision Pro cuando se migra a SwiftUI, es útil poder confiar en ella.


  2. Lee la guía de Apple sobre cómo incorporar aplicaciones existentes a visionOS . Ofrece consejos y sugerencias útiles sobre cómo hacerlo y cómo aprovechar las funciones de visionOS.


  3. Si estás pensando en crear una nueva aplicación multiplataforma, en Xcode hay una pestaña Multiplataforma que ofrece varias plantillas de aplicaciones para usar. También hay un video de la WWDC 2022 sobre el tema.


  4. Si quieres ver ejemplos de aplicaciones que funcionan en varias plataformas, te recomiendo que eches un vistazo a mis aplicaciones personales Christmas Chill y Ocean Chill . Se trata de dos aplicaciones que funcionan en tvOS y Vision Pro, creadas a partir de una única base de código. (¡Pronto habrá compatibilidad con tvOS para Ocean Chill!)