From 9e799a1bf86c04c8b678353c50a7a6a943f293a5 Mon Sep 17 00:00:00 2001 From: alihassan143 Date: Tue, 19 May 2026 21:48:26 +0500 Subject: [PATCH 1/5] feat(flutter_inapp_purchase): add Swift Package Manager support for iOS and macOS - Rewrite Package.swift with proper iOS 15.0 and macOS 14.0 platform declarations, removing incorrect ObjC-only publicHeadersPath and cSettings - Add OpenIAP SPM dependency (https://github.com/hyodotdev/openiap.git v2.2.1) so the plugin's native OpenIAP import resolves correctly under SPM - Point the SPM target to ios/Classes which already uses #if canImport(FlutterMacOS) conditionals, making a single source tree compile correctly for both platforms - Sync macos/Classes/FlutterInappPurchasePlugin.swift with the canonical iOS version, restoring feature parity for CocoaPods macOS builds (beginRefundRequestIOS, syncIOS, subscriptionStatusIOS, currentEntitlementIOS, latestTransactionIOS, isTransactionVerifiedIOS, getTransactionJwsIOS, getReceiptDataIOS, getAppTransactionIOS, verifyPurchaseWithProvider and proper availability guards) --- .../flutter_inapp_purchase/Package.swift | 29 +- .../Classes/FlutterInappPurchasePlugin.swift | 391 ++++++++++++++++-- 2 files changed, 377 insertions(+), 43 deletions(-) diff --git a/libraries/flutter_inapp_purchase/Package.swift b/libraries/flutter_inapp_purchase/Package.swift index f87e7998..c8ea4bbb 100644 --- a/libraries/flutter_inapp_purchase/Package.swift +++ b/libraries/flutter_inapp_purchase/Package.swift @@ -1,30 +1,29 @@ // swift-tools-version: 5.9 -// The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "flutter_inapp_purchase", platforms: [ - .iOS("12.0") + .iOS("15.0"), + .macOS("14.0"), ], products: [ - .library(name: "flutter-inapp-purchase", targets: ["flutter_inapp_purchase"]) + .library(name: "flutter_inapp_purchase", targets: ["flutter_inapp_purchase"]), + ], + dependencies: [ + .package( + url: "https://github.com/hyodotdev/openiap.git", + exact: "2.2.1" + ), ], - dependencies: [], targets: [ .target( name: "flutter_inapp_purchase", - dependencies: [], - path: "ios/Classes", - resources: [ - .process("../Assets") + dependencies: [ + .product(name: "OpenIAP", package: "openiap"), ], - publicHeadersPath: "", - cSettings: [ - .headerSearchPath("../Flutter"), - .headerSearchPath("../../../Flutter/Export") - ] - ) + path: "ios/Classes" + ), ] -) \ No newline at end of file +) diff --git a/libraries/flutter_inapp_purchase/macos/Classes/FlutterInappPurchasePlugin.swift b/libraries/flutter_inapp_purchase/macos/Classes/FlutterInappPurchasePlugin.swift index cf1318c5..aa23951a 100644 --- a/libraries/flutter_inapp_purchase/macos/Classes/FlutterInappPurchasePlugin.swift +++ b/libraries/flutter_inapp_purchase/macos/Classes/FlutterInappPurchasePlugin.swift @@ -1,5 +1,9 @@ import Foundation +#if canImport(FlutterMacOS) import FlutterMacOS +#else +import Flutter +#endif // StoreKit is not directly used; relying on OpenIAP import OpenIAP @@ -28,7 +32,11 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { FlutterIapLog.debug("Swift register called") + #if canImport(FlutterMacOS) let channel = FlutterMethodChannel(name: "flutter_inapp", binaryMessenger: registrar.messenger) + #else + let channel = FlutterMethodChannel(name: "flutter_inapp", binaryMessenger: registrar.messenger()) + #endif let instance = FlutterInappPurchasePlugin() registrar.addMethodCallDelegate(instance, channel: channel) instance.channel = channel @@ -148,7 +156,23 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { clearTransactionIOS(result: result) case "presentCodeRedemptionSheetIOS": - presentCodeRedemptionSheetIOS(result: result) + if #available(iOS 16.0, macOS 14.0, tvOS 16.0, *) { + presentCodeRedemptionSheetIOS(result: result) + } else { + let code: ErrorCode = .featureNotSupported + result(FlutterError(code: code.rawValue, message: "Code redemption requires iOS 16.0+, macOS 14.0+, or tvOS 16.0+", details: nil)) + } + + case "beginRefundRequestIOS": + if let args = call.arguments as? [String: Any], + let sku = args["sku"] as? String { + beginRefundRequestIOS(sku: sku, result: result) + } else if let sku = call.arguments as? String { + beginRefundRequestIOS(sku: sku, result: result) + } else { + let code: ErrorCode = .developerError + result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) + } case "getPromotedProductIOS": getPromotedProductIOS(result: result) @@ -168,17 +192,88 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { result(FlutterError(code: code.rawValue, message: "productId required", details: nil)) } + case "currentEntitlementIOS": + if let args = call.arguments as? [String: Any], + let sku = args["sku"] as? String { + currentEntitlementIOS(sku: sku, result: result) + } else if let sku = call.arguments as? String { + currentEntitlementIOS(sku: sku, result: result) + } else { + let code: ErrorCode = .developerError + result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) + } + + case "latestTransactionIOS": + if let args = call.arguments as? [String: Any], + let sku = args["sku"] as? String { + latestTransactionIOS(sku: sku, result: result) + } else if let sku = call.arguments as? String { + latestTransactionIOS(sku: sku, result: result) + } else { + let code: ErrorCode = .developerError + result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) + } + + case "isTransactionVerifiedIOS": + if let args = call.arguments as? [String: Any], + let sku = args["sku"] as? String { + isTransactionVerifiedIOS(sku: sku, result: result) + } else if let sku = call.arguments as? String { + isTransactionVerifiedIOS(sku: sku, result: result) + } else { + let code: ErrorCode = .developerError + result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) + } + + case "getTransactionJwsIOS": + if let args = call.arguments as? [String: Any], + let sku = args["sku"] as? String { + getTransactionJwsIOS(sku: sku, result: result) + } else if let sku = call.arguments as? String { + getTransactionJwsIOS(sku: sku, result: result) + } else { + let code: ErrorCode = .developerError + result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) + } + + case "getReceiptDataIOS": + getReceiptDataIOS(result: result) + + case "getAppTransactionIOS", "getAppTransaction": + if #available(iOS 16.0, macOS 14.0, tvOS 16.0, *) { + getAppTransactionIOS(result: result) + } else { + let code: ErrorCode = .featureNotSupported + result(FlutterError(code: code.rawValue, message: "getAppTransactionIOS requires iOS 16.0+", details: nil)) + } + + case "syncIOS": + syncIOS(result: result) + + case "subscriptionStatusIOS", "getSubscriptionStatus": + if let args = call.arguments as? [String: Any], + let sku = args["sku"] as? String { + subscriptionStatusIOS(sku: sku, result: result) + } else if let sku = call.arguments as? String { + subscriptionStatusIOS(sku: sku, result: result) + } else { + let code: ErrorCode = .developerError + result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) + } + case "validateReceiptIOS", "verifyPurchase": guard let args = call.arguments as? [String: Any] else { let code: ErrorCode = .developerError result(FlutterError(code: code.rawValue, message: "arguments required", details: nil)) return } + // Support new API: { apple: { sku: "..." } } or legacy { sku: "..." } let sku: String if let appleOptions = args["apple"] as? [String: Any], let appleSku = appleOptions["sku"] as? String { sku = appleSku } else if let legacySku = args["sku"] as? String { + // Backwards compatibility with legacy API sku = legacySku } else { let code: ErrorCode = .developerError @@ -187,32 +282,39 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } validateReceiptIOS(productId: sku, result: result) - case "verifyPurchaseWithProvider": - guard let args = call.arguments as? [String: Any], - let providerStr = args["provider"] as? String else { - let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "provider required", details: nil)) - return - } - verifyPurchaseWithProvider(args: args, provider: providerStr, result: result) - case "canPresentExternalPurchaseNoticeIOS": - canPresentExternalPurchaseNoticeIOS(result: result) + if #available(iOS 17.4, macOS 14.4, tvOS 17.4, *) { + canPresentExternalPurchaseNoticeIOS(result: result) + } else { + let code: ErrorCode = .featureNotSupported + result(FlutterError(code: code.rawValue, message: "External purchase notice requires iOS 17.4+, macOS 14.4+, or tvOS 17.4+", details: nil)) + } case "presentExternalPurchaseNoticeSheetIOS": - presentExternalPurchaseNoticeSheetIOS(result: result) + if #available(iOS 17.4, macOS 14.4, tvOS 17.4, *) { + presentExternalPurchaseNoticeSheetIOS(result: result) + } else { + let code: ErrorCode = .featureNotSupported + result(FlutterError(code: code.rawValue, message: "External purchase notice requires iOS 17.4+, macOS 14.4+, or tvOS 17.4+", details: nil)) + } case "presentExternalPurchaseLinkIOS": - if let args = call.arguments as? [String: Any], - let url = args["url"] as? String { - presentExternalPurchaseLinkIOS(url: url, result: result) - } else if let url = call.arguments as? String { - presentExternalPurchaseLinkIOS(url: url, result: result) + if #available(iOS 16.0, macOS 14.0, tvOS 16.0, *) { + if let args = call.arguments as? [String: Any], + let url = args["url"] as? String { + presentExternalPurchaseLinkIOS(url: url, result: result) + } else if let url = call.arguments as? String { + presentExternalPurchaseLinkIOS(url: url, result: result) + } else { + let code: ErrorCode = .developerError + result(FlutterError(code: code.rawValue, message: "url required", details: nil)) + } } else { - let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "url required", details: nil)) + let code: ErrorCode = .featureNotSupported + result(FlutterError(code: code.rawValue, message: "External purchase link requires iOS 16.0+, macOS 14.0+, or tvOS 16.0+", details: nil)) } + // MARK: - ExternalPurchaseCustomLink (iOS 18.1+) case "isEligibleForExternalPurchaseCustomLinkIOS": if #available(iOS 18.1, macOS 15.0, tvOS 18.1, *) { isEligibleForExternalPurchaseCustomLinkIOS(result: result) @@ -230,7 +332,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { getExternalPurchaseCustomLinkTokenIOS(tokenType: tokenType, result: result) } else { let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "tokenType required", details: nil)) + result(FlutterError(code: code.rawValue, message: "tokenType required ('acquisition' or 'services')", details: nil)) } } else { let code: ErrorCode = .featureNotSupported @@ -246,13 +348,22 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { showExternalPurchaseCustomLinkNoticeIOS(noticeType: noticeType, result: result) } else { let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "noticeType required", details: nil)) + result(FlutterError(code: code.rawValue, message: "noticeType required ('browser')", details: nil)) } } else { let code: ErrorCode = .featureNotSupported result(FlutterError(code: code.rawValue, message: "ExternalPurchaseCustomLink requires iOS 18.1+, macOS 15.0+, or tvOS 18.1+", details: nil)) } + case "verifyPurchaseWithProvider": + guard let args = call.arguments as? [String: Any], + let providerStr = args["provider"] as? String else { + let code: ErrorCode = .developerError + result(FlutterError(code: code.rawValue, message: "provider required", details: nil)) + return + } + verifyPurchaseWithProvider(args: args, provider: providerStr, result: result) + default: result(FlutterMethodNotImplemented) } @@ -320,12 +431,13 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } } - + if promotedProductToken == nil { promotedProductToken = OpenIapModule.shared.promotedProductListenerIOS { [weak self] productId in Task { @MainActor in guard let self = self else { return } FlutterIapLog.debug("promotedProductListenerIOS fired for: \(productId)") + // Emit event that Dart expects: name 'iap-promoted-product' with String payload self.channel?.invokeMethod("iap-promoted-product", arguments: productId) } } @@ -365,7 +477,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { self?.emitPurchaseUpdated(purchase, method: "purchase-updated") }, options: purchaseUpdatedListenerOptions) } - + private func removeOpenIapListeners() { if let token = purchaseUpdatedToken { OpenIapModule.shared.removeListener(token) } if let token = purchaseErrorToken { OpenIapModule.shared.removeListener(token) } @@ -566,6 +678,28 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } + private func beginRefundRequestIOS(sku: String, result: @escaping FlutterResult) { + FlutterIapLog.debug("beginRefundRequestIOS called for sku=\(sku)") + Task { @MainActor in + do { + let status = try await OpenIapModule.shared.beginRefundRequestIOS(sku: sku) + FlutterIapLog.result("beginRefundRequestIOS", value: status ?? "nil") + result(status) + } catch let purchaseError as PurchaseError { + FlutterIapLog.failure("beginRefundRequestIOS", error: purchaseError) + result(FlutterError( + code: purchaseError.code.rawValue, + message: purchaseError.message, + details: purchaseError.productId ?? sku + )) + } catch { + FlutterIapLog.failure("beginRefundRequestIOS", error: error) + let code: ErrorCode = .serviceError + result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) + } + } + } + @available(iOS 15.0, macOS 14.0, tvOS 15.0, *) private func showManageSubscriptionsIOS(result: @escaping FlutterResult) { FlutterIapLog.debug("showManageSubscriptionsIOS called") @@ -696,7 +830,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } } - + private func getAllTransactionsIOS(result: @escaping FlutterResult) { Task { @MainActor in do { @@ -713,7 +847,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } } - + private func clearTransactionIOS(result: @escaping FlutterResult) { FlutterIapLog.debug("clearTransactionIOS called") Task { @MainActor in @@ -787,6 +921,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { FlutterIapLog.debug("verifyPurchaseWithProvider called with provider: \(provider)") Task { @MainActor in do { + // Build props dictionary for OpenIAP var propsDict: [String: Any] = ["provider": provider] if let iapkit = args["iapkit"] as? [String: Any] { var iapkitDict: [String: Any] = [:] @@ -802,10 +937,12 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { propsDict["iapkit"] = iapkitDict } + // Use JSONSerialization + JSONDecoder let jsonData = try JSONSerialization.data(withJSONObject: propsDict) let props = try JSONDecoder().decode(VerifyPurchaseWithProviderProps.self, from: jsonData) let res = try await OpenIapModule.shared.verifyPurchaseWithProvider(props) + // Convert result to dictionary var payload: [String: Any] = [ "provider": res.provider.rawValue ] @@ -827,9 +964,203 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } - // MARK: - Alternative Billing (iOS 18.2+) + private func syncIOS(result: @escaping FlutterResult) { + FlutterIapLog.debug("syncIOS called") + Task { @MainActor in + do { + let success = try await OpenIapModule.shared.syncIOS() + FlutterIapLog.result("syncIOS", value: success) + result(success) + } catch let purchaseError as PurchaseError { + FlutterIapLog.failure("syncIOS", error: purchaseError) + result(FlutterError( + code: purchaseError.code.rawValue, + message: purchaseError.message, + details: purchaseError.productId + )) + } catch { + FlutterIapLog.failure("syncIOS", error: error) + let code: ErrorCode = .syncError + result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) + } + } + } + + private func subscriptionStatusIOS(sku: String, result: @escaping FlutterResult) { + FlutterIapLog.debug("subscriptionStatusIOS called for sku=\(sku)") + Task { @MainActor in + do { + let statuses = try await OpenIapModule.shared.subscriptionStatusIOS(sku: sku) + let payload = statuses.map { + FlutterIapHelper.sanitizeDictionary(OpenIapSerialization.encode($0)) + } + FlutterIapLog.result("subscriptionStatusIOS", value: payload) + result(payload) + } catch let purchaseError as PurchaseError { + FlutterIapLog.failure("subscriptionStatusIOS", error: purchaseError) + result(FlutterError( + code: purchaseError.code.rawValue, + message: purchaseError.message, + details: purchaseError.productId ?? sku + )) + } catch { + FlutterIapLog.failure("subscriptionStatusIOS", error: error) + let code: ErrorCode = .serviceError + result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) + } + } + } + + @available(iOS 16.0, macOS 14.0, tvOS 16.0, *) + private func getAppTransactionIOS(result: @escaping FlutterResult) { + FlutterIapLog.debug("getAppTransactionIOS called") + Task { @MainActor in + do { + if let tx = try await OpenIapModule.shared.getAppTransactionIOS() { + let payload = FlutterIapHelper.sanitizeDictionary(OpenIapSerialization.encode(tx)) + FlutterIapLog.result("getAppTransactionIOS", value: payload) + result(payload) + } else { + result(nil) + } + } catch let purchaseError as PurchaseError { + FlutterIapLog.failure("getAppTransactionIOS", error: purchaseError) + result(FlutterError( + code: purchaseError.code.rawValue, + message: purchaseError.message, + details: purchaseError.productId + )) + } catch { + FlutterIapLog.failure("getAppTransactionIOS", error: error) + let code: ErrorCode = .serviceError + result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) + } + } + } + + // MARK: - StoreKit 2 entitlement queries (iOS 15.0+) + + private func currentEntitlementIOS(sku: String, result: @escaping FlutterResult) { + FlutterIapLog.debug("currentEntitlementIOS called for sku=\(sku)") + Task { @MainActor in + do { + if let purchase = try await OpenIapModule.shared.currentEntitlementIOS(sku: sku) { + let payload = FlutterIapHelper.sanitizeDictionary(OpenIapSerialization.encode(purchase)) + FlutterIapLog.result("currentEntitlementIOS", value: payload) + result(payload) + } else { + result(nil) + } + } catch let purchaseError as PurchaseError { + FlutterIapLog.failure("currentEntitlementIOS", error: purchaseError) + result(FlutterError( + code: purchaseError.code.rawValue, + message: purchaseError.message, + details: purchaseError.productId ?? sku + )) + } catch { + FlutterIapLog.failure("currentEntitlementIOS", error: error) + let code: ErrorCode = .serviceError + result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) + } + } + } + + private func latestTransactionIOS(sku: String, result: @escaping FlutterResult) { + FlutterIapLog.debug("latestTransactionIOS called for sku=\(sku)") + Task { @MainActor in + do { + if let purchase = try await OpenIapModule.shared.latestTransactionIOS(sku: sku) { + let payload = FlutterIapHelper.sanitizeDictionary(OpenIapSerialization.encode(purchase)) + FlutterIapLog.result("latestTransactionIOS", value: payload) + result(payload) + } else { + result(nil) + } + } catch let purchaseError as PurchaseError { + FlutterIapLog.failure("latestTransactionIOS", error: purchaseError) + result(FlutterError( + code: purchaseError.code.rawValue, + message: purchaseError.message, + details: purchaseError.productId ?? sku + )) + } catch { + FlutterIapLog.failure("latestTransactionIOS", error: error) + let code: ErrorCode = .serviceError + result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) + } + } + } + + private func isTransactionVerifiedIOS(sku: String, result: @escaping FlutterResult) { + FlutterIapLog.debug("isTransactionVerifiedIOS called for sku=\(sku)") + Task { @MainActor in + do { + let verified = try await OpenIapModule.shared.isTransactionVerifiedIOS(sku: sku) + FlutterIapLog.result("isTransactionVerifiedIOS", value: verified) + result(verified) + } catch let purchaseError as PurchaseError { + FlutterIapLog.failure("isTransactionVerifiedIOS", error: purchaseError) + result(FlutterError( + code: purchaseError.code.rawValue, + message: purchaseError.message, + details: purchaseError.productId ?? sku + )) + } catch { + FlutterIapLog.failure("isTransactionVerifiedIOS", error: error) + let code: ErrorCode = .serviceError + result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) + } + } + } + + private func getTransactionJwsIOS(sku: String, result: @escaping FlutterResult) { + FlutterIapLog.debug("getTransactionJwsIOS called for sku=\(sku)") + Task { @MainActor in + do { + let jws = try await OpenIapModule.shared.getTransactionJwsIOS(sku: sku) + FlutterIapLog.result("getTransactionJwsIOS", value: jws == nil ? nil : "") + result(jws) + } catch let purchaseError as PurchaseError { + FlutterIapLog.failure("getTransactionJwsIOS", error: purchaseError) + result(FlutterError( + code: purchaseError.code.rawValue, + message: purchaseError.message, + details: purchaseError.productId ?? sku + )) + } catch { + FlutterIapLog.failure("getTransactionJwsIOS", error: error) + let code: ErrorCode = .serviceError + result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) + } + } + } + + private func getReceiptDataIOS(result: @escaping FlutterResult) { + FlutterIapLog.debug("getReceiptDataIOS called") + Task { @MainActor in + do { + let receipt = try await OpenIapModule.shared.getReceiptDataIOS() + FlutterIapLog.result("getReceiptDataIOS", value: receipt == nil ? nil : "") + result(receipt) + } catch let purchaseError as PurchaseError { + FlutterIapLog.failure("getReceiptDataIOS", error: purchaseError) + result(FlutterError( + code: purchaseError.code.rawValue, + message: purchaseError.message, + details: purchaseError.productId + )) + } catch { + FlutterIapLog.failure("getReceiptDataIOS", error: error) + let code: ErrorCode = .serviceError + result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) + } + } + } + + // MARK: - External Purchase Notice (iOS 17.4+) - @available(iOS 18.2, macOS 14.0, tvOS 18.2, *) + @available(iOS 17.4, macOS 14.4, tvOS 17.4, *) private func canPresentExternalPurchaseNoticeIOS(result: @escaping FlutterResult) { FlutterIapLog.debug("canPresentExternalPurchaseNoticeIOS called") Task { @MainActor in @@ -846,7 +1177,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } - @available(iOS 18.2, macOS 14.0, tvOS 18.2, *) + @available(iOS 17.4, macOS 14.4, tvOS 17.4, *) private func presentExternalPurchaseNoticeSheetIOS(result: @escaping FlutterResult) { FlutterIapLog.debug("presentExternalPurchaseNoticeSheetIOS called") Task { @MainActor in @@ -959,7 +1290,11 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { public class FlutterInappPurchasePluginLegacy: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { if #unavailable(iOS 15.0, macOS 14.0, tvOS 15.0) { + #if canImport(FlutterMacOS) let channel = FlutterMethodChannel(name: "flutter_inapp", binaryMessenger: registrar.messenger) + #else + let channel = FlutterMethodChannel(name: "flutter_inapp", binaryMessenger: registrar.messenger()) + #endif let instance = FlutterInappPurchasePluginLegacy() registrar.addMethodCallDelegate(instance, channel: channel) } From 1a4618e64e8164b10bfc6298c06fde9a30bac290 Mon Sep 17 00:00:00 2001 From: alihassan143 Date: Tue, 19 May 2026 21:51:17 +0500 Subject: [PATCH 2/5] revert: restore macos FlutterInappPurchasePlugin.swift to original --- .../Classes/FlutterInappPurchasePlugin.swift | 391 ++---------------- 1 file changed, 28 insertions(+), 363 deletions(-) diff --git a/libraries/flutter_inapp_purchase/macos/Classes/FlutterInappPurchasePlugin.swift b/libraries/flutter_inapp_purchase/macos/Classes/FlutterInappPurchasePlugin.swift index aa23951a..cf1318c5 100644 --- a/libraries/flutter_inapp_purchase/macos/Classes/FlutterInappPurchasePlugin.swift +++ b/libraries/flutter_inapp_purchase/macos/Classes/FlutterInappPurchasePlugin.swift @@ -1,9 +1,5 @@ import Foundation -#if canImport(FlutterMacOS) import FlutterMacOS -#else -import Flutter -#endif // StoreKit is not directly used; relying on OpenIAP import OpenIAP @@ -32,11 +28,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { FlutterIapLog.debug("Swift register called") - #if canImport(FlutterMacOS) let channel = FlutterMethodChannel(name: "flutter_inapp", binaryMessenger: registrar.messenger) - #else - let channel = FlutterMethodChannel(name: "flutter_inapp", binaryMessenger: registrar.messenger()) - #endif let instance = FlutterInappPurchasePlugin() registrar.addMethodCallDelegate(instance, channel: channel) instance.channel = channel @@ -156,23 +148,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { clearTransactionIOS(result: result) case "presentCodeRedemptionSheetIOS": - if #available(iOS 16.0, macOS 14.0, tvOS 16.0, *) { - presentCodeRedemptionSheetIOS(result: result) - } else { - let code: ErrorCode = .featureNotSupported - result(FlutterError(code: code.rawValue, message: "Code redemption requires iOS 16.0+, macOS 14.0+, or tvOS 16.0+", details: nil)) - } - - case "beginRefundRequestIOS": - if let args = call.arguments as? [String: Any], - let sku = args["sku"] as? String { - beginRefundRequestIOS(sku: sku, result: result) - } else if let sku = call.arguments as? String { - beginRefundRequestIOS(sku: sku, result: result) - } else { - let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) - } + presentCodeRedemptionSheetIOS(result: result) case "getPromotedProductIOS": getPromotedProductIOS(result: result) @@ -192,88 +168,17 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { result(FlutterError(code: code.rawValue, message: "productId required", details: nil)) } - case "currentEntitlementIOS": - if let args = call.arguments as? [String: Any], - let sku = args["sku"] as? String { - currentEntitlementIOS(sku: sku, result: result) - } else if let sku = call.arguments as? String { - currentEntitlementIOS(sku: sku, result: result) - } else { - let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) - } - - case "latestTransactionIOS": - if let args = call.arguments as? [String: Any], - let sku = args["sku"] as? String { - latestTransactionIOS(sku: sku, result: result) - } else if let sku = call.arguments as? String { - latestTransactionIOS(sku: sku, result: result) - } else { - let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) - } - - case "isTransactionVerifiedIOS": - if let args = call.arguments as? [String: Any], - let sku = args["sku"] as? String { - isTransactionVerifiedIOS(sku: sku, result: result) - } else if let sku = call.arguments as? String { - isTransactionVerifiedIOS(sku: sku, result: result) - } else { - let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) - } - - case "getTransactionJwsIOS": - if let args = call.arguments as? [String: Any], - let sku = args["sku"] as? String { - getTransactionJwsIOS(sku: sku, result: result) - } else if let sku = call.arguments as? String { - getTransactionJwsIOS(sku: sku, result: result) - } else { - let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) - } - - case "getReceiptDataIOS": - getReceiptDataIOS(result: result) - - case "getAppTransactionIOS", "getAppTransaction": - if #available(iOS 16.0, macOS 14.0, tvOS 16.0, *) { - getAppTransactionIOS(result: result) - } else { - let code: ErrorCode = .featureNotSupported - result(FlutterError(code: code.rawValue, message: "getAppTransactionIOS requires iOS 16.0+", details: nil)) - } - - case "syncIOS": - syncIOS(result: result) - - case "subscriptionStatusIOS", "getSubscriptionStatus": - if let args = call.arguments as? [String: Any], - let sku = args["sku"] as? String { - subscriptionStatusIOS(sku: sku, result: result) - } else if let sku = call.arguments as? String { - subscriptionStatusIOS(sku: sku, result: result) - } else { - let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "sku required", details: nil)) - } - case "validateReceiptIOS", "verifyPurchase": guard let args = call.arguments as? [String: Any] else { let code: ErrorCode = .developerError result(FlutterError(code: code.rawValue, message: "arguments required", details: nil)) return } - // Support new API: { apple: { sku: "..." } } or legacy { sku: "..." } let sku: String if let appleOptions = args["apple"] as? [String: Any], let appleSku = appleOptions["sku"] as? String { sku = appleSku } else if let legacySku = args["sku"] as? String { - // Backwards compatibility with legacy API sku = legacySku } else { let code: ErrorCode = .developerError @@ -282,39 +187,32 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } validateReceiptIOS(productId: sku, result: result) - case "canPresentExternalPurchaseNoticeIOS": - if #available(iOS 17.4, macOS 14.4, tvOS 17.4, *) { - canPresentExternalPurchaseNoticeIOS(result: result) - } else { - let code: ErrorCode = .featureNotSupported - result(FlutterError(code: code.rawValue, message: "External purchase notice requires iOS 17.4+, macOS 14.4+, or tvOS 17.4+", details: nil)) + case "verifyPurchaseWithProvider": + guard let args = call.arguments as? [String: Any], + let providerStr = args["provider"] as? String else { + let code: ErrorCode = .developerError + result(FlutterError(code: code.rawValue, message: "provider required", details: nil)) + return } + verifyPurchaseWithProvider(args: args, provider: providerStr, result: result) + + case "canPresentExternalPurchaseNoticeIOS": + canPresentExternalPurchaseNoticeIOS(result: result) case "presentExternalPurchaseNoticeSheetIOS": - if #available(iOS 17.4, macOS 14.4, tvOS 17.4, *) { - presentExternalPurchaseNoticeSheetIOS(result: result) - } else { - let code: ErrorCode = .featureNotSupported - result(FlutterError(code: code.rawValue, message: "External purchase notice requires iOS 17.4+, macOS 14.4+, or tvOS 17.4+", details: nil)) - } + presentExternalPurchaseNoticeSheetIOS(result: result) case "presentExternalPurchaseLinkIOS": - if #available(iOS 16.0, macOS 14.0, tvOS 16.0, *) { - if let args = call.arguments as? [String: Any], - let url = args["url"] as? String { - presentExternalPurchaseLinkIOS(url: url, result: result) - } else if let url = call.arguments as? String { - presentExternalPurchaseLinkIOS(url: url, result: result) - } else { - let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "url required", details: nil)) - } + if let args = call.arguments as? [String: Any], + let url = args["url"] as? String { + presentExternalPurchaseLinkIOS(url: url, result: result) + } else if let url = call.arguments as? String { + presentExternalPurchaseLinkIOS(url: url, result: result) } else { - let code: ErrorCode = .featureNotSupported - result(FlutterError(code: code.rawValue, message: "External purchase link requires iOS 16.0+, macOS 14.0+, or tvOS 16.0+", details: nil)) + let code: ErrorCode = .developerError + result(FlutterError(code: code.rawValue, message: "url required", details: nil)) } - // MARK: - ExternalPurchaseCustomLink (iOS 18.1+) case "isEligibleForExternalPurchaseCustomLinkIOS": if #available(iOS 18.1, macOS 15.0, tvOS 18.1, *) { isEligibleForExternalPurchaseCustomLinkIOS(result: result) @@ -332,7 +230,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { getExternalPurchaseCustomLinkTokenIOS(tokenType: tokenType, result: result) } else { let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "tokenType required ('acquisition' or 'services')", details: nil)) + result(FlutterError(code: code.rawValue, message: "tokenType required", details: nil)) } } else { let code: ErrorCode = .featureNotSupported @@ -348,22 +246,13 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { showExternalPurchaseCustomLinkNoticeIOS(noticeType: noticeType, result: result) } else { let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "noticeType required ('browser')", details: nil)) + result(FlutterError(code: code.rawValue, message: "noticeType required", details: nil)) } } else { let code: ErrorCode = .featureNotSupported result(FlutterError(code: code.rawValue, message: "ExternalPurchaseCustomLink requires iOS 18.1+, macOS 15.0+, or tvOS 18.1+", details: nil)) } - case "verifyPurchaseWithProvider": - guard let args = call.arguments as? [String: Any], - let providerStr = args["provider"] as? String else { - let code: ErrorCode = .developerError - result(FlutterError(code: code.rawValue, message: "provider required", details: nil)) - return - } - verifyPurchaseWithProvider(args: args, provider: providerStr, result: result) - default: result(FlutterMethodNotImplemented) } @@ -431,13 +320,12 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } } - + if promotedProductToken == nil { promotedProductToken = OpenIapModule.shared.promotedProductListenerIOS { [weak self] productId in Task { @MainActor in guard let self = self else { return } FlutterIapLog.debug("promotedProductListenerIOS fired for: \(productId)") - // Emit event that Dart expects: name 'iap-promoted-product' with String payload self.channel?.invokeMethod("iap-promoted-product", arguments: productId) } } @@ -477,7 +365,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { self?.emitPurchaseUpdated(purchase, method: "purchase-updated") }, options: purchaseUpdatedListenerOptions) } - + private func removeOpenIapListeners() { if let token = purchaseUpdatedToken { OpenIapModule.shared.removeListener(token) } if let token = purchaseErrorToken { OpenIapModule.shared.removeListener(token) } @@ -678,28 +566,6 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } - private func beginRefundRequestIOS(sku: String, result: @escaping FlutterResult) { - FlutterIapLog.debug("beginRefundRequestIOS called for sku=\(sku)") - Task { @MainActor in - do { - let status = try await OpenIapModule.shared.beginRefundRequestIOS(sku: sku) - FlutterIapLog.result("beginRefundRequestIOS", value: status ?? "nil") - result(status) - } catch let purchaseError as PurchaseError { - FlutterIapLog.failure("beginRefundRequestIOS", error: purchaseError) - result(FlutterError( - code: purchaseError.code.rawValue, - message: purchaseError.message, - details: purchaseError.productId ?? sku - )) - } catch { - FlutterIapLog.failure("beginRefundRequestIOS", error: error) - let code: ErrorCode = .serviceError - result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) - } - } - } - @available(iOS 15.0, macOS 14.0, tvOS 15.0, *) private func showManageSubscriptionsIOS(result: @escaping FlutterResult) { FlutterIapLog.debug("showManageSubscriptionsIOS called") @@ -830,7 +696,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } } - + private func getAllTransactionsIOS(result: @escaping FlutterResult) { Task { @MainActor in do { @@ -847,7 +713,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } } - + private func clearTransactionIOS(result: @escaping FlutterResult) { FlutterIapLog.debug("clearTransactionIOS called") Task { @MainActor in @@ -921,7 +787,6 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { FlutterIapLog.debug("verifyPurchaseWithProvider called with provider: \(provider)") Task { @MainActor in do { - // Build props dictionary for OpenIAP var propsDict: [String: Any] = ["provider": provider] if let iapkit = args["iapkit"] as? [String: Any] { var iapkitDict: [String: Any] = [:] @@ -937,12 +802,10 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { propsDict["iapkit"] = iapkitDict } - // Use JSONSerialization + JSONDecoder let jsonData = try JSONSerialization.data(withJSONObject: propsDict) let props = try JSONDecoder().decode(VerifyPurchaseWithProviderProps.self, from: jsonData) let res = try await OpenIapModule.shared.verifyPurchaseWithProvider(props) - // Convert result to dictionary var payload: [String: Any] = [ "provider": res.provider.rawValue ] @@ -964,203 +827,9 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } - private func syncIOS(result: @escaping FlutterResult) { - FlutterIapLog.debug("syncIOS called") - Task { @MainActor in - do { - let success = try await OpenIapModule.shared.syncIOS() - FlutterIapLog.result("syncIOS", value: success) - result(success) - } catch let purchaseError as PurchaseError { - FlutterIapLog.failure("syncIOS", error: purchaseError) - result(FlutterError( - code: purchaseError.code.rawValue, - message: purchaseError.message, - details: purchaseError.productId - )) - } catch { - FlutterIapLog.failure("syncIOS", error: error) - let code: ErrorCode = .syncError - result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) - } - } - } - - private func subscriptionStatusIOS(sku: String, result: @escaping FlutterResult) { - FlutterIapLog.debug("subscriptionStatusIOS called for sku=\(sku)") - Task { @MainActor in - do { - let statuses = try await OpenIapModule.shared.subscriptionStatusIOS(sku: sku) - let payload = statuses.map { - FlutterIapHelper.sanitizeDictionary(OpenIapSerialization.encode($0)) - } - FlutterIapLog.result("subscriptionStatusIOS", value: payload) - result(payload) - } catch let purchaseError as PurchaseError { - FlutterIapLog.failure("subscriptionStatusIOS", error: purchaseError) - result(FlutterError( - code: purchaseError.code.rawValue, - message: purchaseError.message, - details: purchaseError.productId ?? sku - )) - } catch { - FlutterIapLog.failure("subscriptionStatusIOS", error: error) - let code: ErrorCode = .serviceError - result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) - } - } - } - - @available(iOS 16.0, macOS 14.0, tvOS 16.0, *) - private func getAppTransactionIOS(result: @escaping FlutterResult) { - FlutterIapLog.debug("getAppTransactionIOS called") - Task { @MainActor in - do { - if let tx = try await OpenIapModule.shared.getAppTransactionIOS() { - let payload = FlutterIapHelper.sanitizeDictionary(OpenIapSerialization.encode(tx)) - FlutterIapLog.result("getAppTransactionIOS", value: payload) - result(payload) - } else { - result(nil) - } - } catch let purchaseError as PurchaseError { - FlutterIapLog.failure("getAppTransactionIOS", error: purchaseError) - result(FlutterError( - code: purchaseError.code.rawValue, - message: purchaseError.message, - details: purchaseError.productId - )) - } catch { - FlutterIapLog.failure("getAppTransactionIOS", error: error) - let code: ErrorCode = .serviceError - result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) - } - } - } - - // MARK: - StoreKit 2 entitlement queries (iOS 15.0+) - - private func currentEntitlementIOS(sku: String, result: @escaping FlutterResult) { - FlutterIapLog.debug("currentEntitlementIOS called for sku=\(sku)") - Task { @MainActor in - do { - if let purchase = try await OpenIapModule.shared.currentEntitlementIOS(sku: sku) { - let payload = FlutterIapHelper.sanitizeDictionary(OpenIapSerialization.encode(purchase)) - FlutterIapLog.result("currentEntitlementIOS", value: payload) - result(payload) - } else { - result(nil) - } - } catch let purchaseError as PurchaseError { - FlutterIapLog.failure("currentEntitlementIOS", error: purchaseError) - result(FlutterError( - code: purchaseError.code.rawValue, - message: purchaseError.message, - details: purchaseError.productId ?? sku - )) - } catch { - FlutterIapLog.failure("currentEntitlementIOS", error: error) - let code: ErrorCode = .serviceError - result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) - } - } - } - - private func latestTransactionIOS(sku: String, result: @escaping FlutterResult) { - FlutterIapLog.debug("latestTransactionIOS called for sku=\(sku)") - Task { @MainActor in - do { - if let purchase = try await OpenIapModule.shared.latestTransactionIOS(sku: sku) { - let payload = FlutterIapHelper.sanitizeDictionary(OpenIapSerialization.encode(purchase)) - FlutterIapLog.result("latestTransactionIOS", value: payload) - result(payload) - } else { - result(nil) - } - } catch let purchaseError as PurchaseError { - FlutterIapLog.failure("latestTransactionIOS", error: purchaseError) - result(FlutterError( - code: purchaseError.code.rawValue, - message: purchaseError.message, - details: purchaseError.productId ?? sku - )) - } catch { - FlutterIapLog.failure("latestTransactionIOS", error: error) - let code: ErrorCode = .serviceError - result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) - } - } - } - - private func isTransactionVerifiedIOS(sku: String, result: @escaping FlutterResult) { - FlutterIapLog.debug("isTransactionVerifiedIOS called for sku=\(sku)") - Task { @MainActor in - do { - let verified = try await OpenIapModule.shared.isTransactionVerifiedIOS(sku: sku) - FlutterIapLog.result("isTransactionVerifiedIOS", value: verified) - result(verified) - } catch let purchaseError as PurchaseError { - FlutterIapLog.failure("isTransactionVerifiedIOS", error: purchaseError) - result(FlutterError( - code: purchaseError.code.rawValue, - message: purchaseError.message, - details: purchaseError.productId ?? sku - )) - } catch { - FlutterIapLog.failure("isTransactionVerifiedIOS", error: error) - let code: ErrorCode = .serviceError - result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) - } - } - } - - private func getTransactionJwsIOS(sku: String, result: @escaping FlutterResult) { - FlutterIapLog.debug("getTransactionJwsIOS called for sku=\(sku)") - Task { @MainActor in - do { - let jws = try await OpenIapModule.shared.getTransactionJwsIOS(sku: sku) - FlutterIapLog.result("getTransactionJwsIOS", value: jws == nil ? nil : "") - result(jws) - } catch let purchaseError as PurchaseError { - FlutterIapLog.failure("getTransactionJwsIOS", error: purchaseError) - result(FlutterError( - code: purchaseError.code.rawValue, - message: purchaseError.message, - details: purchaseError.productId ?? sku - )) - } catch { - FlutterIapLog.failure("getTransactionJwsIOS", error: error) - let code: ErrorCode = .serviceError - result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) - } - } - } - - private func getReceiptDataIOS(result: @escaping FlutterResult) { - FlutterIapLog.debug("getReceiptDataIOS called") - Task { @MainActor in - do { - let receipt = try await OpenIapModule.shared.getReceiptDataIOS() - FlutterIapLog.result("getReceiptDataIOS", value: receipt == nil ? nil : "") - result(receipt) - } catch let purchaseError as PurchaseError { - FlutterIapLog.failure("getReceiptDataIOS", error: purchaseError) - result(FlutterError( - code: purchaseError.code.rawValue, - message: purchaseError.message, - details: purchaseError.productId - )) - } catch { - FlutterIapLog.failure("getReceiptDataIOS", error: error) - let code: ErrorCode = .serviceError - result(FlutterError(code: code.rawValue, message: defaultMessage(for: code), details: error.localizedDescription)) - } - } - } - - // MARK: - External Purchase Notice (iOS 17.4+) + // MARK: - Alternative Billing (iOS 18.2+) - @available(iOS 17.4, macOS 14.4, tvOS 17.4, *) + @available(iOS 18.2, macOS 14.0, tvOS 18.2, *) private func canPresentExternalPurchaseNoticeIOS(result: @escaping FlutterResult) { FlutterIapLog.debug("canPresentExternalPurchaseNoticeIOS called") Task { @MainActor in @@ -1177,7 +846,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { } } - @available(iOS 17.4, macOS 14.4, tvOS 17.4, *) + @available(iOS 18.2, macOS 14.0, tvOS 18.2, *) private func presentExternalPurchaseNoticeSheetIOS(result: @escaping FlutterResult) { FlutterIapLog.debug("presentExternalPurchaseNoticeSheetIOS called") Task { @MainActor in @@ -1290,11 +959,7 @@ public class FlutterInappPurchasePlugin: NSObject, FlutterPlugin { public class FlutterInappPurchasePluginLegacy: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { if #unavailable(iOS 15.0, macOS 14.0, tvOS 15.0) { - #if canImport(FlutterMacOS) let channel = FlutterMethodChannel(name: "flutter_inapp", binaryMessenger: registrar.messenger) - #else - let channel = FlutterMethodChannel(name: "flutter_inapp", binaryMessenger: registrar.messenger()) - #endif let instance = FlutterInappPurchasePluginLegacy() registrar.addMethodCallDelegate(instance, channel: channel) } From 9d4d97e267e4fa6f43aa1a6a91da7aa1ba787fe1 Mon Sep 17 00:00:00 2001 From: alihassan143 Date: Tue, 19 May 2026 21:54:33 +0500 Subject: [PATCH 3/5] feat(flutter_inapp_purchase): add tvOS 15.0 platform to Package.swift --- libraries/flutter_inapp_purchase/Package.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/flutter_inapp_purchase/Package.swift b/libraries/flutter_inapp_purchase/Package.swift index c8ea4bbb..93e0ca05 100644 --- a/libraries/flutter_inapp_purchase/Package.swift +++ b/libraries/flutter_inapp_purchase/Package.swift @@ -7,6 +7,7 @@ let package = Package( platforms: [ .iOS("15.0"), .macOS("14.0"), + .tvOS("15.0"), ], products: [ .library(name: "flutter_inapp_purchase", targets: ["flutter_inapp_purchase"]), From 5c184a07d7fc39bffaf70d6a1b38a805658f0140 Mon Sep 17 00:00:00 2001 From: alihassan143 Date: Tue, 19 May 2026 21:55:30 +0500 Subject: [PATCH 4/5] revert: remove tvOS platform, keep only iOS and macOS --- libraries/flutter_inapp_purchase/Package.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/flutter_inapp_purchase/Package.swift b/libraries/flutter_inapp_purchase/Package.swift index 93e0ca05..c8ea4bbb 100644 --- a/libraries/flutter_inapp_purchase/Package.swift +++ b/libraries/flutter_inapp_purchase/Package.swift @@ -7,7 +7,6 @@ let package = Package( platforms: [ .iOS("15.0"), .macOS("14.0"), - .tvOS("15.0"), ], products: [ .library(name: "flutter_inapp_purchase", targets: ["flutter_inapp_purchase"]), From aaf5b612876011fe9098520f17345c0495fa6d13 Mon Sep 17 00:00:00 2001 From: alihassan143 Date: Tue, 2 Jun 2026 22:04:39 +0500 Subject: [PATCH 5/5] feat(flutter): add SPM support for iOS and macOS Restructure iOS and macOS Swift sources into SPM-compatible layout under flutter_inapp_purchase/Sources/flutter_inapp_purchase/. Add Package.swift manifests for both platforms, update podspecs to point to the new source paths, and wire up Xcode projects in the example app to use FlutterGeneratedPluginSwiftPackage. Fix missing env asset that blocked macOS and iOS example builds. --- .../flutter_inapp_purchase/Package.swift | 11 ++--- .../flutter_inapp_purchase/example/.gitignore | 3 ++ .../ios/Runner.xcodeproj/project.pbxproj | 30 +++++++++++- .../xcshareddata/xcschemes/Runner.xcscheme | 18 ++++++++ .../example/ios/Runner/AppDelegate.h | 2 +- .../example/ios/Runner/AppDelegate.m | 10 ++-- .../example/ios/Runner/Info.plist | 21 +++++++++ .../macos/Runner.xcodeproj/project.pbxproj | 46 +++++++++++-------- .../xcshareddata/xcschemes/Runner.xcscheme | 18 ++++++++ .../ios/Assets/.gitkeep | 0 .../ios/flutter_inapp_purchase.podspec | 2 +- .../ios/flutter_inapp_purchase/Package.swift | 27 +++++++++++ .../FlutterIapHelper.swift | 0 .../FlutterIapLog.swift | 0 .../FlutterInappPurchasePlugin.swift | 0 .../macos/flutter_inapp_purchase.podspec | 2 +- .../flutter_inapp_purchase/Package.swift | 27 +++++++++++ .../FlutterIapHelper.swift | 0 .../FlutterIapLog.swift | 0 .../FlutterInappPurchasePlugin.swift | 0 20 files changed, 184 insertions(+), 33 deletions(-) delete mode 100644 libraries/flutter_inapp_purchase/ios/Assets/.gitkeep create mode 100644 libraries/flutter_inapp_purchase/ios/flutter_inapp_purchase/Package.swift rename libraries/flutter_inapp_purchase/ios/{Classes => flutter_inapp_purchase/Sources/flutter_inapp_purchase}/FlutterIapHelper.swift (100%) rename libraries/flutter_inapp_purchase/ios/{Classes => flutter_inapp_purchase/Sources/flutter_inapp_purchase}/FlutterIapLog.swift (100%) rename libraries/flutter_inapp_purchase/ios/{Classes => flutter_inapp_purchase/Sources/flutter_inapp_purchase}/FlutterInappPurchasePlugin.swift (100%) create mode 100644 libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase/Package.swift rename libraries/flutter_inapp_purchase/macos/{Classes => flutter_inapp_purchase/Sources/flutter_inapp_purchase}/FlutterIapHelper.swift (100%) rename libraries/flutter_inapp_purchase/macos/{Classes => flutter_inapp_purchase/Sources/flutter_inapp_purchase}/FlutterIapLog.swift (100%) rename libraries/flutter_inapp_purchase/macos/{Classes => flutter_inapp_purchase/Sources/flutter_inapp_purchase}/FlutterInappPurchasePlugin.swift (100%) diff --git a/libraries/flutter_inapp_purchase/Package.swift b/libraries/flutter_inapp_purchase/Package.swift index c8ea4bbb..1083fba8 100644 --- a/libraries/flutter_inapp_purchase/Package.swift +++ b/libraries/flutter_inapp_purchase/Package.swift @@ -9,13 +9,10 @@ let package = Package( .macOS("14.0"), ], products: [ - .library(name: "flutter_inapp_purchase", targets: ["flutter_inapp_purchase"]), + .library(name: "flutter-inapp-purchase", targets: ["flutter_inapp_purchase"]) ], dependencies: [ - .package( - url: "https://github.com/hyodotdev/openiap.git", - exact: "2.2.1" - ), + .package(url: "https://github.com/hyodotdev/openiap.git", from: "2.2.1"), ], targets: [ .target( @@ -23,7 +20,7 @@ let package = Package( dependencies: [ .product(name: "OpenIAP", package: "openiap"), ], - path: "ios/Classes" - ), + path: "ios/flutter_inapp_purchase/Sources/flutter_inapp_purchase" + ) ] ) diff --git a/libraries/flutter_inapp_purchase/example/.gitignore b/libraries/flutter_inapp_purchase/example/.gitignore index dee655cc..3dc94599 100644 --- a/libraries/flutter_inapp_purchase/example/.gitignore +++ b/libraries/flutter_inapp_purchase/example/.gitignore @@ -7,3 +7,6 @@ build/ .flutter-plugins + +# Local env file with API keys - copy from env.example and fill in values +env diff --git a/libraries/flutter_inapp_purchase/example/ios/Runner.xcodeproj/project.pbxproj b/libraries/flutter_inapp_purchase/example/ios/Runner.xcodeproj/project.pbxproj index 21541b12..55a7267e 100644 --- a/libraries/flutter_inapp_purchase/example/ios/Runner.xcodeproj/project.pbxproj +++ b/libraries/flutter_inapp_purchase/example/ios/Runner.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 2D5378271FAD1A9400D5DBA9 /* StoreKit.storekit in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAD1A9400D5DBA9 /* StoreKit.storekit */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3CCED4E62E30A89200CE4F79 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CCED4E52E30A89200CE4F79 /* StoreKit.framework */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; @@ -42,6 +43,9 @@ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3CCED4E52E30A89200CE4F79 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; 49A6FFBAD3488E7D435E2D63 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 784666492D4C4C64000A1A5F /* FlutterFramework */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterFramework; path = Flutter/ephemeral/Packages/.packages/FlutterFramework; sourceTree = ""; }; + 78DABEA22ED26510000E7860 /* flutter_inapp_purchase */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = flutter_inapp_purchase; path = ../../ios/flutter_inapp_purchase; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; @@ -62,6 +66,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, 3CCED4E62E30A89200CE4F79 /* StoreKit.framework in Frameworks */, 079B74431F6B5F836BD33DBC /* Pods_Runner.framework in Frameworks */, ); @@ -82,6 +87,9 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78DABEA22ED26510000E7860 /* flutter_inapp_purchase */, + 784666492D4C4C64000A1A5F /* FlutterFramework */, + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -165,6 +173,9 @@ dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -198,6 +209,9 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -248,12 +262,10 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/flutter_inapp_purchase/flutter_inapp_purchase.framework", "${BUILT_PRODUCTS_DIR}/openiap/OpenIAP.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inapp_purchase.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenIAP.framework", ); runOnlyForDeploymentPostprocessing = 0; @@ -511,6 +523,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } diff --git a/libraries/flutter_inapp_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/libraries/flutter_inapp_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 1a629b63..3f2248af 100644 --- a/libraries/flutter_inapp_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/libraries/flutter_inapp_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + #import -@interface AppDelegate : FlutterAppDelegate +@interface AppDelegate : FlutterAppDelegate @end diff --git a/libraries/flutter_inapp_purchase/example/ios/Runner/AppDelegate.m b/libraries/flutter_inapp_purchase/example/ios/Runner/AppDelegate.m index 59a72e90..64973b98 100644 --- a/libraries/flutter_inapp_purchase/example/ios/Runner/AppDelegate.m +++ b/libraries/flutter_inapp_purchase/example/ios/Runner/AppDelegate.m @@ -5,9 +5,13 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - [GeneratedPluginRegistrant registerWithRegistry:self]; + // Override point for customization after application launch. - return [super application:application didFinishLaunchingWithOptions:launchOptions]; + return [super application:application + didFinishLaunchingWithOptions:launchOptions]; +} +- (void)didInitializeImplicitFlutterEngine: + (NSObject *)engineBridge { + [GeneratedPluginRegistrant registerWithRegistry:engineBridge.pluginRegistry]; } - @end diff --git a/libraries/flutter_inapp_purchase/example/ios/Runner/Info.plist b/libraries/flutter_inapp_purchase/example/ios/Runner/Info.plist index 4d62b3f9..40fb0311 100644 --- a/libraries/flutter_inapp_purchase/example/ios/Runner/Info.plist +++ b/libraries/flutter_inapp_purchase/example/ios/Runner/Info.plist @@ -52,5 +52,26 @@ cstr6suwn9.skadnetwork + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneDelegateClassName + FlutterSceneDelegate + UISceneConfigurationName + flutter + UISceneStoryboardFile + Main + + + + diff --git a/libraries/flutter_inapp_purchase/example/macos/Runner.xcodeproj/project.pbxproj b/libraries/flutter_inapp_purchase/example/macos/Runner.xcodeproj/project.pbxproj index 6e9e9479..5e1ce7fa 100644 --- a/libraries/flutter_inapp_purchase/example/macos/Runner.xcodeproj/project.pbxproj +++ b/libraries/flutter_inapp_purchase/example/macos/Runner.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; D0626713F80DD2BD49E91E5F /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5637C7071BCB7780E65D7EB /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ @@ -78,6 +79,9 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 784666492D4C4C64000A1A5F /* FlutterFramework */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterFramework; path = ephemeral/Packages/.packages/FlutterFramework; sourceTree = ""; }; + 78DABEA22ED26510000E7860 /* flutter_inapp_purchase */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = flutter_inapp_purchase; path = ../../../macos/flutter_inapp_purchase; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 8464B893525EE848211C4C1B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; @@ -103,6 +107,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, 157D99104874B164A5EC7598 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -178,6 +183,9 @@ 33CEB47122A05771004F2AC0 /* Flutter */ = { isa = PBXGroup; children = ( + 78DABEA22ED26510000E7860 /* flutter_inapp_purchase */, + 784666492D4C4C64000A1A5F /* FlutterFramework */, + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, @@ -240,7 +248,6 @@ 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - 45BEBE97C1FC6AE6D9522D26 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -248,6 +255,9 @@ 33CC11202044C79F0003C045 /* PBXTargetDependency */, ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 33CC10ED2044A3C60003C045 /* flutter_inapp_purchase_example.app */; productType = "com.apple.product-type.application"; @@ -292,6 +302,9 @@ Base, ); mainGroup = 33CC10E42044A3C60003C045; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -384,23 +397,6 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; - 45BEBE97C1FC6AE6D9522D26 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 49A51C8CD36F5E5A826ADFB4 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -797,6 +793,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 33CC10E52044A3C60003C045 /* Project object */; } diff --git a/libraries/flutter_inapp_purchase/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/libraries/flutter_inapp_purchase/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 4dfe7012..0b7220ce 100644 --- a/libraries/flutter_inapp_purchase/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/libraries/flutter_inapp_purchase/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + '../LICENSE' } s.author = { 'Hyo Dev' => 'hyo@hyo.dev' } s.source = { :path => '.' } - s.source_files = 'Classes/**/*.swift' + s.source_files = 'flutter_inapp_purchase/Sources/flutter_inapp_purchase/**/*.swift' s.dependency 'Flutter' # Use OpenIAP Apple native module (via CocoaPods) s.dependency 'openiap', openiap_versions['apple'] diff --git a/libraries/flutter_inapp_purchase/ios/flutter_inapp_purchase/Package.swift b/libraries/flutter_inapp_purchase/ios/flutter_inapp_purchase/Package.swift new file mode 100644 index 00000000..9ec6af7e --- /dev/null +++ b/libraries/flutter_inapp_purchase/ios/flutter_inapp_purchase/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version: 5.9 + +import PackageDescription + +let package = Package( + name: "flutter_inapp_purchase", + platforms: [ + .iOS("15.0"), + ], + products: [ + .library(name: "flutter-inapp-purchase", targets: ["flutter_inapp_purchase"]) + ], + dependencies: [ + .package(name: "FlutterFramework", path: "../FlutterFramework"), + .package(url: "https://github.com/hyodotdev/openiap.git", from: "2.2.1"), + ], + targets: [ + .target( + name: "flutter_inapp_purchase", + dependencies: [ + .product(name: "FlutterFramework", package: "FlutterFramework"), + .product(name: "OpenIAP", package: "openiap"), + ], + path: "Sources/flutter_inapp_purchase" + ) + ] +) diff --git a/libraries/flutter_inapp_purchase/ios/Classes/FlutterIapHelper.swift b/libraries/flutter_inapp_purchase/ios/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterIapHelper.swift similarity index 100% rename from libraries/flutter_inapp_purchase/ios/Classes/FlutterIapHelper.swift rename to libraries/flutter_inapp_purchase/ios/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterIapHelper.swift diff --git a/libraries/flutter_inapp_purchase/ios/Classes/FlutterIapLog.swift b/libraries/flutter_inapp_purchase/ios/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterIapLog.swift similarity index 100% rename from libraries/flutter_inapp_purchase/ios/Classes/FlutterIapLog.swift rename to libraries/flutter_inapp_purchase/ios/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterIapLog.swift diff --git a/libraries/flutter_inapp_purchase/ios/Classes/FlutterInappPurchasePlugin.swift b/libraries/flutter_inapp_purchase/ios/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterInappPurchasePlugin.swift similarity index 100% rename from libraries/flutter_inapp_purchase/ios/Classes/FlutterInappPurchasePlugin.swift rename to libraries/flutter_inapp_purchase/ios/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterInappPurchasePlugin.swift diff --git a/libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase.podspec b/libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase.podspec index 9c8ab76e..5523fecc 100644 --- a/libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase.podspec +++ b/libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase.podspec @@ -22,7 +22,7 @@ In App Purchase plugin for flutter. This project has been forked by react-native s.license = { :file => '../LICENSE' } s.author = { 'Hyo Dev' => 'hyo@hyo.dev' } s.source = { :path => '.' } - s.source_files = 'Classes/**/*.swift' + s.source_files = 'flutter_inapp_purchase/Sources/flutter_inapp_purchase/**/*.swift' s.dependency 'FlutterMacOS' # Use OpenIAP Apple native module (via CocoaPods) s.dependency 'openiap', openiap_versions['apple'] diff --git a/libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase/Package.swift b/libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase/Package.swift new file mode 100644 index 00000000..87985b96 --- /dev/null +++ b/libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version: 5.9 + +import PackageDescription + +let package = Package( + name: "flutter_inapp_purchase", + platforms: [ + .macOS("14.0"), + ], + products: [ + .library(name: "flutter-inapp-purchase", targets: ["flutter_inapp_purchase"]) + ], + dependencies: [ + .package(name: "FlutterFramework", path: "../FlutterFramework"), + .package(url: "https://github.com/hyodotdev/openiap.git", from: "2.2.1"), + ], + targets: [ + .target( + name: "flutter_inapp_purchase", + dependencies: [ + .product(name: "FlutterFramework", package: "FlutterFramework"), + .product(name: "OpenIAP", package: "openiap"), + ], + path: "Sources/flutter_inapp_purchase" + ) + ] +) diff --git a/libraries/flutter_inapp_purchase/macos/Classes/FlutterIapHelper.swift b/libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterIapHelper.swift similarity index 100% rename from libraries/flutter_inapp_purchase/macos/Classes/FlutterIapHelper.swift rename to libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterIapHelper.swift diff --git a/libraries/flutter_inapp_purchase/macos/Classes/FlutterIapLog.swift b/libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterIapLog.swift similarity index 100% rename from libraries/flutter_inapp_purchase/macos/Classes/FlutterIapLog.swift rename to libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterIapLog.swift diff --git a/libraries/flutter_inapp_purchase/macos/Classes/FlutterInappPurchasePlugin.swift b/libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterInappPurchasePlugin.swift similarity index 100% rename from libraries/flutter_inapp_purchase/macos/Classes/FlutterInappPurchasePlugin.swift rename to libraries/flutter_inapp_purchase/macos/flutter_inapp_purchase/Sources/flutter_inapp_purchase/FlutterInappPurchasePlugin.swift