1+ import Foundation
2+ import StoreKit
3+
4+ // MARK: - Objective-C Bridge for Kotlin Multiplatform
5+
6+ @available ( iOS 15 . 0 , macOS 14 . 0 , * )
7+ @objc public extension OpenIapModule {
8+
9+ // MARK: - Connection Management
10+
11+ @objc func initConnectionWithCompletion( _ completion: @escaping ( Bool , Error ? ) -> Void ) {
12+ Task {
13+ do {
14+ let result = try await initConnection ( )
15+ completion ( result, nil )
16+ } catch {
17+ completion ( false , error)
18+ }
19+ }
20+ }
21+
22+ @objc func endConnectionWithCompletion( _ completion: @escaping ( Bool , Error ? ) -> Void ) {
23+ Task {
24+ do {
25+ let result = try await endConnection ( )
26+ completion ( result, nil )
27+ } catch {
28+ completion ( false , error)
29+ }
30+ }
31+ }
32+
33+ // MARK: - Product Management
34+
35+ @objc func fetchProductsWithSkus(
36+ _ skus: [ String ] ,
37+ type: String ? ,
38+ completion: @escaping ( [ Any ] ? , Error ? ) -> Void
39+ ) {
40+ Task {
41+ do {
42+ let productType = type. flatMap { ProductQueryType ( rawValue: $0) }
43+ let request = ProductRequest ( skus: skus, type: productType)
44+ let result = try await fetchProducts ( request)
45+
46+ switch result {
47+ case . products( let products) :
48+ // Extract ProductIOS from Product enum and convert to dictionaries
49+ let productIOS = ( products ?? [ ] ) . compactMap { product -> ProductIOS ? in
50+ guard case let . productIos( value) = product else { return nil }
51+ return value
52+ }
53+ print ( " [OpenIAP] Fetched \( productIOS. count) products " )
54+ let dictionaries = productIOS. map { OpenIapSerialization . encode ( $0) }
55+ completion ( dictionaries, nil )
56+
57+ case . subscriptions( let subscriptions) :
58+ // Extract ProductSubscriptionIOS from ProductSubscription enum and convert to dictionaries
59+ let subscriptionIOS = ( subscriptions ?? [ ] ) . compactMap { subscription -> ProductSubscriptionIOS ? in
60+ guard case let . productSubscriptionIos( value) = subscription else { return nil }
61+ return value
62+ }
63+ print ( " [OpenIAP] Fetched \( subscriptionIOS. count) subscriptions " )
64+ let dictionaries = subscriptionIOS. map { OpenIapSerialization . encode ( $0) }
65+ completion ( dictionaries, nil )
66+ }
67+ } catch {
68+ completion ( nil , error)
69+ }
70+ }
71+ }
72+
73+ @objc func getPromotedProductIOSWithCompletion( _ completion: @escaping ( Any ? , Error ? ) -> Void ) {
74+ Task {
75+ do {
76+ let product = try await getPromotedProductIOS ( )
77+ if let productIOS = product {
78+ // Convert ProductIOS to dictionary
79+ let dictionary = OpenIapSerialization . encode ( productIOS)
80+ completion ( dictionary, nil )
81+ } else {
82+ completion ( nil , nil )
83+ }
84+ } catch {
85+ completion ( nil , error)
86+ }
87+ }
88+ }
89+
90+ // MARK: - Purchase Management
91+
92+ @objc func requestPurchaseWithSku(
93+ _ sku: String ,
94+ quantity: Int ,
95+ type: String ? ,
96+ completion: @escaping ( Any ? , Error ? ) -> Void
97+ ) {
98+ Task {
99+ do {
100+ let productType = type. flatMap { ProductQueryType ( rawValue: $0) } ?? . inApp
101+ let iosProps = RequestPurchaseIosProps (
102+ andDangerouslyFinishTransactionAutomatically: nil ,
103+ appAccountToken: nil ,
104+ quantity: quantity,
105+ sku: sku,
106+ withOffer: nil
107+ )
108+ let props = RequestPurchaseProps (
109+ request: . purchase(
110+ RequestPurchasePropsByPlatforms ( android: nil , ios: iosProps)
111+ ) ,
112+ type: productType
113+ )
114+
115+ let result = try await requestPurchase ( props)
116+
117+ switch result {
118+ case . purchase( let purchase) :
119+ let dictionary = OpenIapSerialization . purchase ( purchase)
120+ completion ( dictionary, nil )
121+ case . purchases( let purchases) :
122+ if let firstPurchase = purchases? . first {
123+ let dictionary = OpenIapSerialization . purchase ( firstPurchase)
124+ completion ( dictionary, nil )
125+ } else {
126+ completion ( nil , nil )
127+ }
128+ case . none:
129+ completion ( nil , nil )
130+ }
131+ } catch {
132+ completion ( nil , error)
133+ }
134+ }
135+ }
136+
137+ @objc func restorePurchasesWithCompletion( _ completion: @escaping ( Error ? ) -> Void ) {
138+ Task {
139+ do {
140+ try await restorePurchases ( )
141+ completion ( nil )
142+ } catch {
143+ completion ( error)
144+ }
145+ }
146+ }
147+
148+ @objc func getAvailablePurchasesWithCompletion( _ completion: @escaping ( [ Any ] ? , Error ? ) -> Void ) {
149+ Task {
150+ do {
151+ let purchases = try await getAvailablePurchases ( nil )
152+ let dictionaries = OpenIapSerialization . purchases ( purchases)
153+ completion ( dictionaries, nil )
154+ } catch {
155+ completion ( nil , error)
156+ }
157+ }
158+ }
159+
160+ // MARK: - Transaction Management
161+
162+ @objc func finishTransactionWithPurchaseId(
163+ _ purchaseId: String ,
164+ productId: String ,
165+ isConsumable: Bool ,
166+ completion: @escaping ( Error ? ) -> Void
167+ ) {
168+ Task {
169+ do {
170+ let purchaseInput = PurchaseInput (
171+ id: purchaseId,
172+ ids: nil ,
173+ isAutoRenewing: false ,
174+ platform: . ios,
175+ productId: productId,
176+ purchaseState: . purchased,
177+ purchaseToken: nil ,
178+ quantity: 1 ,
179+ transactionDate: Date ( ) . timeIntervalSince1970
180+ )
181+ try await finishTransaction ( purchase: purchaseInput, isConsumable: isConsumable)
182+ completion ( nil )
183+ } catch {
184+ completion ( error)
185+ }
186+ }
187+ }
188+
189+ @objc func getPendingTransactionsIOSWithCompletion( _ completion: @escaping ( [ Any ] ? , Error ? ) -> Void ) {
190+ Task {
191+ do {
192+ let transactions = try await getPendingTransactionsIOS ( )
193+ let dictionaries = OpenIapSerialization . purchases ( transactions)
194+ completion ( dictionaries, nil )
195+ } catch {
196+ completion ( nil , error)
197+ }
198+ }
199+ }
200+
201+ @objc func clearTransactionIOSWithCompletion( _ completion: @escaping ( Bool , Error ? ) -> Void ) {
202+ Task {
203+ do {
204+ let result = try await clearTransactionIOS ( )
205+ completion ( result, nil )
206+ } catch {
207+ completion ( false , error)
208+ }
209+ }
210+ }
211+
212+ // MARK: - Validation
213+
214+ @objc func getReceiptDataIOSWithCompletion( _ completion: @escaping ( String ? , Error ? ) -> Void ) {
215+ Task {
216+ do {
217+ let receipt = try await getReceiptDataIOS ( )
218+ completion ( receipt, nil )
219+ } catch {
220+ completion ( nil , error)
221+ }
222+ }
223+ }
224+
225+ // MARK: - Store Information
226+
227+ @objc func getStorefrontIOSWithCompletion( _ completion: @escaping ( String ? , Error ? ) -> Void ) {
228+ Task {
229+ do {
230+ let storefront = try await getStorefrontIOS ( )
231+ completion ( storefront, nil )
232+ } catch {
233+ completion ( nil , error)
234+ }
235+ }
236+ }
237+
238+ // MARK: - Subscription Management
239+
240+ @objc func getActiveSubscriptionsWithCompletion( _ completion: @escaping ( [ Any ] ? , Error ? ) -> Void ) {
241+ Task {
242+ do {
243+ let subscriptions = try await getActiveSubscriptions ( nil )
244+ let dictionaries = subscriptions. map { OpenIapSerialization . encode ( $0) }
245+ completion ( dictionaries, nil )
246+ } catch {
247+ completion ( nil , error)
248+ }
249+ }
250+ }
251+
252+ // MARK: - UI
253+
254+ @objc func presentCodeRedemptionSheetIOSWithCompletion( _ completion: @escaping ( Bool , Error ? ) -> Void ) {
255+ Task {
256+ do {
257+ let result = try await presentCodeRedemptionSheetIOS ( )
258+ completion ( result, nil )
259+ } catch {
260+ completion ( false , error)
261+ }
262+ }
263+ }
264+
265+ @objc func showManageSubscriptionsIOSWithCompletion( _ completion: @escaping ( [ Any ] ? , Error ? ) -> Void ) {
266+ Task {
267+ do {
268+ let purchases = try await showManageSubscriptionsIOS ( )
269+ let dictionaries = OpenIapSerialization . purchases ( purchases)
270+ completion ( dictionaries, nil )
271+ } catch {
272+ completion ( nil , error)
273+ }
274+ }
275+ }
276+ }
0 commit comments