- iOS-specific functions MUST have
IOSsuffix - Android-specific functions MUST have
Androidsuffix - Cross-platform functions have NO suffix
// iOS-specific functions
func presentCodeRedemptionSheetIOS()
func showManageSubscriptionsIOS()
func deepLinkToSubscriptionsIOS()
func getPromotedProductIOS()
func requestPurchaseOnPromotedProductIOS()
func syncIOS()
func getReceiptDataIOS()
// Cross-platform functions
func initConnection()
func fetchProducts()
func requestPurchase()
func finishTransaction()// Missing IOS suffix for iOS-specific
func presentCodeRedemptionSheet() // Should be presentCodeRedemptionSheetIOS()
func showManageSubscriptions() // Should be showManageSubscriptionsIOS()
// Unnecessary suffix for cross-platform
func requestPurchaseIOS() // Should be requestPurchase() if cross-platform- MUST match openiap.dev API naming
- Use exact same function names as React Native OpenIAP
initConnection()- Initialize IAP connectionendConnection()- End IAP connectionfetchProducts()- Fetch products from storegetAvailablePurchases()- Get available/restored purchasesrequestPurchase()- Request a purchasefinishTransaction()- Finish a transaction
- Acronyms should be ALL CAPS only when they appear as a suffix
- When acronyms appear at the beginning or middle, use Pascal case (first letter caps, rest lowercase)
- Package/Module names follow the same rule:
OpenIAP(Open at beginning =Open, IAP as suffix =IAP)
OpenIAP(Package name: Open at beginning, IAP as suffix)IapManager(IAP at beginning)IapPurchase(IAP at beginning)IapError(IAP at beginning)OpenIapTests(both Open and IAP at beginning/middle)ProductIAP(IAP as suffix)ManagerIAP(IAP as suffix)
OpenIap(should beOpenIAP- IAP is suffix)IAPManager(should beIapManager)IAPPurchase(should beIapPurchase)IAPError(should beIapError)OpenIAPTests(should beOpenIapTests- IAP is in middle, not suffix)
- iOS:
Ioswhen at beginning/middle,IOSwhen as suffix - IAP:
Iapwhen at beginning/middle,IAPwhen as suffix - API:
Apiwhen at beginning/middle,APIwhen as suffix - URL:
Urlwhen at beginning/middle,URLwhen as suffix
OpenIapErrorstatic code constants use PascalCase names (e.g.UserCancelled,SkuNotFound) while the raw string value stays as theE_code for parity with other platforms.- Always reference the PascalCase constants in Swift and avoid introducing new
E_-prefixed identifiers.
The Types.swift file in Sources/Models/ is auto-generated from the OpenIAP GraphQL schema. DO NOT edit this file directly as changes will be overwritten.
To update types to match the latest OpenIAP GraphQL schema:
# Generate types using version from openiap-versions.json
./scripts/generate-types.sh
# Or override with environment variable
OPENIAP_GQL_VERSION=1.0.9 ./scripts/generate-types.sh
# Or specify version as argument
./scripts/generate-types.sh 1.0.9The script will:
- Read the version from
openiap-versions.json(if available) - Download the Swift types from the openiap-gql GitHub releases
- Extract and place them in
Sources/Models/Types.swift
Version is managed in openiap-versions.json:
{
"apple": "1.2.5",
"gql": "1.0.10"
}Fields:
apple: OpenIAP Apple package version (auto-updated bybump-version.sh)gql: openiap-gql version for type generation
To update GQL types:
- Edit
openiap-versions.json- change"gql"version - Run
./scripts/generate-types.sh - Run
swift testto verify compatibility
To bump Apple package version:
./scripts/bump-version.sh [major|minor|patch|x.x.x]This automatically updates:
"apple"field inopeniap-versions.json- All version references in README
- Creates git commit and tag
Note: The VERSION file has been removed. All version management is now in openiap-versions.json.
openiap.podspec automatically reads the version from openiap-versions.json using Ruby's JSON parser.
Fallback behavior:
- If
openiap-versions.jsonis not found: uses1.0.10 - Requires
jqorpython3to parse JSON
Available versions: https://github.com/hyodotdev/openiap-gql/releases
Note: Not all releases have Swift assets; use versions with openiap-swift.zip
- Always regenerate types after updating to a new openiap-gql version
- Run tests after regenerating to ensure compatibility:
swift test - Commit
openiap-versions.jsonchanges to track version history
- Run tests with:
swift test - Build with:
swift build - Use real product IDs:
dev.hyo.martie.10bulbs,dev.hyo.martie.30bulbs
-
Sources/Models/: OpenIAP official types that match openiap.dev/docs/types
Product.swift- ProductIOS and related typesPurchase.swift- PurchaseIOS and related typesActiveSubscription.swift- ActiveSubscription typePurchaseError.swift- PurchaseError typeReceipt.swift- Receipt validation types- etc.
-
Sources/Helpers/: Internal helper classes (NOT in OpenIAP official types)
ProductManager.swift- Thread-safe product cachingIapStatus.swift- UI status management for SwiftUI
-
Sources/: Main module files
OpenIapModule.swift- Core implementationOpenIapStore.swift- SwiftUI-friendly storeOpenIapProtocol.swift- API interface definitions
- Models: Must match OpenIAP specification exactly
- Helpers: Use descriptive names ending with purpose (Manager, Cache, Status, etc.)
- Avoid confusing names: Don't use "Store" for caching classes (use Cache, Manager instead)
- Follow Conventional Commits format:
<type>: <description> - Type MUST be lowercase (e.g.,
feat:,fix:,docs:,refactor:) - Description starts with lowercase after the colon and space
feat:- New featurefix:- Bug fixdocs:- Documentation changesrefactor:- Code refactoringtest:- Test additions or changeschore:- Maintenance tasks
feat: add Objective-C bridge for Kotlin Multiplatform
fix: use DiscountOfferInputIOS for subscription offers
docs: update API documentation
refactor: simplify purchase flow logic
Feat: add new feature // Type should be lowercase
fix: Add new feature // Description should start with lowercase
FIX: something // Type should be lowercase
- Purchase Flow should display real-time purchase events
- Transaction observer handles purchase completion
- Mock data available for testing when real products not configured