Skip to content

Commit 312822c

Browse files
hyochanclaude
andauthored
fix(apple): add watchOS platform compatibility (#81)
## Summary - Use `#if os(iOS) || os(tvOS)` instead of `canImport(UIKit)` for UIWindowScene (not available on watchOS) - Use `#if os(iOS)` for `presentCodeRedemptionSheet` (iOS-only API) - Use `#if os(iOS) || os(tvOS) || os(visionOS)` for `UIApplication.open` (not available on watchOS/macOS) - Add `watchOS 9.0` to `@available` for `getAppTransactionIOS` (AppTransaction requires watchOS 9.0+) - Add `tvOS 16.0` to `@available` annotations for consistency Fixes watchOS build errors that occurred after merging #80. ## Test plan - [x] Validated with `pod lib lint openiap.podspec --allow-warnings` - [ ] CI build passes for all platforms (iOS, macOS, tvOS, watchOS) 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added support for tvOS 16.0 and watchOS 9.0 platforms. * **Improvements** * Enhanced platform detection logic across Apple devices for better compatibility. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 8b25eb9 commit 312822c

File tree

6 files changed

+73
-46
lines changed

6 files changed

+73
-46
lines changed

.github/workflows/release-apple.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ on:
1111
- patch
1212
- minor
1313
- major
14+
- current
1415
default: patch
1516
target_version:
1617
description: 'Manual version override (e.g., 1.3.5). Leave empty to auto-bump.'
@@ -57,6 +58,10 @@ jobs:
5758
fi
5859
NEW_VERSION="$TARGET_VERSION"
5960
echo "Using manual version: $NEW_VERSION"
61+
elif [ "${{ github.event.inputs.version }}" = "current" ]; then
62+
NEW_VERSION="$CURRENT_VERSION"
63+
echo "Using current version (no bump): $NEW_VERSION"
64+
echo "skip_version_commit=true" >> $GITHUB_OUTPUT
6065
else
6166
# Parse version components
6267
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
@@ -101,6 +106,7 @@ jobs:
101106
fi
102107
103108
- name: Update version in openiap-versions.json
109+
if: steps.version.outputs.skip_version_commit != 'true'
104110
working-directory: packages/apple
105111
env:
106112
VERSION: ${{ steps.version.outputs.version }}
@@ -110,9 +116,11 @@ jobs:
110116
mv temp.json ../../openiap-versions.json
111117
112118
- name: Sync version files
119+
if: steps.version.outputs.skip_version_commit != 'true'
113120
run: ./scripts/sync-versions.sh
114121

115122
- name: Commit version update
123+
if: steps.version.outputs.skip_version_commit != 'true'
116124
env:
117125
VERSION: ${{ steps.version.outputs.version }}
118126
run: |

.github/workflows/release-google.yml

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ on:
1111
- patch
1212
- minor
1313
- major
14+
- current
1415
default: patch
1516

1617
env:
@@ -36,51 +37,67 @@ jobs:
3637
CURRENT_VERSION=$(jq -r '.google' openiap-versions.json)
3738
echo "Current version: $CURRENT_VERSION"
3839
39-
# Parse version components
40-
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
41-
42-
# Bump version based on input
43-
case "${{ github.event.inputs.version }}" in
44-
major)
45-
MAJOR=$((MAJOR + 1))
46-
MINOR=0
47-
PATCH=0
48-
;;
49-
minor)
50-
MINOR=$((MINOR + 1))
51-
PATCH=0
52-
;;
53-
patch)
54-
PATCH=$((PATCH + 1))
55-
;;
56-
esac
57-
58-
NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
59-
echo "New version: $NEW_VERSION"
40+
if [ "${{ github.event.inputs.version }}" = "current" ]; then
41+
NEW_VERSION="$CURRENT_VERSION"
42+
echo "Using current version (no bump): $NEW_VERSION"
43+
echo "skip_version_commit=true" >> $GITHUB_OUTPUT
44+
else
45+
# Parse version components
46+
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
47+
48+
# Bump version based on input
49+
case "${{ github.event.inputs.version }}" in
50+
major)
51+
MAJOR=$((MAJOR + 1))
52+
MINOR=0
53+
PATCH=0
54+
;;
55+
minor)
56+
MINOR=$((MINOR + 1))
57+
PATCH=0
58+
;;
59+
patch)
60+
PATCH=$((PATCH + 1))
61+
;;
62+
esac
63+
64+
NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
65+
echo "New version: $NEW_VERSION"
66+
fi
6067
echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV
6168
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
6269
6370
- name: Check if tag already exists
6471
id: check_tag
6572
env:
6673
VERSION: ${{ steps.version.outputs.version }}
74+
SKIP_VERSION_COMMIT: ${{ steps.version.outputs.skip_version_commit }}
6775
run: |
6876
if git rev-parse "google-$VERSION" >/dev/null 2>&1; then
69-
echo "exists=true" >> $GITHUB_OUTPUT
70-
echo "❌ Tag google-$VERSION already exists. Skipping release."
71-
exit 1
72-
fi
73-
74-
if git rev-parse "google-v$VERSION" >/dev/null 2>&1; then
75-
echo "exists=true" >> $GITHUB_OUTPUT
76-
echo "❌ Legacy tag google-v$VERSION already exists. Choose a new version."
77-
exit 1
77+
if [ "$SKIP_VERSION_COMMIT" = "true" ]; then
78+
echo "exists=true" >> $GITHUB_OUTPUT
79+
echo "⚠️ Tag google-$VERSION already exists. Will reuse existing tag (current mode)."
80+
else
81+
echo "exists=true" >> $GITHUB_OUTPUT
82+
echo "❌ Tag google-$VERSION already exists. Use 'current' to retry with existing version."
83+
exit 1
84+
fi
85+
elif git rev-parse "google-v$VERSION" >/dev/null 2>&1; then
86+
if [ "$SKIP_VERSION_COMMIT" = "true" ]; then
87+
echo "exists=true" >> $GITHUB_OUTPUT
88+
echo "⚠️ Legacy tag google-v$VERSION already exists. Will reuse existing tag (current mode)."
89+
else
90+
echo "exists=true" >> $GITHUB_OUTPUT
91+
echo "❌ Legacy tag google-v$VERSION already exists. Use 'current' to retry with existing version."
92+
exit 1
93+
fi
94+
else
95+
echo "exists=false" >> $GITHUB_OUTPUT
96+
echo "✓ Tag google-$VERSION does not exist, proceeding with release"
7897
fi
7998
80-
echo "exists=false" >> $GITHUB_OUTPUT
81-
echo "✓ Tag google-$VERSION does not exist, proceeding with release"
82-
8399
- name: Update version in openiap-versions.json
100+
if: steps.version.outputs.skip_version_commit != 'true'
84101
working-directory: packages/google
85102
env:
86103
VERSION: ${{ steps.version.outputs.version }}
@@ -90,9 +107,11 @@ jobs:
90107
mv temp.json ../../openiap-versions.json
91108
92109
- name: Sync version files
110+
if: steps.version.outputs.skip_version_commit != 'true'
93111
run: ./scripts/sync-versions.sh
94112

95113
- name: Commit version update
114+
if: steps.version.outputs.skip_version_commit != 'true'
96115
env:
97116
VERSION: ${{ steps.version.outputs.version }}
98117
run: |

packages/apple/Sources/OpenIapModule+ObjC.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ import StoreKit
603603
}
604604
}
605605

606-
@available(iOS 16.0, macOS 14.0, *)
606+
@available(iOS 16.0, macOS 14.0, tvOS 16.0, watchOS 9.0, *)
607607
@objc func getAppTransactionIOSWithCompletion(_ completion: @escaping (Any?, Error?) -> Void) {
608608
Task {
609609
do {

packages/apple/Sources/OpenIapModule.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,9 @@ public final class OpenIapModule: NSObject, OpenIapModuleProtocol {
341341
do {
342342
// iOS 17.0+, tvOS 17.0+, macOS 15.2+: Use purchase(confirmIn:options:) for better purchase confirmation UI
343343
// Reference: https://developer.apple.com/documentation/storekit/product/purchase(confirmin:options:)-6dj6y
344-
#if canImport(UIKit)
345-
// iOS/tvOS: Use UIWindowScene
346-
if #available(iOS 17.0, tvOS 17.0, *) {
344+
#if os(iOS) || os(tvOS) || os(visionOS)
345+
// iOS/tvOS/visionOS: Use UIWindowScene (not available on watchOS)
346+
if #available(iOS 17.0, tvOS 17.0, visionOS 1.0, *) {
347347
let scene: UIWindowScene? = await MainActor.run {
348348
UIApplication.shared.connectedScenes.first as? UIWindowScene
349349
}
@@ -356,7 +356,7 @@ public final class OpenIapModule: NSObject, OpenIapModuleProtocol {
356356
} else {
357357
result = try await product.purchase(options: options)
358358
}
359-
#elseif canImport(AppKit)
359+
#elseif os(macOS)
360360
// macOS: Use NSWindow (macOS 15.2+)
361361
if #available(macOS 15.2, *) {
362362
let window: NSWindow? = await MainActor.run {
@@ -1066,15 +1066,15 @@ public final class OpenIapModule: NSObject, OpenIapModuleProtocol {
10661066
/// - SeeAlso: https://developer.apple.com/documentation/storekit/skpaymentqueue/3566726-presentcoderedemptionsheet
10671067
public func presentCodeRedemptionSheetIOS() async throws -> Bool {
10681068
try await ensureConnection()
1069-
// tvOS: SKPaymentQueue.presentCodeRedemptionSheet explicitly unavailable on tvOS
1070-
#if canImport(UIKit) && !os(tvOS)
1069+
// presentCodeRedemptionSheet is only available on iOS, not tvOS/watchOS/macOS
1070+
#if os(iOS)
10711071
await MainActor.run {
10721072
SKPaymentQueue.default().presentCodeRedemptionSheet()
10731073
}
10741074
return true
10751075
#else
10761076
throw makePurchaseError(code: .featureNotSupported)
1077-
#endif // canImport(UIKit) && !os(tvOS)
1077+
#endif // os(iOS)
10781078
}
10791079

10801080
public func showManageSubscriptionsIOS() async throws -> [PurchaseIOS] {
@@ -1159,9 +1159,9 @@ public final class OpenIapModule: NSObject, OpenIapModuleProtocol {
11591159

11601160
public func presentExternalPurchaseLinkIOS(_ url: String) async throws -> ExternalPurchaseLinkResultIOS {
11611161
try await ensureConnection()
1162-
// UIKit platforms: Open external link using UIApplication.open
1162+
// UIApplication.open is available on iOS/tvOS/visionOS but not watchOS/macOS
11631163
// Reference: https://developer.apple.com/documentation/uikit/uiapplication/1648685-open
1164-
#if canImport(UIKit)
1164+
#if os(iOS) || os(tvOS) || os(visionOS)
11651165
guard let customLink = URL(string: url) else {
11661166
return ExternalPurchaseLinkResultIOS(
11671167
error: "Invalid URL",
@@ -1184,7 +1184,7 @@ public final class OpenIapModule: NSObject, OpenIapModuleProtocol {
11841184
}
11851185
#else
11861186
throw makePurchaseError(code: .featureNotSupported)
1187-
#endif // canImport(UIKit)
1187+
#endif // os(iOS) || os(tvOS) || os(visionOS)
11881188
}
11891189

11901190
// MARK: - ExternalPurchaseCustomLink (iOS 18.1+)

packages/apple/Sources/OpenIapProtocol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public protocol OpenIapModuleProtocol {
6969

7070
// Store Information
7171
func getStorefrontIOS() async throws -> String
72-
@available(iOS 16.0, macOS 14.0, *)
72+
@available(iOS 16.0, macOS 14.0, tvOS 16.0, watchOS 9.0, *)
7373
func getAppTransactionIOS() async throws -> AppTransaction?
7474

7575
// Subscription Management

packages/apple/Sources/OpenIapStore.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ public final class OpenIapStore: ObservableObject {
414414
try await module.getStorefrontIOS()
415415
}
416416

417-
@available(iOS 16.0, macOS 14.0, *)
417+
@available(iOS 16.0, macOS 14.0, tvOS 16.0, watchOS 9.0, *)
418418
public func getAppTransactionIOS() async throws -> AppTransaction? {
419419
try await module.getAppTransactionIOS()
420420
}

0 commit comments

Comments
 (0)