Skip to content

Commit 5a0630b

Browse files
Kobikg78claude
andcommitted
Fix SPM version-pin asymmetry with CocoaPods
Package.swift pinned AppsFlyerFramework with `from: "6.18.0"` (a semver range, ..<7.0.0), while the podspec pins CocoaPods to exactly 6.18.0. CI's own iOS E2E run exposed the drift: it resolved and ran against 6.18.1 via SPM. Switch to `.exact("6.18.0")` so both distribution paths pin identically, and correct the docs/plan that described the old pin as correct. Also retracts a stale claim in plans/01-ios-spm-core-support.md that `.iOS("12.0")` is invalid SwiftPM syntax — verified valid via `swift package describe`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 3b6a4b9 commit 5a0630b

4 files changed

Lines changed: 12 additions & 10 deletions

File tree

docs/features/F-060-swift-package-manager-support.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Shared source tree (used by both paths, single copy — no duplication):
3939
4040
SPM path (resolved by `flutter build`/`swift build` at build configuration time):
4141
ios/appsflyer_sdk/Package.swift
42-
→ target "appsflyer_sdk" depends on product "AppsFlyerLib" from AppsFlyerFramework, pinned from: "6.18.0"
42+
→ target "appsflyer_sdk" depends on product "AppsFlyerLib" from AppsFlyerFramework, pinned exactly to 6.18.0
4343
→ compiles the shared Sources/ tree above as a ClangTarget, iOS 12.0 minimum
4444
→ does NOT reference ios/PurchaseConnector/ at all — no PurchaseConnector target/product exists in this manifest
4545
@@ -54,7 +54,7 @@ CocoaPods path (resolved by `pod install` at install time, unchanged behavior):
5454
## Files
5555
| File | Role |
5656
|------|------|
57-
| `ios/appsflyer_sdk/Package.swift` | New SPM manifest. `swift-tools-version:5.9` (Xcode 15.0+), `platforms: [.iOS("12.0")]` (matches the podspec's existing deployment target). Declares one product/target depending on `AppsFlyerFramework`'s `AppsFlyerLib` product, `from: "6.18.0"`. |
57+
| `ios/appsflyer_sdk/Package.swift` | New SPM manifest. `swift-tools-version:5.9` (Xcode 15.0+), `platforms: [.iOS("12.0")]` (matches the podspec's existing deployment target). Declares one product/target depending on `AppsFlyerFramework`'s `AppsFlyerLib` product, pinned `.exact("6.18.0")`, matching the podspec's exact CocoaPods pin. |
5858
| `ios/appsflyer_sdk/Sources/appsflyer_sdk/*.m` | Core implementation files, moved verbatim from `ios/Classes/` via `git mv` (confirmed zero content diff) — now the single shared source tree for both CocoaPods and SPM. |
5959
| `ios/appsflyer_sdk/Sources/appsflyer_sdk/include/appsflyer_sdk/*.h` | Public headers, moved verbatim from `ios/Classes/``AppsflyerSdkPlugin.h` is where `pluginClass: AppsflyerSdkPlugin` (declared in `pubspec.yaml`, unchanged) resolves from in both integration paths. |
6060
| `ios/appsflyer_sdk.podspec` | `Core` subspec's `source_files`/`public_header_files` repointed to the new shared path; `PurchaseConnector` subspec is untouched. No marker added to declare SPM availability — Flutter's tooling detects it purely by the presence of `Package.swift` at the conventional path. |

docs/tech-designs/spm-support.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ let package = Package(
5353
.library(name: "appsflyer-sdk", targets: ["appsflyer_sdk"])
5454
],
5555
dependencies: [
56-
.package(url: "https://github.com/AppsFlyerSDK/AppsFlyerFramework.git", from: "6.18.0")
56+
.package(url: "https://github.com/AppsFlyerSDK/AppsFlyerFramework.git", .exact("6.18.0"))
5757
],
5858
targets: [
5959
.target(
@@ -69,7 +69,9 @@ let package = Package(
6969
)
7070
```
7171

72-
**Correction to draft PR #454**: its PR description names the dependency product `AppsFlyerLib-Static`. I fetched `AppsFlyerFramework`'s actual `Package.swift` at tag `6.18.0` directly via GitHub API — the declared product name is `AppsFlyerLib`, not `AppsFlyerLib-Static` (that string only appears in the *binary artifact's zip filename*, not the SPM product). Using the wrong product name would fail dependency resolution outright. Pin `from: "6.18.0"` to match the podspec's existing `ss.ios.dependency 'AppsFlyerFramework','6.18.0'` — no native SDK version bump required (R-001 confirmed the 6.18.0 tag's own Package.swift resolves and is valid).
72+
**Correction to draft PR #454**: its PR description names the dependency product `AppsFlyerLib-Static`. I fetched `AppsFlyerFramework`'s actual `Package.swift` at tag `6.18.0` directly via GitHub API — the declared product name is `AppsFlyerLib`, not `AppsFlyerLib-Static` (that string only appears in the *binary artifact's zip filename*, not the SPM product). Using the wrong product name would fail dependency resolution outright. Pin `.exact("6.18.0")` to match the podspec's existing `ss.ios.dependency 'AppsFlyerFramework','6.18.0'` exactly — no native SDK version bump required (R-001 confirmed the 6.18.0 tag's own Package.swift resolves and is valid).
73+
74+
**Correction (post-review)**: the original design used `from: "6.18.0"`, a semver-range requirement (`6.18.0..<7.0.0`) rather than an exact pin. This was caught during PR review — the CI E2E run cited in the PR's test plan actually resolved and ran against `AppsFlyerFramework` **6.18.1**, not 6.18.0, exposing a real asymmetry: CocoaPods consumers get exactly 6.18.0, SPM consumers could silently float onto any untested patch/minor release below 7.0.0. Changed to `.exact("6.18.0")` so both distribution paths pin identically. Re-verified via `swift package describe`: `Requirement: Exact: 6.18.0`.
7375

7476
### `ios/appsflyer_sdk.podspec` — path updates only, no marker needed
7577

ios/appsflyer_sdk/Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ let package = Package(
88
.library(name: "appsflyer-sdk", targets: ["appsflyer_sdk"])
99
],
1010
dependencies: [
11-
.package(url: "https://github.com/AppsFlyerSDK/AppsFlyerFramework.git", from: "6.18.0")
11+
.package(url: "https://github.com/AppsFlyerSDK/AppsFlyerFramework.git", .exact("6.18.0"))
1212
],
1313
targets: [
1414
.target(

plans/01-ios-spm-core-support.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ Add a `Package.swift` for the plugin's **Core** module so SPM-enabled Flutter ap
1616

1717
| PR | Approach | Verdict |
1818
|---|---|---|
19-
| [#454](https://github.com/AppsFlyerSDK/appsflyer-flutter-plugin/pull/454) (`nurlangarash`) | True `git mv` of `Classes/*``ios/appsflyer_sdk/Sources/appsflyer_sdk/` (+headers → `.../include/appsflyer_sdk/`), podspec updated to match, single source of truth. Depends on `AppsFlyerFramework-Static` / product `AppsFlyerLib-Static` (matches `static_framework = true`). Copilot flagged `.iOS("12.0")` (invalid) and product/target name mismatch — **both already fixed** in follow-up commit `98d9938dd2`. PurchaseConnector explicitly untouched. | **Use this as the base.** |
20-
| [#455](https://github.com/AppsFlyerSDK/appsflyer-flutter-plugin/pull/455) (`TeddyYeung`) | Duplicates Core sources into a second tree, leaves podspec pointing at old `Classes/` — two copies to maintain forever. Same `.iOS("12.0")` bug, **never fixed**. Adds `.gitignore` entries (`.build/`, `.swiftpm/`) — worth cherry-picking. | Reject the architecture; take only the `.gitignore` hunk. |
19+
| [#454](https://github.com/AppsFlyerSDK/appsflyer-flutter-plugin/pull/454) (`nurlangarash`) | True `git mv` of `Classes/*``ios/appsflyer_sdk/Sources/appsflyer_sdk/` (+headers → `.../include/appsflyer_sdk/`), podspec updated to match, single source of truth. Depends on `AppsFlyerFramework-Static` / product `AppsFlyerLib-Static` (matches `static_framework = true`) — this product name is wrong, corrected to `AppsFlyerLib` during implementation. Copilot flagged `.iOS("12.0")` as invalid and a product/target name mismatch — the name mismatch was real, but the `.iOS("12.0")` flag was itself wrong (verified valid via `swift package describe`; not something that needed fixing). PurchaseConnector explicitly untouched. | **Use this as the base.** |
20+
| [#455](https://github.com/AppsFlyerSDK/appsflyer-flutter-plugin/pull/455) (`TeddyYeung`) | Duplicates Core sources into a second tree, leaves podspec pointing at old `Classes/` — two copies to maintain forever. Uses the same `.iOS("12.0")` syntax, which is valid (see #454's corrected note) and was never actually a bug. Adds `.gitignore` entries (`.build/`, `.swiftpm/`) — worth cherry-picking. | Reject the architecture; take only the `.gitignore` hunk. |
2121
| [#370](https://github.com/AppsFlyerSDK/appsflyer-flutter-plugin/pull/370) (`alejandro-all-win-software`, oldest) | Tried to fold PurchaseConnector itself into SPM via an env-var-gated target (`ENABLE_PURCHASE_CONNECTOR=1`) + dependency on `appsflyer-apple-purchase-connector`. Author's own comment: *"blocked by flutter/flutter#161182... if you find another way to opt in to Purchase Connector, I'd be happy to close this PR in favor of that approach."* | **Do not repeat this.** This is exactly the dead end DELIVERY-125462 tells us to route around by staying CocoaPods-only for PurchaseConnector. |
2222

2323
None of the three have maintainer review; all are `REVIEW_REQUIRED`/`BLOCKED` on branch protection only (CI/security scans pass on all three).
@@ -66,7 +66,7 @@ let package = Package(
6666
]
6767
)
6868
```
69-
Anti-pattern guard (from Copilot's actual review on #454): `.iOS("12.0")` is **not** valid SwiftPM API — must be `.iOS(.v12)`. Library name uses hyphens (`appsflyer-sdk`), target/package name keeps underscores (`appsflyer_sdk`) — this is Flutter's documented convention, not a typo.
69+
~~Anti-pattern guard (from Copilot's actual review on #454): `.iOS("12.0")` is **not** valid SwiftPM API — must be `.iOS(.v12)`.~~ **Corrected during implementation review**: this claim is wrong. `SupportedPlatform.IOSVersion` conforms to `ExpressibleByStringLiteral`, so `.iOS("12.0")` is valid and compiles. Verified directly: the shipped `Package.swift` uses `.iOS("12.0")` and `swift package describe` resolves `Platforms: Name: ios, Version: 12.0` with no error. Both `.iOS("12.0")` and `.iOS(.v12)` work; this repo uses the former. Library name uses hyphens (`appsflyer-sdk`), target/package name keeps underscores (`appsflyer_sdk`) — this is Flutter's documented convention, not a typo.
7070

7171
Podspec `Core` subspec path update (mirrors #454 exactly):
7272
```ruby
@@ -121,7 +121,7 @@ SwiftPM added **Package Traits** in Swift 6.1 ([docs.swift.org/swiftpm/.../packa
121121

122122
**What to do:**
123123
1. Cherry-pick #455's `.gitignore` addition: `.build/`, `.swiftpm/`.
124-
2. Confirm `Package.swift` matches the corrected form in Phase 0.B exactly (`.iOS(.v12)`, not `.iOS("12.0")`; product `AppsFlyerLib-Static` from `AppsFlyerFramework-Static`, pinned `exact: "6.18.0"` to match the podspec's `AppsFlyerFramework` pin).
124+
2. Confirm `Package.swift` matches the shipped, verified form: `.iOS("12.0")` (confirmed valid — see Phase 0.B correction); product `AppsFlyerLib` from `AppsFlyerFramework` (not `AppsFlyerLib-Static`/`AppsFlyerFramework-Static` — that naming was wrong, see #454 correction above), pinned `.exact("6.18.0")` to match the podspec's `AppsFlyerFramework` pin exactly.
125125
3. Confirm `cSettings: [.headerSearchPath("include/appsflyer_sdk")]` is present (required for the `.m` files' `#import` statements to resolve).
126126
4. Confirm all 4 public headers live under `Sources/appsflyer_sdk/include/appsflyer_sdk/` and the 3 `.m` files live directly under `Sources/appsflyer_sdk/` (not under `include/`).
127127

@@ -197,6 +197,6 @@ This is a **plugin-only** change (adds SPM plumbing, does not touch native SDK v
197197
2. All four build-matrix rows in Phase 5 verified with evidence (CI logs or local build output).
198198
3. `CHANGELOG.md` and `pubspec.yaml` version bumped per Phase 3.
199199
4. `doc/Installation.md` and `doc/PurchaseConnector.md` updated per Phase 4, explicitly stating the PurchaseConnector/SPM limitation.
200-
5. No `.iOS("12.0")`-style invalid SwiftPM API left in `Package.swift` (`grep -n '\.iOS(\"' ios/appsflyer_sdk/Package.swift` should return nothing).
200+
5. ~~No `.iOS("12.0")`-style invalid SwiftPM API left in `Package.swift`~~ — retracted: `.iOS("12.0")` is valid (verified via `swift package describe`); the shipped `Package.swift` intentionally uses this form.
201201
6. No duplicate source files between `ios/Classes/` (should no longer exist) and `ios/appsflyer_sdk/Sources/`.
202202
7. Ready to open a PR against DELIVERY-125462, referencing and closing out #454/#455/#370 in the description (crediting their work, explaining why #454 was chosen as base).

0 commit comments

Comments
 (0)