Skip to content

fix(ios): unwrap paymentId before calling LinkrunnerKit capturePayment [4.1.1] - #40

Merged
Shofiya2003 merged 1 commit into
mainfrom
fix/ios-capture-payment-optional-paymentid
Jul 31, 2026
Merged

fix(ios): unwrap paymentId before calling LinkrunnerKit capturePayment [4.1.1]#40
Shofiya2003 merged 1 commit into
mainfrom
fix/ios-capture-payment-optional-paymentid

Conversation

@Shofiya2003

@Shofiya2003 Shofiya2003 commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Every published 4.x release of this package fails to compile on iOS. capturePayment in the Swift bridge passes an optional String? into LinkrunnerKit's capturePayment, which has taken a non-optional String since LinkrunnerKit 4.0.0.

Swift Compiler Error (Xcode): Value of optional type 'String?' must be unwrapped to a value of type 'String'
ios/Classes/SwiftLinkrunnerPlugin.swift:322:31

This is unconditional — it fails for every consumer regardless of their Dart code, because it is our own source that does not type-check.

Root cause

Making paymentId mandatory (LIN-1649) needed three changes in this package. Only two were made:

Layer Status
Dart model — lib/models/lr_capture_payment.dart (final String paymentId, required, non-empty validated) done
Pod pin — ios/linkrunner.podspec bumped to LinkrunnerKit 4.x done
Swift bridge — ios/Classes/SwiftLinkrunnerPlugin.swift missed

ee83237 (the 4.0.0 bump) touched CHANGELOG.md, android/build.gradle, ios/linkrunner.podspec, lib/linkrunner.dart and pubspec.yaml — the bridge was not among them. The native SDK did nothing wrong; 4.0.0 was an intentional major. rn-linkrunner already handles this correctly at ios/LinkrunnerSDK.swift:134, which is why React Native builds fine on the same LinkrunnerKit 4.1.0.

Affected versions

Pins read from the published pub.dev tarballs, not from git:

linkrunner published LinkrunnerKit pin iOS
3.10.0 2026-06-20 3.11.0 builds
4.0.1 2026-07-09 4.0.1 broken
4.0.2 2026-07-23 4.0.1 broken
4.0.3 2026-07-28 4.0.1 broken
4.1.0 2026-07-29 4.1.0 broken

3.10.0 is the last iOS-clean release. Android is unaffected — only the Swift bridge has the mismatch. 4.0.0 was never published to pub.dev, so no consumer can be on it.

Why it was not caught

Three layers could have caught this; none of them compile Swift against the pinned pod:

  1. flutter pub publish validates and archives — it never invokes Xcode or swiftc. flutter analyze is Dart-only.
  2. The local playground's Podfile.lock was pinned to LinkrunnerKit 3.7.0 (last pod install: 2025-12-17), where an optional paymentId is legal. Local iOS builds kept compiling the new bridge against the old API.
  3. There is no CI that builds iOS.

The fix

Unwrap at the method-channel boundary and make the private helper take a non-optional String, matching the rn-linkrunner pattern. Dart already guarantees paymentId is present and non-empty, so this is a no-op for correct callers; malformed channel payloads now get an INVALID_ARGUMENT FlutterError instead of failing to compile.

Verification

Reproduced and fixed against the real playground (flutter-linkrunner-sandbox, path: ../linkrunner) with a freshly resolved Podfile.lock on LinkrunnerKit 4.1.0.

Before — reproduces the reported error at the exact reported line:

Failed to build iOS app
Swift Compiler Error (Xcode): Value of optional type 'String?' must be unwrapped to a value of type 'String'
ios/Classes/SwiftLinkrunnerPlugin.swift:322:31

After — same playground, same pod, unchanged Podfile.lock:

Building com.example.linkrunnerFlutterPlayground for device (ios-release)...
Running Xcode build...
Xcode build done.                                           25.9s
✓ Built build/ios/iphoneos/Runner.app (16.8MB)

flutter analyze reports 0 errors (the 15 remaining info lints are pre-existing constant_identifier_names warnings in lib/models/lr_consent.dart, unchanged from 4.1.0).

Release

Bumps to 4.1.1 across the three places the version lives — pubspec.yaml, ios/linkrunner.podspec (s.version; the LinkrunnerKit dependency stays pinned at 4.1.0) and LinkRunner.packageVersion in lib/linkrunner.dart — plus a CHANGELOG.md entry. This needs to reach pub.dev promptly: until it does, there is no clean customer-side workaround for iOS on 4.x, and every Flutter customer advised to upgrade to 4.1.0 is blocked.

Follow-ups (not in this PR)

  • Add a CI job that runs flutter build ios --no-codesign against the playground. A stale Podfile.lock hid this for four releases; nothing else in the pipeline type-checks the bridge.
  • Audit the Capacitor bridge for the same optional-vs-required drift. rn-linkrunner is already correct.
  • LinkrunnerKit 4.0.0 is tagged but absent from CocoaPods trunk (trunk goes 3.11.0 -> 4.0.1 -> 4.1.0). Harmless today since no published Flutter release pins it, but worth reconciling.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed iOS build failures affecting versions 4.0.1–4.1.0.
    • Improved payment capture validation by rejecting missing or empty payment IDs with a clear error.
    • Preserved existing Dart API and Android behavior.
  • Release

    • Updated the SDK version to 4.1.1.

The Swift bridge passed an optional String? into LinkrunnerKit's
capturePayment, which has taken a non-optional String since
LinkrunnerKit 4.0.0. Xcode rejected it outright:

  Value of optional type 'String?' must be unwrapped to a value of
  type 'String' — SwiftLinkrunnerPlugin.swift:322:31

This broke every iOS build on 4.0.1, 4.0.2, 4.0.3 and 4.1.0
regardless of the consumer's Dart code, since it is our own source
that fails to type-check. Android was never affected — only the
Swift bridge has the mismatch.

Making paymentId mandatory (LIN-1649) updated the Dart model and the
pod pin but not the bridge; ee83237 touched five files and none of
them was SwiftLinkrunnerPlugin.swift. Unwrap at the method-channel
boundary instead, matching rn-linkrunner's ios/LinkrunnerSDK.swift.
LRCapturePayment.paymentId is already required and non-empty
validated in Dart, so correct callers see no behaviour change;
malformed channel payloads now get an INVALID_ARGUMENT FlutterError.

Verified against the playground with a freshly resolved Podfile.lock
on LinkrunnerKit 4.1.0: the error reproduces at the exact reported
line before this change, and `flutter build ios --no-codesign`
succeeds after it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 14e5be2c-7865-456c-ae85-1da93135c472

📥 Commits

Reviewing files that changed from the base of the PR and between 993ba23 and 3bebe4c.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • ios/Classes/SwiftLinkrunnerPlugin.swift
  • ios/linkrunner.podspec
  • lib/linkrunner.dart
  • pubspec.yaml

📝 Walkthrough

Walkthrough

The iOS plugin now requires a non-empty paymentId before native payment capture. Package, podspec, Dart version, and changelog entries now report release 4.1.1.

Changes

iOS payment capture release

Layer / File(s) Summary
Require payment ID for iOS capture
ios/Classes/SwiftLinkrunnerPlugin.swift
The method-channel boundary rejects missing or empty payment IDs and passes a non-optional String to native capture.
Publish version 4.1.1
pubspec.yaml, ios/linkrunner.podspec, lib/linkrunner.dart, CHANGELOG.md
Package metadata, LinkRunner.packageVersion, the podspec, and release notes now identify version 4.1.1.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • RathodDarshil/linkrunner issue 40 — Addresses the same iOS capturePayment paymentId optionality mismatch.

Possibly related PRs

Suggested reviewers: chetanbhosale

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the iOS fix and identifies the 4.1.1 release.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ios-capture-payment-optional-paymentid

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Shofiya2003
Shofiya2003 merged commit eabc5c2 into main Jul 31, 2026
1 check passed
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.

1 participant