Skip to content

fix(flutter): name the iOS podspec after the pub package (pulsar_haptics) - #141

Merged
piaskowyk merged 1 commit into
software-mansion:mainfrom
ilya-clicapin:fix/flutter-cocoapods-podspec-name
Aug 10, 2026
Merged

fix(flutter): name the iOS podspec after the pub package (pulsar_haptics)#141
piaskowyk merged 1 commit into
software-mansion:mainfrom
ilya-clicapin:fix/flutter-cocoapods-podspec-name

Conversation

@ilya-clicapin

Copy link
Copy Markdown
Contributor

Fixes #140.

What was broken

Flutter derives the expected podspec filename from the pub package name, so it looked for flutter/pulsar/ios/pulsar_haptics.podspec. The file was named pulsar.podspec, and because ios/pulsar_haptics/Package.swift is present the tooling concluded the plugin is Swift Package Manager only. In an app that uses CocoaPods, flutter pub get ends with:

Plugin pulsar_haptics is only compatible with Swift Package Manager. Try enabling Swift Package Manager by running "flutter config --enable-swift-package-manager" or remove the plugin as a dependency.

The pub name also drives the module GeneratedPluginRegistrant imports (@import pulsar_haptics;), so even forcing the pod in by hand would have built it under the wrong module name.

Changes

  • Rename flutter/pulsar/ios/pulsar.podspec to ios/pulsar_haptics.podspec and set s.name = 'pulsar_haptics'.
  • Tag s.version with a pulsar-sync:flutter-version marker so scripts/sync-sdk-versions.mjs keeps it in step with the pub version — it was stuck at 0.0.1 while the package is at 0.0.3.
  • Point scripts/sync-sdk-versions.mjs at the new filename (it would otherwise throw on the old path).
  • Drop the stale references to a podspec named pulsar from CONTRIBUTING.md and from the SPM comment in _build-ios-flutter.yml (that workflow's symlink dance is unchanged — the mirror is now pulsar_haptics, but routing through a uniquely-named symlink still costs nothing).
  • Example app: regenerate ios/Podfile.lock, and drop use_frameworks! — see below.

The use_frameworks! caveat

CocoaPods' target validator compares product module names case-insensitively, so the plugin pod pulsar_haptics collides with the module CocoaPods derives for the native pod Pulsar-haptics (Pulsar_haptics):

[!] The 'Pods-Runner' target has frameworks with conflicting names: pulsar_haptics.

This only triggers when the app opts into frameworks; with the default static linkage pod install is fine. That's why the example app's Podfile drops use_frameworks!, with a comment pointing here.

The real fix is s.module_name = 'Pulsar' on iOS/Pulsar/Pulsar-haptics.podspec — that is the module name the Swift Package already exposes, and the Flutter bridge's #if canImport(Pulsar_haptics) / #elseif canImport(Pulsar) shim already accepts both — but it only takes effect once a native pod carrying it is published, so I left it out. Happy to fold it in if you'd rather ship both together.

Verification

Flutter 3.44.0, Xcode 26.5, CocoaPods 1.16.2, on flutter/PulsarApp.

With SPM disabled (flutter config --no-enable-swift-package-manager), which is the configuration from the issue:

  • flutter pub get — succeeds (fails on main with the error above)
  • pod install — installs Flutter, Pulsar-haptics (1.1.2), pulsar_haptics (0.0.3)
  • flutter build ios --debug --no-codesign --simulator — builds

With SPM enabled, flutter build ios --debug --no-codesign --simulator still builds, so the CI path in _build-ios-flutter.yml is unaffected. node scripts/sync-sdk-versions.mjs runs clean and leaves the tree unchanged.

Not included

The CI guard suggested in the issue. The Flutter iOS job in test-build-apps.yml is workflow_dispatch-only and goes through SPM, so adding a CocoaPods cell (SPM off, pub get + pod install) is a dispatcher-shape decision I'd rather leave to you — say the word and I'll add it here.

Unrelated drift I noticed while in here: the Flutter plugin pins Pulsar-haptics at 1.1.2 while sdk-versions.json lists iOS 1.2.0. Left untouched.

Flutter derives the expected podspec path from the pub package name, so it looked for `ios/pulsar_haptics.podspec`, did not find it, and — because `ios/pulsar_haptics/Package.swift` is present — concluded the plugin is Swift Package Manager only. In an app that uses CocoaPods, `flutter pub get` then failed with "Plugin pulsar_haptics is only compatible with Swift Package Manager" and the plugin could not be adopted at all. The same name drives the module `GeneratedPluginRegistrant` imports (`@import pulsar_haptics;`), so even with SPM disabled by hand the pod built under the wrong module name.

Rename `ios/pulsar.podspec` to `ios/pulsar_haptics.podspec`, set `s.name` to match, and tag `s.version` with a `pulsar-sync:flutter-version` marker so `scripts/sync-sdk-versions.mjs` keeps it in step with the pub version instead of leaving it stuck at 0.0.1.

CocoaPods compares product module names case-insensitively, so the plugin pod `pulsar_haptics` now collides with the native pod's derived module `Pulsar_haptics` (from `Pulsar-haptics`) whenever the app opts into frameworks. The example app's Podfile drops `use_frameworks!` for that reason; declaring `s.module_name = 'Pulsar'` on the native podspec — matching the module name its Swift Package already exposes — would lift the restriction for apps that need frameworks, but that needs a native release and is left out here.

Verified on the example app with Flutter 3.44.0: with SPM disabled, `flutter pub get` and `pod install` succeed and `flutter build ios --debug --simulator` builds; with SPM enabled, the build still succeeds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ilya-clicapin
ilya-clicapin force-pushed the fix/flutter-cocoapods-podspec-name branch from 9d2b015 to a488f54 Compare July 29, 2026 15:45
@ilya-clicapin
ilya-clicapin marked this pull request as ready for review August 7, 2026 15:33
@piaskowyk

piaskowyk commented Aug 10, 2026

Copy link
Copy Markdown
Member

Thank you for that fix!! I will try to release it soon 🫡

@piaskowyk
piaskowyk merged commit 8d2a699 into software-mansion:main Aug 10, 2026
piaskowyk added a commit that referenced this pull request Aug 10, 2026
* fix(ios): expose native pod as module `Pulsar` (module_name)

The published `Pulsar-haptics` pod had no `s.module_name`, so CocoaPods
derived the module `Pulsar_haptics` from the pod name. That is inconsistent
with the Swift Package (which already exposes `Pulsar`) and with the docs,
which tell every consumer to `import Pulsar` — a CocoaPods-only user following
the README would hit `no such module 'Pulsar'`.

It also collides, case-insensitively, with the Flutter plugin pod
`pulsar_haptics`: `pod install` fails with "frameworks with conflicting names:
pulsar_haptics" whenever a Flutter app opts into `use_frameworks!` (common with
Firebase and other Swift pods). This was the remaining caveat from #141.

Set `s.module_name = 'Pulsar'` so CocoaPods and SPM agree, and bump the iOS
version to 1.3.0 (via sdk-versions.json + sync) so the change ships in a
release. No source changes: this only renames the imported module.

Note: renames the CocoaPods module for existing consumers who imported the
derived `Pulsar_haptics` — they switch to `import Pulsar` (compile-time, one
line). Migration note to follow in the changelog.

* Update Pulsar-haptics.podspec
piaskowyk added a commit that referenced this pull request Aug 10, 2026
* fix(flutter): pin native pod to 1.3.0 and re-enable use_frameworks!

Faza 2+3 follow-up to #171 (native `s.module_name = 'Pulsar'`, shipped in
Pulsar-haptics 1.3.0). Now that the native pod exposes the `Pulsar` module,
the case-insensitive CocoaPods collision between the plugin pod `pulsar_haptics`
and `Pulsar-haptics` is gone, so a Flutter app can opt into `use_frameworks!`
(dynamic frameworks — needed by Firebase and other Swift pods) again.

- Bump the plugin's native iOS pin 1.1.2 -> 1.3.0 via sdk-versions.json + sync
  (the `pulsar-sync:flutter-pulsar-ios` marker in pulsar_haptics.podspec), and
  the SwiftPM dependency in Package.swift `from: "1.1.4"` -> `"1.3.0"`. This also
  clears the pre-existing pod/SPM pin drift.
- Re-enable `use_frameworks!` in the example app Podfile (removed as a workaround
  in #141).

Verified: with `use_frameworks!` on and the 1.3.0 native pod (module `Pulsar`),
`pod install` on flutter/PulsarApp resolves Flutter + Pulsar-haptics (1.3.0) +
pulsar_haptics (0.0.3) with no "conflicting names" error.

Note: the example app's ios/Podfile.lock is intentionally not regenerated here —
the published Pulsar-haptics 1.3.0 podspec is on the CDN and correct
(platforms: ios 13.0, module_name: Pulsar), but the CDN's aggregated version
index has not yet listed 1.3.0, so `pod install` against the published pod is
briefly unresolvable. Regenerate the lock once the index propagates.

* Rescope to Faza 3 only: drop version/pin bumps

Those live in the separate Flutter 0.1.0 release change; keeping them here only
duplicated it. This PR now touches just the example Podfile (re-enable
use_frameworks!). Merge after the native iOS pin reaches 1.3.0.
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.

Flutter plugin unusable with CocoaPods: iOS podspec is named pulsar.podspec but the pub package is pulsar_haptics

2 participants