paint-brush
Come creare il tuo progetto Xcode per più piattaforme nell'ecosistema Appledi@darrylbayliss
165 letture Nuova storia

Come creare il tuo progetto Xcode per più piattaforme nell'ecosistema Apple

di Darryl Bayliss9m2025/02/12
Read on Terminal Reader

Troppo lungo; Leggere

Scopri come realizzare il tuo progetto Xcode per più piattaforme nell'ecosistema Apple.
featured image - Come creare il tuo progetto Xcode per più piattaforme nell'ecosistema Apple
Darryl Bayliss HackerNoon profile picture
0-item
1-item

A giugno 2023, quando Apple ha annunciato Vision Pro, ho avuto un'idea che poteva funzionare bene sul visore: una raccolta di video in loop riprodotti insieme al tuo utilizzo quotidiano. Avevo già un'app che poteva farlo chiamata Christmas Chill , qualcosa che ho creato quando è stata resa disponibile la prima Apple TV che supportava un App Store. Presenta una raccolta di video in loop che puoi usare come sfondo festivo.


Ogni anno, durante l'inverno, trascorro un paio di giorni a migliorarlo, aggiungendo nuovi contenuti e migliorando la base di codice. Una delle modifiche più importanti apportate al progetto è avvenuta a dicembre 2023, quando l'interfaccia utente è stata migrata da UIKit e Storyboard a SwiftUI.


Bene, per lo più migrato. Avevo bisogno di una vista supportata da AVPlayer racchiusa in un UIViewRepresentable . Un'ottima API che fornisce interoperabilità tra UIKit e SwiftUI, se mai ne avessi bisogno.


Ero stato un po' titubante a migrare prima perché avevo una buona comprensione della Declarative UI e dei suoi concetti da altri lavori con React e Jetpack Compose . Tutto è cambiato per me con l'introduzione di Apple Vision Pro e il suo supporto per SwiftUI. Christmas Chill è stato un bel progetto per mantenere aggiornate le mie conoscenze di Apple Dev, ed ero desideroso di acquisire esperienza espandendo l'app su dispositivi diversi.


Una volta completata la migrazione del 2023 a SwiftUI per Christmas Chill, nel 2024 ho iniziato ad aggiungere il supporto per Vision Pro. Di seguito, ecco come ho proceduto e cosa consiglio se stai cercando di fare lo stesso per le tue app.

Aggiunta di una nuova piattaforma

Per iniziare, il progetto deve essere in grado di compilare per Vision Pro come destinazione; farlo è sorprendentemente facile! All'interno di Xcode, seleziona il file .xcodeproj e, nel menu a discesa Supported Destinations , fai clic sul pulsante più.


Destinazioni supportate



Appare un menu a discesa di tutte le piattaforme Apple disponibili. Passa il mouse sulla piattaforma desiderata da aggiungere come destinazione, in questo caso Apple Vision, quindi fai clic su Apple Vision nella sezione appena visualizzata.


Aggiungi destinazione Apple Vision Pro



Apparirà un piccolo popup per informarti delle modifiche che Xcode deve apportare al target. Fai clic su Abilita .


Abilita supporto destinazione


Successivamente, crea l'app usando il visionOS Simulator. Se hai a portata di mano un Vision Pro, puoi trovare le istruzioni su come installarlo sul tuo dispositivo qui .


Durante la compilazione, è probabile che Xcode trovi errori del compilatore e/o che l'app si blocchi. Questo è previsto e una pratica di pazienza. Da questo punto, devi correggere gli errori nel tuo progetto finché l'app non compila e non si blocca più.


Nel mio caso, ci sono voluti circa 30 minuti, in parte grazie al duro lavoro svolto in precedenza per migrare l'app da UIKit a SwiftUI!

Blocchi di compilazione condizionale

SwiftUI, nel suo nucleo, è un framework multipiattaforma, il che significa che semplicemente compilando il codice SwiftUI per una piattaforma diversa, ne modificherà l'aspetto. Tenendo conto dello stile della piattaforma e di vari metodi di interazione.


Sebbene questo aiuti a fare rapidi progressi durante lo sviluppo, potresti voler avere più controllo su come appare l'app e sfruttare i punti di forza di ogni singola piattaforma. Un buon esempio sono le capacità di Immersion di Vision Pro; SwiftUI fornisce un'API per questo tramite ImmersiveSpace , un'API disponibile solo per visionOS.


Se hai provato a utilizzare questa API durante la compilazione del progetto per Apple TV, Xcode genererà un errore che informa che questa API non è disponibile.


Quindi, qual è la soluzione per evitare questa situazione? La risposta viene dall'uso dei Blocchi di Compilazione Condizionale . I Blocchi di Compilazione sono sezioni di codice che forniscono istruzioni su quando il compilatore dovrebbe compilare il codice all'interno del blocco.


Sebbene supportino una varietà di condizioni, la più utile per le nostre esigenze è rilevare per quale piattaforma il codice viene compilato. Puoi farlo con solo poche righe di codice:


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


Una bella funzionalità di Xcode per supportare i blocchi di compilazione condizionali è quella di chiarire quale codice verrà compilato a seconda della piattaforma selezionata per la compilazione. Inoltre, eliminerà leggermente il codice che non verrà compilato.


Blocchi di compilazione condizionale

Iniezione di dipendenza tramite fasi di build

Uno dei trucchi più utili che ho scoperto è usare le fasi di build Compile Sources e Copy Bundle Resources come una forma di dependency injection. Questi processi vengono eseguiti quando l'app viene compilata e possono essere trovati nella scheda Build Phases nel progetto Xcode.


Fasi di costruzione


Compile Sources si occupa del grosso lavoro di compilazione del codice sorgente in codice macchina. Che si tratti di Swift, Objective-C o persino C/C++.

Copy Bundle Resources copia tutte le risorse correlate per il target dell'app nell'App Bundle . Un contenitore di sorta per tutto il codice e le risorse dell'app, tra cui immagini, video, stringhe localizzabili e altro.


Queste due fasi di build offrono molta flessibilità alle app, poiché ogni nuovo target fornisce le proprie fasi di build, inclusi i due passaggi precedenti. Le app Whitelabel che forniscono alle aziende un modo per personalizzare i propri contenuti utilizzano questa tecnica, tra le altre.


Potresti scoprire di voler fornire contenuti diversi per le tue app, a seconda della piattaforma su cui vengono eseguite. Usiamo queste fasi di build a nostro vantaggio e forniamo due diverse fonti di contenuti per farlo.


Per prima cosa, utilizziamo unprotocollo Swift per fornire un contratto che prevede di essere eseguito da una struttura o da una classe.


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


Ora, diamo un'occhiata a due implementatori del protocollo. Ecco il primo:


 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 è l'implementazione concreta utilizzata per il primo target dell'app. Fornisce un array di Content , che fa riferimento ai nomi delle risorse trovati nel bundle dell'app per il target.


 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), ] } }


Il prossimo è TargetAppBContentManager , l'implementazione concreta utilizzata per il secondo target dell'app. Sembra molto simile alla prima implementazione, tranne per l'App B in cui gli identificatori sono diversi.


Con entrambe le implementazioni create, ora puoi farvi riferimento indirettamente nel tuo codice impostando il tipo dell'oggetto su ContentManager . Guarda l'esempio ViewModel qui sotto:


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


Il ViewModel si aspetta che un tipo di ContentManager venga passato tramite il suo inizializzatore. Il ViewModel può essere passato da entrambi i tipi di ContentManager e continuare a funzionare come previsto. Ciò significa anche che il ViewModel può essere riutilizzato in entrambi i target dell'app.


L'ultima cosa da fare è assicurarsi che il ContentManager corretto venga aggiunto alla fase Compile Sources. In questo caso, all'App A viene passato TargetAppAContentMananger come parte delle sue fonti e all'App B viene passato TargetAppBContentManager .


Aggiungere Content Manager alla fase di compilazione delle fonti

Aggiunta di risorse del bundle dell'app

L'ultima cosa rimasta da fare è assicurarsi che ogni Bundle dell'app contenga risorse con nomi che corrispondono agli identificatori utilizzati dall'app. Il modo più semplice è controllare la fase di build Copy Bundle Resources di ogni target dell'app e assicurarsi che le risorse siano referenziate dal content manager. In caso contrario, trascinale dal tuo progetto Xcode nella fase copy resources.


Questo richiede un po' di tempo e attenzione per il test, poiché non si riceve un errore in fase di compilazione se una risorsa a cui si fa riferimento non è disponibile nel bundle. Durante l'esecuzione, si verificherà un crash!


Un buon modo per automatizzare il controllo è scrivere un test unitario per confermare che tutte le risorse a cui fa riferimento ContentManager siano archiviate nel bundle. Se il test fallisce quando viene eseguito, allora sai che c'è una risorsa mancante nel bundle.

Dove andare adesso?

Se sei arrivato fin qui, dovresti avere una buona idea di come portare la tua app su altre piattaforme Apple.


Per concludere questo post, vi lascio un paio di suggerimenti e risorse che vi consiglio:


  1. Se si aggiunge il supporto Apple Vision a un'app esistente, per prima cosa, migrare quanto più codice possibile da UIKit a SwiftUI. Dopo aver visto la velocità di un'app esistente che funziona su Vision Pro quando migrata a SwiftUI, è utile poter contare su.


  2. Leggi la guida di Apple su come portare le app esistenti su visionOS . Fornisce utili suggerimenti e consigli su come farlo e come sfruttare le funzionalità di visionOS.


  3. Se stai pensando di iniziare una nuova app multipiattaforma, c'è una scheda Multiplatform disponibile in Xcode, che fornisce una serie di modelli di app da usare. C'è anche un video del WWDC 2022 sull'argomento.


  4. Se vuoi vedere esempi di app che funzionano su più piattaforme, ti consiglio di dare un'occhiata alle mie app personali Christmas Chill e Ocean Chill . Si tratta di due app che funzionano su tvOS e Vision Pro, create da un'unica base di codice. (il supporto tvOS per Ocean Chill arriverà presto!)