[{"data":1,"prerenderedAt":22},["ShallowReactive",2],{"articolo-swift-package-manager-in-flutter-addio-graduale-a-cocoapods":3,"comments-article-swift-package-manager-in-flutter-addio-graduale-a-cocoapods":21},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"cover_remote_url":9,"cover_credit":9,"video_url":9,"status":10,"published_at":11,"meta_title":12,"meta_description":13,"category":14,"author":18},128,"Swift Package Manager in Flutter: addio (graduale) a CocoaPods","swift-package-manager-in-flutter-addio-graduale-a-cocoapods","Flutter sta migrando la gestione delle dipendenze iOS e macOS da CocoaPods a Swift Package Manager. Vediamo come abilitarlo, come migrare un'app esistente, come aggiungere il supporto SPM a un plugin e come gestire CI e troubleshooting.","## Perché Flutter sta passando a Swift Package Manager\n\nPer anni la gestione delle dipendenze native su iOS e macOS in Flutter è stata affidata a **CocoaPods**: un tool Ruby, esterno alla toolchain Apple, che richiede installazione separata, aggiornamenti continui e che è la causa di una quota enorme delle segnalazioni di build rotte (il classico `pod install` che fallisce dopo un aggiornamento di Xcode o di Ruby).\n\n**Swift Package Manager (SPM)** è invece integrato direttamente in Xcode e nella toolchain Swift. Il team Flutter ha iniziato la migrazione con l'obiettivo di:\n\n- eliminare la dipendenza da Ruby e CocoaPods nel setup di sviluppo;\n- permettere ai plugin di usare l'enorme ecosistema di pacchetti Swift già esistente;\n- allinearsi agli strumenti ufficiali Apple, con build più prevedibili.\n\nIl supporto è arrivato in **preview per iOS** con Flutter 3.24 e si è esteso a **macOS** nelle versioni successive. CocoaPods non sparisce da un giorno all'altro: i due sistemi **convivono**, e Flutter usa SPM per i plugin che lo supportano e CocoaPods per tutti gli altri.\n\n## Abilitare SPM nel proprio ambiente\n\nIl supporto è dietro un feature flag globale della CLI:\n\n```bash\nflutter config --enable-swift-package-manager\n```\n\nPer disabilitarlo:\n\n```bash\nflutter config --no-enable-swift-package-manager\n```\n\nRequisiti tipici: **Xcode 15 o superiore**, deployment target minimo **iOS 12** \u002F **macOS 10.14** (SPM non supporta target più bassi per i plugin Flutter).\n\nUn modo veloce per verificare lo stato dei flag:\n\n```bash\nflutter config --list\nflutter doctor -v\n```\n\n## Migrare un'app esistente\n\nLa parte sorprendente è che **non esiste un comando di migrazione dedicato**: una volta abilitato il flag, basta eseguire\n\n```bash\nflutter run\n# oppure\nflutter build ios\n```\n\ne lo strumento modifica automaticamente il progetto Xcode. In concreto vengono aggiunti:\n\n1. una build phase chiamata **\"Run Prepare Flutter Framework Script\"** nel target Runner;\n2. un pacchetto locale generato, `FlutterGeneratedPluginSwiftPackage`, posizionato in `ios\u002FFlutter\u002Fephemeral\u002FPackages\u002F` (o `macos\u002FFlutter\u002Fephemeral\u002FPackages\u002F`), che elenca come dipendenze i plugin SPM-ready;\n3. il riferimento al pacchetto dentro `Runner.xcodeproj`.\n\nLe modifiche a `Runner.xcodeproj` vanno **committate**, perché fanno parte della configurazione del progetto. La cartella `ephemeral` è invece già ignorata dal `.gitignore` standard di Flutter e viene rigenerata ad ogni build.\n\nDa quel momento, per ogni plugin Flutter verifica se esiste un `Package.swift`: se sì lo integra via SPM, altrimenti continua a passarlo a CocoaPods. Nei log con `flutter run -v` si leggono righe del tipo \"Adding Swift Package Manager integration\" e l'elenco dei plugin gestiti da ciascun sistema.\n\n### Disattivare SPM per un singolo progetto\n\nSe un'app ha problemi (per esempio script o post_install complessi nel Podfile), si può restare su CocoaPods solo per quel progetto aggiungendo in cima a `ios\u002FPodfile`:\n\n```ruby\n# Mantieni CocoaPods per questo progetto\ndisable_swift_package_manager!\n\nplatform :ios, '13.0'\n```\n\n## Aggiungere il supporto SPM a un plugin\n\nSe mantenete un plugin su pub.dev, aggiungere SPM significa **affiancare** un `Package.swift` al `.podspec` esistente, senza rompere gli utenti ancora su CocoaPods. La struttura attesa è questa:\n\n```\nmy_plugin\u002F\n└── ios\u002F\n    ├── my_plugin\u002F\n    │   ├── Package.swift\n    │   └── Sources\u002F\n    │       └── my_plugin\u002F\n    │           ├── MyPlugin.swift\n    │           └── Resources\u002F\n    └── my_plugin.podspec\n```\n\nNota la cartella intermedia con lo stesso nome del plugin: è lì che Flutter cerca il manifest SPM.\n\nUn `Package.swift` minimale:\n\n```swift\n\u002F\u002F swift-tools-version: 5.9\nimport PackageDescription\n\nlet package = Package(\n  name: \"my_plugin\",\n  platforms: [\n    .iOS(\"12.0\")\n  ],\n  products: [\n    \u002F\u002F Il nome del prodotto non può coincidere con quello del target:\n    \u002F\u002F per convenzione si usano i trattini.\n    .library(name: \"my-plugin\", targets: [\"my_plugin\"])\n  ],\n  dependencies: [],\n  targets: [\n    .target(\n      name: \"my_plugin\",\n      dependencies: [],\n      resources: [\n        .process(\"Resources\")\n      ],\n      cSettings: [\n        .headerSearchPath(\"include\u002Fmy_plugin\")\n      ]\n    )\n  ]\n)\n```\n\nPunti di attenzione:\n\n- **Nomi**: il target deve chiamarsi come il plugin (snake_case), il prodotto `library` deve avere un nome diverso (per convenzione con i trattini).\n- **Sorgenti**: devono stare in `Sources\u002F\u003Cnome_target>\u002F`. Se prima erano in `ios\u002FClasses\u002F`, vanno spostate; aggiornate il `.podspec` con `s.source_files = 'my_plugin\u002FSources\u002Fmy_plugin\u002F**\u002F*.swift'` così i due sistemi puntano agli stessi file.\n- **Risorse**: con SPM si accedono tramite `Bundle.module`, mentre con CocoaPods servono i bundle classici. Una soluzione comune è un helper condizionale:\n\n```swift\nextension Bundle {\n  static var pluginBundle: Bundle {\n    #if SWIFT_PACKAGE\n      return Bundle.module\n    #else\n      return Bundle(for: MyPlugin.self)\n    #endif\n  }\n}\n```\n\n- **Dipendenze native di terze parti**: una libreria disponibile come Swift Package si dichiara in `dependencies`, mentre un framework binario si integra con `.binaryTarget(name:path:)` puntando a un `.xcframework`.\n- **Registrazione del plugin**: non cambia nulla lato Dart né lato registrazione; il `FlutterPlugin` continua a esporre `register(with:)` come sempre.\n\n```swift\npublic class MyPlugin: NSObject, FlutterPlugin {\n  public static func register(with registrar: FlutterPluginRegistrar) {\n    let channel = FlutterMethodChannel(\n      name: \"my_plugin\",\n      binaryMessenger: registrar.messenger()\n    )\n    let instance = MyPlugin()\n    registrar.addMethodCallDelegate(instance, channel: channel)\n  }\n\n  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {\n    switch call.method {\n    case \"getPlatformVersion\":\n      result(\"iOS \" + UIDevice.current.systemVersion)\n    default:\n      result(FlutterMethodNotImplemented)\n    }\n  }\n}\n```\n\nE dal lato Dart nulla cambia:\n\n```dart\nimport 'package:flutter\u002Fservices.dart';\n\nclass MyPlugin {\n  static const _channel = MethodChannel('my_plugin');\n\n  static Future\u003CString?> getPlatformVersion() {\n    return _channel.invokeMethod\u003CString>('getPlatformVersion');\n  }\n}\n```\n\n### Testare entrambe le modalità\n\nPrima di pubblicare, conviene verificare che l'app di esempio compili in tutti e due gli scenari:\n\n```bash\n# Con SPM attivo\nflutter config --enable-swift-package-manager\ncd example && flutter clean && flutter build ios --no-codesign\n\n# Con CocoaPods\nflutter config --no-enable-swift-package-manager\ncd example && flutter clean && flutter build ios --no-codesign\n```\n\nNei test CI dei plugin ufficiali questa doppia matrice è la norma: è l'unico modo per non rompere gli utenti che non hanno ancora abilitato il flag.\n\n## Impatti su CI\u002FCD\n\nAlcune accortezze quando spostate la build su una pipeline:\n\n- **Abilitate il flag nel job**, altrimenti la build userà CocoaPods anche se il progetto è già migrato: aggiungete `flutter config --enable-swift-package-manager` prima di `flutter build`.\n- **Rete**: la risoluzione dei pacchetti SPM scarica dipendenze remote. Se usate runner con rete limitata, può servire un mirror o una cache.\n- **Cache**: i pacchetti risolti finiscono nella DerivedData e in `~\u002FLibrary\u002FCaches\u002Forg.swift.swiftpm`. Cachearli riduce sensibilmente i tempi.\n- **Risoluzione anticipata**: per fallire presto e in modo leggibile si può lanciare\n\n```bash\nxcodebuild -resolvePackageDependencies -workspace ios\u002FRunner.xcworkspace -scheme Runner\n```\n\n- Finché esiste almeno un plugin solo-CocoaPods, **CocoaPods resta necessario** sul runner: la migrazione completa dell'ecosistema richiederà tempo.\n\n## Troubleshooting dei problemi più comuni\n\n- **\"Couldn't find package\" \u002F pacchetto non risolto**: in Xcode usate *File → Packages → Reset Package Caches*, poi `flutter clean` e ricompilate.\n- **Deployment target troppo basso**: se il progetto punta a iOS 11, SPM si rifiuta di integrare i plugin. Alzate `platform :ios, '13.0'` nel Podfile e `IPHONEOS_DEPLOYMENT_TARGET` nelle build settings.\n- **Plugin non trovato dopo la migrazione**: controllate che la build phase \"Run Prepare Flutter Framework Script\" sia presente nel target Runner e che `ios\u002FFlutter\u002Fephemeral\u002FPackages\u002F` venga rigenerata.\n- **Progetti Xcode molto personalizzati**: se avete script custom o target multipli, valutate di restare temporaneamente su CocoaPods con `disable_swift_package_manager!` e migrare in un secondo momento.\n- **Risorse mancanti a runtime**: quasi sempre è il discorso `Bundle.module` vs `Bundle(for:)` visto sopra.\n\n## Conviene migrare adesso?\n\nPer un'**app in produzione** la migrazione è a basso rischio ma non urgente: potete abilitare il flag su un branch, verificare che tutti i plugin usati compilino e misurare i tempi di build. Il rollback è immediato (`--no-enable-swift-package-manager` o `disable_swift_package_manager!`).\n\nPer chi **mantiene un plugin**, invece, conviene agire subito: aggiungere un `Package.swift` accanto al `.podspec` è retrocompatibile al 100% e, man mano che il flag diventerà il default, eviterà agli utenti di dover installare CocoaPods solo per causa vostra.\n\nLa direzione è chiara: in un futuro non troppo lontano un nuovo progetto Flutter per iOS e macOS si compilerà senza Ruby, senza Podfile e senza `pod install`. Arrivarci con anticipo significa evitare la fretta quando il cambio diventerà obbligatorio.",null,"published","2026-10-15T04:01:33+00:00","Swift Package Manager in Flutter: guida alla migrazione","Come abilitare Swift Package Manager in Flutter, migrare un'app iOS\u002FmacOS da CocoaPods, aggiungere Package.swift a un plugin e gestire CI e troubleshooting.",{"id":15,"name":16,"slug":17},2,"Novità","novita",{"id":19,"name":20},1,"Flutter Bot",[],1792316901584]