Skip to content
This repository was archived by the owner on Oct 16, 2025. It is now read-only.

fix: fixed isEligibleForIntroOfferIOS()#23

Merged
hyochan merged 1 commit intohyodotdev:mainfrom
nahlebn1k:main
Oct 13, 2025
Merged

fix: fixed isEligibleForIntroOfferIOS()#23
hyochan merged 1 commit intohyodotdev:mainfrom
nahlebn1k:main

Conversation

@nahlebn1k
Copy link
Contributor

@nahlebn1k nahlebn1k commented Oct 13, 2025

Hi, I discovered that isEligibleForIntroOfferIOS() is not working as expected. After digging into it, I found that this feature relies on Transaction.currentEntitlements, which only returns subscriptions with a state of subscribed or inGracePeriod. As a result, the outcome doesn’t accurately represent the actual introductory offer eligibility.

This fix changes the implementation to rely on Product.SubscriptionInfo.isEligibleForIntroOffer(for: groupID) https://developer.apple.com/documentation/storekit/product/subscriptioninfo/iseligibleforintrooffer(for:)

Summary by CodeRabbit

  • Bug Fixes
    • Corrected detection of introductory offer eligibility on iOS, reducing cases where eligible users were incorrectly marked ineligible and ensuring intro pricing appears consistently when applicable.
  • Performance
    • Streamlined the eligibility check for subscriptions, providing a faster and more reliable purchase flow with fewer delays before showing available offers.
  • Refactor
    • Simplified internal logic for determining eligibility, reducing complexity without altering public interfaces or visible app behavior beyond improved consistency.

@coderabbitai
Copy link

coderabbitai bot commented Oct 13, 2025

Walkthrough

The isEligibleForIntroOfferIOS method in Sources/OpenIapModule.swift was refactored to use StoreKit’s SubscriptionInfo.isEligibleForIntroOffer(for:) in a single async call, removing the prior loop over current entitlements and manual verification. No public API signatures were changed.

Changes

Cohort / File(s) Summary
Intro offer eligibility refactor
Sources/OpenIapModule.swift
Replaced manual entitlement iteration and verification with a direct await call to StoreKit.Product.SubscriptionInfo.isEligibleForIntroOffer(for:), simplifying control flow and removing early-return logic.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor App
  participant OpenIapModule
  participant StoreKit as StoreKit.SubscriptionInfo

  App->>OpenIapModule: isEligibleForIntroOfferIOS(productId)
  Note over OpenIapModule: Previous flow removed:<br/>- Iterate entitlements<br/>- Verify each transaction<br/>- Early return if match
  OpenIapModule->>StoreKit: isEligibleForIntroOffer(for: product)
  StoreKit-->>OpenIapModule: Bool eligibility
  OpenIapModule-->>App: Return eligibility
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

🛠 bugfix

Suggested reviewers

  • hyochan

Poem

A hop and a skip through StoreKit’s door,
One tidy call—no looping lore.
I twitch my nose, refactor done,
Async whispers: “Eligibility won?”
Carrot-shaped futures, clean and bright,
Bunny approves—ship it tonight! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly references the primary change, namely fixing the isEligibleForIntroOfferIOS() function, and is concise and specific enough for a reader to understand the main intent of the PR. Although it repeats “fix,” it still accurately summarizes the key update without extraneous details.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4824756 and 2462e56.

📒 Files selected for processing (1)
  • Sources/OpenIapModule.swift (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
Sources/**/*.swift

📄 CodeRabbit inference engine (CLAUDE.md)

Sources/**/*.swift: iOS-specific functions MUST have IOS suffix
Android-specific functions MUST have Android suffix
Cross-platform functions must have NO platform suffix
Acronyms in Swift should be ALL CAPS only when used as a suffix; otherwise use Pascal case (first letter caps, rest lowercase)
Specific casing: iOS -> Ios in beginning/middle, IOS as suffix
Specific casing: IAP -> Iap in beginning/middle, IAP as suffix
Specific casing: API -> Api in beginning/middle, API as suffix
Specific casing: URL -> Url in beginning/middle, URL as suffix
OpenIapError static code constants use PascalCase names; raw string values remain E_ codes; avoid introducing new E_-prefixed identifiers in Swift

Files:

  • Sources/OpenIapModule.swift
Sources/{OpenIapProtocol.swift,OpenIapModule.swift}

📄 CodeRabbit inference engine (CLAUDE.md)

Sources/{OpenIapProtocol.swift,OpenIapModule.swift}: Public API names MUST match openiap.dev and React Native OpenIAP (Apple module)
Use standard Apple module API names exactly: initConnection(), endConnection(), fetchProducts(), getAvailablePurchases(), requestPurchase(), finishTransaction()

Files:

  • Sources/OpenIapModule.swift
🧠 Learnings (1)
📚 Learning: 2025-10-09T19:13:15.972Z
Learnt from: CR
PR: hyodotdev/openiap-apple#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-09T19:13:15.972Z
Learning: Applies to Sources/{OpenIapProtocol.swift,OpenIapModule.swift} : Use standard Apple module API names exactly: initConnection(), endConnection(), fetchProducts(), getAvailablePurchases(), requestPurchase(), finishTransaction()

Applied to files:

  • Sources/OpenIapModule.swift
🧬 Code graph analysis (1)
Sources/OpenIapModule.swift (2)
Sources/OpenIapStore.swift (1)
  • isEligibleForIntroOfferIOS (318-320)
Sources/OpenIapModule+ObjC.swift (1)
  • isEligibleForIntroOfferIOSWithGroupID (415-424)
🔇 Additional comments (2)
Sources/OpenIapModule.swift (2)

608-610: LGTM! Correct use of Apple's recommended API.

The implementation correctly uses Product.SubscriptionInfo.isEligibleForIntroOffer(for:) which is Apple's recommended method for checking introductory offer eligibility. This fix addresses the limitation of the previous approach that relied on Transaction.currentEntitlements, which only returned subscriptions in specific states.


608-610: Verify if the throws declaration is intentional for API compatibility.

The function signature declares async throws -> Bool, but Apple's isEligibleForIntroOffer(for:) API is async -> Bool (non-throwing). This means the implementation never actually throws an error.

Since the coding guidelines require public API names to match openiap.dev and React Native OpenIAP, please confirm whether the throws declaration is:

  1. Required for API compatibility with the cross-platform interface
  2. Intentionally retained for future-proofing
  3. Should be removed to match the underlying Apple API more precisely

Based on coding guidelines.


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

@nahlebn1k
Copy link
Contributor Author

@hyochan Please check this as soon as possible! 🙏🙏🙏

@hyochan hyochan merged commit 2462e56 into hyodotdev:main Oct 13, 2025
2 checks passed
@hyochan hyochan added the 🛠 bugfix All kinds of bug fixes label Oct 13, 2025
Copy link
Member

@hyochan hyochan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

🛠 bugfix All kinds of bug fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants