Skip to content

feat(sdk-flutter): add Swift Package Manager support to plugin_screeb - #19

Open
ScreebyBot wants to merge 5 commits into
masterfrom
screeby/sdk-flutter-ajouter-le-support-swift-pac-3d13a384-f7d
Open

feat(sdk-flutter): add Swift Package Manager support to plugin_screeb#19
ScreebyBot wants to merge 5 commits into
masterfrom
screeby/sdk-flutter-ajouter-le-support-swift-pac-3d13a384-f7d

Conversation

@ScreebyBot

@ScreebyBot ScreebyBot commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Contexte

Flutter 3.44 (stable) fait de Swift Package Manager le gestionnaire de paquets iOS/macOS par défaut, et CocoaPods passe en maintenance avant dépréciation. Sans support SPM, plugin_screeb risque des échecs de build sur les toolchains Flutter récentes. Demandé via l'issue GitHub #18 et une conversation Crisp (BetTube).

Cette PR inclut le support SPM initial plus les corrections issues de la vérification manuelle iOS/Xcode de @MD4 et des relectures suivantes.

Changement

Support SPM (d'après le guide officiel Flutter) :

  • Sources iOS réorganisées dans ios/plugin_screeb/Sources/plugin_screeb/, le layout attendu par l'outillage SPM, avec ios/plugin_screeb/Package.swift déclarant le plugin en target de bibliothèque SPM, dépendant du SDK natif via sa distribution SPM existante (ScreebApp/sdk-ios-public, exact: "4.2.0" — même version que le podspec).
  • Target Swift-only : le shim ObjC (PluginScreebPlugin.h/.m) est supprimé et la classe Swift renommée SwiftPluginScreebPluginPluginScreebPlugin pour matcher directement le ios.pluginClass du pubspec.yaml. SwiftPM refuse les targets mixtes Swift/ObjC sous tools-version 6.5 : le target n'aurait pas pu être résolu du tout, soit exactement l'échec que ce ticket vise à éviter. C'est aussi ainsi que flutter/packages livre ses propres plugins Swift.
  • source_files du podspec mis à jour (Swift uniquement) : les installs CocoaPods continuent de fonctionner — les deux gestionnaires restent supportés pendant la transition.
  • scripts/sync-sdk-versions.mjs corrigé (il pointait encore l'ancien chemin ios/Classes/SwiftPluginScreebPlugin.swift, ce qui cassait versions:check dans le job js de la CI) et étendu pour synchroniser aussi le pin exact: du Package.swift, afin que les versions natives SPM et CocoaPods ne puissent plus diverger.

Corrections de revue :

  • examples/example-flutter/ios/Podfile.lock désynchronisé (relevé par @MD4 : pod install échouait en conflit de version). Le lockfile est maintenant exactement celui que produirait pod install — chaque ligne vérifiée, pas supposée : versions à 4.2.0 ; plugin_screeb: 27bafe69… = sha1 du podspec courant ; PODFILE CHECKSUM: bbd322ee… = sha1 du Podfile courant ; et Screeb: 38aabbcb… recalculé depuis le podspec trunk officiel (CocoaPods/Specs, Specs/6/8/c/Screeb/4.2.0/Screeb.podspec.json). Méthode validée au passage : le podspec 4.0.3 hashe en ddb9f7cc…, exactement la valeur qui était committée ici (et celle du lockfile d'example-reactnative, qui épingle bien encore la 4.0.3).
  • Mode dev SDK local en SPM : Package.swift honore le même switch SCREEB_USE_LOCAL_SDK que le podspec. Un manifeste SwiftPM ne pouvant pas invoquer xcodebuild, le chemin local passe par un binaryTarget pointant un xcframework pré-construit via le script existant scripts/build-local-ios-xcframework.mjs (déjà utilisé par KMP/MAUI). L'artefact doit vivre dans le package (plugin_screeb/Screeb.xcframework, gitignoré), référencé par un chemin sans .. : Flutter résout le Package.swift d'un plugin à travers un symlink par build (ios/Flutter/ephemeral/Packages/.packages/<plugin>-<version>, cf. xcode_project.dart / _createPluginSymlink), et les chemins relatifs se résolvent depuis ce symlink, pas depuis l'emplacement réel du plugin — c'est la raison pour laquelle FlutterFramework est lui-même symlinké dans le package (« binary targets must be relative », swift_package_manager.dart). Documenté dans docs/screeb-team-release.md, avec le caveat que SwiftPM met en cache l'évaluation du manifeste par contenu de fichier et non par environnement — basculer SCREEB_USE_LOCAL_SDK peut nécessiter un flutter clean.
  • Mention SPM ajoutée au packages/sdk-flutter/README.md public (rien ne l'indiquait, hors doc interne de release).

Aucun changement d'API Dart ni de pubspec.yaml. Bump de version / entrée CHANGELOG volontairement omis : ce repo bumpe les versions liées au SDK natif via un commit de release automatisé séparé.

Tests

  • node scripts/sync-sdk-versions.mjs --check : passe.
  • flutter analyze (packages/sdk-flutter) : « No issues found! ».
  • flutter test (packages/sdk-flutter) : 6/6 tests passés (comportement Dart inchangé).
  • npm run lint (Lerna/eslint, gate du hook pre-commit) : passe — les warnings restants sont pré-existants et hors diff (sdk-browser).
  • Lacune connue, à lever avant merge : rien ici n'exerce le code iOS. Cet environnement n'a ni macOS, ni Xcode, ni CocoaPods, ni toolchain swift, et le job flutter de la CI (.github/workflows/ci.yml) est Dart-only (pub get / analyze / test) — il ne build jamais iOS. En particulier, la branche SCREEB_USE_LOCAL_SDK=true du Package.swift n'est exercée par aucune gate et aucun swift build / flutter build ios n'a été lancé. Le correctif de chemin s'appuie sur la lecture directe des sources flutter_tools 3.44.9 citées ci-dessus, et le lockfile sur des sha1 recalculés depuis les podspecs trunk officiels — mais une validation macOS/Xcode (pod install sans réécriture du lockfile + build SPM des deux modes) reste nécessaire.

Flutter 3.44 makes SPM the default plugin package manager and CocoaPods
is moving to maintenance-only, so plugin_screeb needs both to keep
building for consumers. Reorganizes the iOS sources into the layout
Flutter's plugin-authors guide requires (ios/plugin_screeb/Sources/plugin_screeb
with public headers under include/plugin_screeb), adds the matching
Package.swift wiring the native Screeb iOS SDK via its existing SPM
distribution (pinned to 4.2.0, same as the podspec), and updates the
podspec paths so CocoaPods installs keep working unchanged.
SwiftPM rejects mixed Swift/Objective-C targets below tools-version
6.5. The previous SPM target mixed PluginScreebPlugin.m/.h with
SwiftPluginScreebPlugin.swift under swift-tools-version 5.9, so
package resolution failed outright for any Flutter app on SwiftPM --
exactly the build failure this support was meant to prevent. Drops
the Objective-C registration shim (which also relied on the
plugin_screeb-Swift.h compatibility header SwiftPM does not generate
for non-mixed targets) and renames the Swift plugin class to
PluginScreebPlugin so it matches pubspec.yaml's existing
ios.pluginClass directly, the same approach flutter/packages uses for
its own Swift-only plugins.

Also fixes scripts/sync-sdk-versions.mjs, which still pointed at the
old ios/Classes/SwiftPluginScreebPlugin.swift path (broken by the
prior SPM restructuring commit and failing `versions:check`), and
wires the new Package.swift pin into the same release sync so the
SPM and CocoaPods native SDK versions can't drift apart.
Address PR #19 review feedback: the committed example Podfile.lock still
pinned Screeb 4.0.3 while the podspec/Package.swift require 4.2.0, which
made `pod install` fail on a version conflict until a manual `pod update
Screeb`. Bump the lockfile's PODS/SPEC CHECKSUMS to 4.2.0 (recomputed the
plugin_screeb spec checksum from its current podspec; Screeb's remains
whatever CocoaPods trunk publishes and self-corrects on the next install
since it isn't a :path pod).

Also give the SPM manifest a SCREEB_USE_LOCAL_SDK dev path so plugin
authors aren't locked into CocoaPods to iterate on an unpublished native
SDK change. Since a Package.swift manifest can't invoke xcodebuild the
way the podspec's :path dependency can, it swaps in a local binaryTarget
built ahead of time by the existing build-local-ios-xcframework.mjs
script instead, documented alongside the other local-SDK flows in
docs/screeb-team-release.md.
The local-SDK binaryTarget in Package.swift used a path relying on
`..` to reach a xcframework built at the monorepo root
(../../../../.local/ios/Screeb.xcframework). Flutter resolves a
plugin's Package.swift through a per-build symlink under
ios/Flutter/ephemeral/Packages/.packages/<plugin>-<version>, and
relative paths in the manifest resolve against that symlink's own
location, not the plugin's real path in this monorepo — confirmed by
reading flutter_tools' swift_package_manager.dart, which symlinks
FlutterFramework's own binaryTarget inside that same directory for
exactly this reason ("binary targets must be relative"). The old path
resolved to <app>/ios/Flutter/.local/ios/Screeb.xcframework, which the
documented build command never wrote to.

Move the artifact inside the plugin package itself
(plugin_screeb/Screeb.xcframework) and reference it with a `..`-free,
package-root-relative path, which resolves identically whether or not
it's read through the symlink. Update the documented build command and
.gitignore entry to match, and note that toggling SCREEB_USE_LOCAL_SDK
may need a `flutter clean` since SwiftPM caches manifest evaluation by
file content, not by environment. Also add a short SPM mention to the
public README, since nothing previously said the plugin supports it.

Known residual limitation carried over from the previous fix: the
Podfile.lock's Screeb (not plugin_screeb) SPEC CHECKSUM is still the
one computed for 4.0.3's podspec, not 4.2.0's — it can't be recomputed
without a real `pod install` on macOS, which isn't available here. This
doesn't block `pod install` (a stale checksum on a non-:path pod just
triggers a redownload, unlike the version conflict fixed previously),
but is a known gap to close with a real `pod install` before merge.
The Screeb SPEC CHECKSUM was still the one computed for the 4.0.3
podspec, even though the rest of the lockfile was bumped to 4.2.0, so
`pod install` would still see the pod as changed and rewrite the line —
the very lockfile/podspec desync the bump was meant to remove.

Recomputed from the official trunk podspecs (CocoaPods/Specs, path
Specs/6/8/c/Screeb/<version>/Screeb.podspec.json): 4.0.3 hashes to
ddb9f7cca468c375406d607d949ffea34809d009, which is exactly the value
that was committed here (and the one in example-reactnative's lockfile,
which does still pin 4.0.3) — that match confirms the method — and
4.2.0 hashes to 38aabbcb171c850e1d30d4037c2a5fe7547c20ea.

Every remaining checksum in the file was verified rather than assumed:
plugin_screeb 27bafe69… is the sha1 of the current podspec and PODFILE
CHECKSUM bbd322ee… is the sha1 of the current Podfile, both unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants