[in_app_purchase_storekit] Remove OCMock (#6862)
Fixes https://github.com/flutter/flutter/issues/149849
Also fixes the broken symlinking between test files.
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] page, which explains my
responsibilities.
- [x] I read and followed the [relevant style guides] and ran the
auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages
repo does use `dart format`.)
- [x] I signed the [CLA].
- [x] The title of the PR starts with the name of the package surrounded
by square brackets, e.g. `[shared_preferences]`
- [x] I [linked to at least one issue that this PR fixes] in the
description above.
- [x] I updated `pubspec.yaml` with an appropriate new version according
to the [pub versioning philosophy], or this PR is [exempt from version
changes].
- [x] I updated `CHANGELOG.md` to add a description of the change,
[following repository CHANGELOG style], or this PR is [exempt from
CHANGELOG changes].
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] All existing and new tests are passing.
If you need help, consider asking for advice on the #hackers-new channel
on [Discord].
<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/packages/blob/main/CONTRIBUTING.md
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md
[relevant style guides]:
https://github.com/flutter/packages/blob/main/CONTRIBUTING.md#style
[CLA]: https://cla.developers.google.com/
[Discord]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Chat.md
[linked to at least one issue that this PR fixes]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#overview
[pub versioning philosophy]: https://dart.dev/tools/pub/versioning
[exempt from version changes]:
https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#version
[following repository CHANGELOG style]:
https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changelog-style
[exempt from CHANGELOG changes]:
https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changelog
[test-exempt]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#tests
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md
index 070f075..18072ee 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md
+++ b/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md
@@ -1,6 +1,10 @@
+## 0.3.17
+
+* Removes OCMock from tests.
+
## 0.3.16
-* Converts main plugin class to Swift
+* Converts main plugin class to Swift.
## 0.3.15
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPPaymentQueueDelegate.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPPaymentQueueDelegate.h
index 4347846..12ef96b 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPPaymentQueueDelegate.h
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPPaymentQueueDelegate.h
@@ -9,13 +9,14 @@
#endif
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
+#import "FLTMethodChannelProtocol.h"
NS_ASSUME_NONNULL_BEGIN
API_AVAILABLE(ios(13))
API_UNAVAILABLE(tvos, macos, watchos)
@interface FIAPPaymentQueueDelegate : NSObject <SKPaymentQueueDelegate>
-- (id)initWithMethodChannel:(FlutterMethodChannel *)methodChannel;
+- (id)initWithMethodChannel:(id<FLTMethodChannelProtocol>)methodChannel;
@end
NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPPaymentQueueDelegate.m b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPPaymentQueueDelegate.m
index cb18d9b..d0efb06 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPPaymentQueueDelegate.m
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPPaymentQueueDelegate.m
@@ -7,13 +7,14 @@
@interface FIAPPaymentQueueDelegate ()
-@property(strong, nonatomic, readonly) FlutterMethodChannel *callbackChannel;
+// The designated Flutter method channel that handles if a transaction should be continued
+@property(nonatomic, strong, readonly) id<FLTMethodChannelProtocol> callbackChannel;
@end
@implementation FIAPPaymentQueueDelegate
-- (id)initWithMethodChannel:(FlutterMethodChannel *)methodChannel {
+- (id)initWithMethodChannel:(id<FLTMethodChannelProtocol>)methodChannel {
self = [super init];
if (self) {
_callbackChannel = methodChannel;
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPReceiptManager.m
index 22a3973..503eb0f 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPReceiptManager.m
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPReceiptManager.m
@@ -14,13 +14,15 @@
// Gets the receipt file data from the location of the url. Can be nil if
// there is an error. This interface is defined so it can be stubbed for testing.
- (NSData *)getReceiptData:(NSURL *)url error:(NSError **)error;
-
+// Gets the app store receipt url. Can be nil if
+// there is an error. This property is defined so it can be stubbed for testing.
+@property(nonatomic, readonly) NSURL *receiptURL;
@end
@implementation FIAPReceiptManager
- (NSString *)retrieveReceiptWithError:(FlutterError **)flutterError {
- NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
+ NSURL *receiptURL = self.receiptURL;
if (!receiptURL) {
return nil;
}
@@ -43,4 +45,8 @@
return [NSData dataWithContentsOfURL:url options:NSDataReadingMappedIfSafe error:error];
}
+- (NSURL *)receiptURL {
+ return [[NSBundle mainBundle] appStoreReceiptURL];
+}
+
@end
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPRequestHandler.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPRequestHandler.h
index cbf21d6..ea6e2b7 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPRequestHandler.h
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPRequestHandler.h
@@ -2,19 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#import <FLTRequestHandlerProtocol.h>
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
NS_ASSUME_NONNULL_BEGIN
-typedef void (^ProductRequestCompletion)(SKProductsResponse *_Nullable response,
- NSError *_Nullable errror);
-
-@interface FIAPRequestHandler : NSObject
+@interface FIAPRequestHandler : NSObject <FLTRequestHandlerProtocol>
- (instancetype)initWithRequest:(SKRequest *)request;
- (void)startProductRequestWithCompletionHandler:(ProductRequestCompletion)completion;
@end
+// The default request handler that wraps FIAPRequestHandler
+@interface DefaultRequestHandler : NSObject <FLTRequestHandlerProtocol>
+
+// Initialize this wrapper with an instance of FIAPRequestHandler
+- (instancetype)initWithRequestHandler:(FIAPRequestHandler *)handler;
+@end
NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPRequestHandler.m b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPRequestHandler.m
index 8767265..d2ef682 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPRequestHandler.m
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPRequestHandler.m
@@ -9,8 +9,8 @@
@interface FIAPRequestHandler () <SKProductsRequestDelegate>
-@property(copy, nonatomic) ProductRequestCompletion completion;
-@property(strong, nonatomic) SKRequest *request;
+@property(nonatomic, copy) ProductRequestCompletion completion;
+@property(nonatomic, strong) SKRequest *request;
@end
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPaymentQueueHandler.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPaymentQueueHandler.h
index 356940c..68ddcaa 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPaymentQueueHandler.h
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPaymentQueueHandler.h
@@ -5,130 +5,16 @@
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
#import "FIATransactionCache.h"
+#import "FLTPaymentQueueHandlerProtocol.h"
+#import "FLTPaymentQueueProtocol.h"
+#import "FLTTransactionCacheProtocol.h"
@class SKPaymentTransaction;
NS_ASSUME_NONNULL_BEGIN
-typedef void (^TransactionsUpdated)(NSArray<SKPaymentTransaction *> *transactions);
-typedef void (^TransactionsRemoved)(NSArray<SKPaymentTransaction *> *transactions);
-typedef void (^RestoreTransactionFailed)(NSError *error);
-typedef void (^RestoreCompletedTransactionsFinished)(void);
-typedef BOOL (^ShouldAddStorePayment)(SKPayment *payment, SKProduct *product);
-typedef void (^UpdatedDownloads)(NSArray<SKDownload *> *downloads);
-
-@interface FIAPaymentQueueHandler : NSObject <SKPaymentTransactionObserver>
-
-@property(NS_NONATOMIC_IOSONLY, weak, nullable) id<SKPaymentQueueDelegate> delegate API_AVAILABLE(
- ios(13.0), macos(10.15), watchos(6.2));
-@property(nonatomic, readonly, nullable)
- SKStorefront *storefront API_AVAILABLE(ios(13.0), macos(10.15), watchos(6.2));
-
-/// Creates a new FIAPaymentQueueHandler initialized with an empty
-/// FIATransactionCache.
-///
-/// @param queue The SKPaymentQueue instance connected to the App Store and
-/// responsible for processing transactions.
-/// @param transactionsUpdated Callback method that is called each time the App
-/// Store indicates transactions are updated.
-/// @param transactionsRemoved Callback method that is called each time the App
-/// Store indicates transactions are removed.
-/// @param restoreTransactionFailed Callback method that is called each time
-/// the App Store indicates transactions failed
-/// to restore.
-/// @param restoreCompletedTransactionsFinished Callback method that is called
-/// each time the App Store
-/// indicates restoring of
-/// transactions has finished.
-/// @param shouldAddStorePayment Callback method that is called each time an
-/// in-app purchase has been initiated from the
-/// App Store.
-/// @param updatedDownloads Callback method that is called each time the App
-/// Store indicates downloads are updated.
-- (instancetype)initWithQueue:(nonnull SKPaymentQueue *)queue
- transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated
- transactionRemoved:(nullable TransactionsRemoved)transactionsRemoved
- restoreTransactionFailed:(nullable RestoreTransactionFailed)restoreTransactionFailed
- restoreCompletedTransactionsFinished:
- (nullable RestoreCompletedTransactionsFinished)restoreCompletedTransactionsFinished
- shouldAddStorePayment:(nullable ShouldAddStorePayment)shouldAddStorePayment
- updatedDownloads:(nullable UpdatedDownloads)updatedDownloads
- DEPRECATED_MSG_ATTRIBUTE(
- "Use the "
- "'initWithQueue:transactionsUpdated:transactionsRemoved:restoreTransactionsFinished:"
- "shouldAddStorePayment:updatedDownloads:transactionCache:' message instead.");
-
-/// Creates a new FIAPaymentQueueHandler.
-///
-/// The "transactionsUpdated", "transactionsRemoved" and "updatedDownloads"
-/// callbacks are only called while actively observing transactions. To start
-/// observing transactions send the "startObservingPaymentQueue" message.
-/// Sending the "stopObservingPaymentQueue" message will stop actively
-/// observing transactions. When transactions are not observed they are cached
-/// to the "transactionCache" and will be delivered via the
-/// "transactionsUpdated", "transactionsRemoved" and "updatedDownloads"
-/// callbacks as soon as the "startObservingPaymentQueue" message arrives.
-///
-/// Note: cached transactions that are not processed when the application is
-/// killed will be delivered again by the App Store as soon as the application
-/// starts again.
-///
-/// @param queue The SKPaymentQueue instance connected to the App Store and
-/// responsible for processing transactions.
-/// @param transactionsUpdated Callback method that is called each time the App
-/// Store indicates transactions are updated.
-/// @param transactionsRemoved Callback method that is called each time the App
-/// Store indicates transactions are removed.
-/// @param restoreTransactionFailed Callback method that is called each time
-/// the App Store indicates transactions failed
-/// to restore.
-/// @param restoreCompletedTransactionsFinished Callback method that is called
-/// each time the App Store
-/// indicates restoring of
-/// transactions has finished.
-/// @param shouldAddStorePayment Callback method that is called each time an
-/// in-app purchase has been initiated from the
-/// App Store.
-/// @param updatedDownloads Callback method that is called each time the App
-/// Store indicates downloads are updated.
-/// @param transactionCache An empty [FIATransactionCache] instance that is
-/// responsible for keeping track of transactions that
-/// arrive when not actively observing transactions.
-- (instancetype)initWithQueue:(nonnull SKPaymentQueue *)queue
- transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated
- transactionRemoved:(nullable TransactionsRemoved)transactionsRemoved
- restoreTransactionFailed:(nullable RestoreTransactionFailed)restoreTransactionFailed
- restoreCompletedTransactionsFinished:
- (nullable RestoreCompletedTransactionsFinished)restoreCompletedTransactionsFinished
- shouldAddStorePayment:(nullable ShouldAddStorePayment)shouldAddStorePayment
- updatedDownloads:(nullable UpdatedDownloads)updatedDownloads
- transactionCache:(nonnull FIATransactionCache *)transactionCache;
-// Can throw exceptions if the transaction type is purchasing, should always used in a @try block.
-- (void)finishTransaction:(nonnull SKPaymentTransaction *)transaction;
-- (void)restoreTransactions:(nullable NSString *)applicationName;
-- (void)presentCodeRedemptionSheet API_UNAVAILABLE(tvos, macos, watchos);
-- (NSArray<SKPaymentTransaction *> *)getUnfinishedTransactions;
-
-// This method needs to be called before any other methods.
-- (void)startObservingPaymentQueue;
-// Call this method when the Flutter app is no longer listening
-- (void)stopObservingPaymentQueue;
-
-// Appends a payment to the SKPaymentQueue.
-//
-// @param payment Payment object to be added to the payment queue.
-// @return whether "addPayment" was successful.
-- (BOOL)addPayment:(SKPayment *)payment;
-
-// Displays the price consent sheet.
-//
-// The price consent sheet is only displayed when the following
-// is true:
-// - You have increased the price of the subscription in App Store Connect.
-// - The subscriber has not yet responded to a price consent query.
-// Otherwise the method has no effect.
-- (void)showPriceConsentIfNeeded API_AVAILABLE(ios(13.4))API_UNAVAILABLE(tvos, macos, watchos);
-
+@interface FIAPaymentQueueHandler
+ : NSObject <SKPaymentTransactionObserver, FLTPaymentQueueHandlerProtocol>
@end
NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPaymentQueueHandler.m b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPaymentQueueHandler.m
index 6005657..e221ce0 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPaymentQueueHandler.m
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPaymentQueueHandler.m
@@ -10,34 +10,34 @@
/// The SKPaymentQueue instance connected to the App Store and responsible for processing
/// transactions.
-@property(strong, nonatomic) SKPaymentQueue *queue;
+@property(nonatomic, strong) SKPaymentQueue *queue;
/// Callback method that is called each time the App Store indicates transactions are updated.
-@property(nullable, copy, nonatomic) TransactionsUpdated transactionsUpdated;
+@property(nonatomic, nullable, copy) TransactionsUpdated transactionsUpdated;
/// Callback method that is called each time the App Store indicates transactions are removed.
-@property(nullable, copy, nonatomic) TransactionsRemoved transactionsRemoved;
+@property(nonatomic, nullable, copy) TransactionsRemoved transactionsRemoved;
/// Callback method that is called each time the App Store indicates transactions failed to restore.
-@property(nullable, copy, nonatomic) RestoreTransactionFailed restoreTransactionFailed;
+@property(nonatomic, nullable, copy) RestoreTransactionFailed restoreTransactionFailed;
/// Callback method that is called each time the App Store indicates restoring of transactions has
/// finished.
-@property(nullable, copy, nonatomic)
+@property(nonatomic, nullable, copy)
RestoreCompletedTransactionsFinished paymentQueueRestoreCompletedTransactionsFinished;
/// Callback method that is called each time an in-app purchase has been initiated from the App
/// Store.
-@property(nullable, copy, nonatomic) ShouldAddStorePayment shouldAddStorePayment;
+@property(nonatomic, nullable, copy) ShouldAddStorePayment shouldAddStorePayment;
/// Callback method that is called each time the App Store indicates downloads are updated.
-@property(nullable, copy, nonatomic) UpdatedDownloads updatedDownloads;
+@property(nonatomic, nullable, copy) UpdatedDownloads updatedDownloads;
/// The transaction cache responsible for caching transactions.
///
/// Keeps track of transactions that arrive when the Flutter client is not
/// actively observing for transactions.
-@property(strong, nonatomic, nonnull) FIATransactionCache *transactionCache;
+@property(nonatomic, strong, nonnull) FIATransactionCache *transactionCache;
/// Indicates if the Flutter client is observing transactions.
///
@@ -51,7 +51,9 @@
@implementation FIAPaymentQueueHandler
-- (instancetype)initWithQueue:(nonnull SKPaymentQueue *)queue
+@synthesize delegate;
+
+- (instancetype)initWithQueue:(nonnull id<FLTPaymentQueueProtocol>)queue
transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated
transactionRemoved:(nullable TransactionsRemoved)transactionsRemoved
restoreTransactionFailed:(nullable RestoreTransactionFailed)restoreTransactionFailed
@@ -66,10 +68,10 @@
restoreCompletedTransactionsFinished:restoreCompletedTransactionsFinished
shouldAddStorePayment:shouldAddStorePayment
updatedDownloads:updatedDownloads
- transactionCache:[[FIATransactionCache alloc] init]];
+ transactionCache:[[DefaultTransactionCache alloc] init]];
}
-- (instancetype)initWithQueue:(nonnull SKPaymentQueue *)queue
+- (instancetype)initWithQueue:(nonnull id<FLTPaymentQueueProtocol>)queue
transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated
transactionRemoved:(nullable TransactionsRemoved)transactionsRemoved
restoreTransactionFailed:(nullable RestoreTransactionFailed)restoreTransactionFailed
@@ -77,7 +79,7 @@
(nullable RestoreCompletedTransactionsFinished)restoreCompletedTransactionsFinished
shouldAddStorePayment:(nullable ShouldAddStorePayment)shouldAddStorePayment
updatedDownloads:(nullable UpdatedDownloads)updatedDownloads
- transactionCache:(nonnull FIATransactionCache *)transactionCache {
+ transactionCache:(nonnull id<FLTTransactionCacheProtocol>)transactionCache {
self = [super init];
if (self) {
_queue = queue;
@@ -170,7 +172,7 @@
#endif
#if TARGET_OS_IOS
-- (void)showPriceConsentIfNeeded {
+- (void)showPriceConsentIfNeeded API_AVAILABLE(ios(13.4)) {
[self.queue showPriceConsentIfNeeded];
}
#endif
@@ -233,7 +235,7 @@
return self.queue.transactions;
}
-- (SKStorefront *)storefront {
+- (SKStorefront *)storefront API_AVAILABLE(ios(13.0)) {
return self.queue.storefront;
}
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/InAppPurchasePlugin.swift b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/InAppPurchasePlugin.swift
index 511fc26..4ebd882 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/InAppPurchasePlugin.swift
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/InAppPurchasePlugin.swift
@@ -18,17 +18,19 @@
// note - the type should be FIAPPaymentQueueDelegate, but this is only available >= iOS 13,
// FIAPPaymentQueueDelegate only gets set/used in registerPaymentQueueDelegateWithError or removePaymentQueueDelegateWithError, which both are ios13+ only
private var paymentQueueDelegate: Any?
- private var requestHandlers = Set<FIAPRequestHandler>()
- private var handlerFactory: ((SKRequest) -> FIAPRequestHandler)
+ // Swift sets do not accept protocols, only concrete implementations
+ // TODO(louisehsu): Change it back to a set when removing obj-c dependancies from this file via type erasure
+ private var requestHandlers = NSHashTable<FLTRequestHandlerProtocol>()
+ private var handlerFactory: ((SKRequest) -> FLTRequestHandlerProtocol)
// TODO(louisehsu): Once tests are migrated to swift, we can use @testable import, and make theses vars private again and remove all instances of @objc
@objc
public var registrar: FlutterPluginRegistrar?
// This property is optional, as it requires self to exist to be initialized.
@objc
- public var paymentQueueHandler: FIAPaymentQueueHandler?
+ public var paymentQueueHandler: FLTPaymentQueueHandlerProtocol?
// This property is optional, as it needs to be set during plugin registration, and can't be directly initialized.
@objc
- public var transactionObserverCallbackChannel: FlutterMethodChannel?
+ public var transactionObserverCallbackChannel: FLTMethodChannelProtocol?
public static func register(with registrar: FlutterPluginRegistrar) {
#if os(iOS)
@@ -50,8 +52,8 @@
// This init is used for tests
public init(
receiptManager: FIAPReceiptManager,
- handlerFactory: @escaping (SKRequest) -> FIAPRequestHandler = {
- FIAPRequestHandler(request: $0)
+ handlerFactory: @escaping (SKRequest) -> FLTRequestHandlerProtocol = {
+ DefaultRequestHandler(requestHandler: FIAPRequestHandler(request: $0))
}
) {
self.receiptManager = receiptManager
@@ -65,7 +67,7 @@
self.registrar = registrar
self.paymentQueueHandler = FIAPaymentQueueHandler(
- queue: SKPaymentQueue.default(),
+ queue: DefaultPaymentQueue(queue: SKPaymentQueue.default()),
transactionsUpdated: { [weak self] transactions in
self?.handleTransactionsUpdated(transactions)
},
@@ -84,15 +86,18 @@
updatedDownloads: { [weak self] _ in
self?.updatedDownloads()
},
- transactionCache: FIATransactionCache())
+ transactionCache: DefaultTransactionCache(cache: FIATransactionCache()))
#if os(iOS)
let messenger = registrar.messenger()
#endif
#if os(macOS)
let messenger = registrar.messenger
#endif
- transactionObserverCallbackChannel = FlutterMethodChannel(
- name: "plugins.flutter.io/in_app_purchase", binaryMessenger: messenger)
+ transactionObserverCallbackChannel = DefaultMethodChannel(
+ channel: FlutterMethodChannel(
+ name: "plugins.flutter.io/in_app_purchase",
+ binaryMessenger: messenger)
+ )
}
// MARK: - Pigeon Functions
@@ -128,7 +133,7 @@
) {
let request = getProductRequest(withIdentifiers: Set(productIdentifiers))
let handler = handlerFactory(request)
- requestHandlers.insert(handler)
+ requestHandlers.add(handler)
handler.startProductRequest { [weak self] response, startProductRequestError in
guard let self = self else { return }
@@ -282,7 +287,7 @@
let properties = receiptProperties?.compactMapValues { $0 } ?? [:]
let request = getRefreshReceiptRequest(properties: properties.isEmpty ? nil : properties)
let handler = handlerFactory(request)
- requestHandlers.insert(handler)
+ requestHandlers.add(handler)
handler.startProductRequest { [weak self] response, error in
if let error = error {
let requestError = FlutterError(
@@ -322,10 +327,10 @@
binaryMessenger: messenger)
guard let unwrappedChannel = paymentQueueDelegateCallbackChannel else {
- fatalError("registrar.messenger can not be nil.")
+ fatalError("paymentQueueDelegateCallbackChannel can not be nil.")
}
paymentQueueDelegate = FIAPPaymentQueueDelegate(
- methodChannel: unwrappedChannel)
+ methodChannel: DefaultMethodChannel(channel: unwrappedChannel))
getPaymentQueueHandler().delegate = paymentQueueDelegate as? SKPaymentQueueDelegate
}
@@ -419,7 +424,7 @@
return value is NSNull ? nil : value
}
- private func getPaymentQueueHandler() -> FIAPaymentQueueHandler {
+ private func getPaymentQueueHandler() -> FLTPaymentQueueHandlerProtocol {
guard let paymentQueueHandler = self.paymentQueueHandler else {
fatalError(
"paymentQueueHandler can't be nil. Please ensure you're using init(registrar: FlutterPluginRegistrar)"
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTMethodChannelProtocol.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTMethodChannelProtocol.h
new file mode 100644
index 0000000..1285643
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTMethodChannelProtocol.h
@@ -0,0 +1,33 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if TARGET_OS_OSX
+#import <FlutterMacOS/FlutterMacOS.h>
+#else
+#import <Flutter/Flutter.h>
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+/// A protocol that wraps FlutterMethodChannel.
+@protocol FLTMethodChannelProtocol <NSObject>
+
+/// Invokes the specified Flutter method with the specified arguments, expecting
+/// an asynchronous result.
+- (void)invokeMethod:(NSString *)method arguments:(id _Nullable)arguments;
+
+/// Invokes the specified Flutter method with the specified arguments and specified callback
+- (void)invokeMethod:(NSString *)method
+ arguments:(id _Nullable)arguments
+ result:(FlutterResult _Nullable)callback;
+
+@end
+
+/// The default method channel that wraps FlutterMethodChannel
+@interface DefaultMethodChannel : NSObject <FLTMethodChannelProtocol>
+
+/// Initialize this wrapper with a FlutterMethodChannel
+- (instancetype)initWithChannel:(FlutterMethodChannel *)channel;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTMethodChannelProtocol.m b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTMethodChannelProtocol.m
new file mode 100644
index 0000000..17e0e08
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTMethodChannelProtocol.m
@@ -0,0 +1,32 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "FLTMethodChannelProtocol.h"
+
+@interface DefaultMethodChannel ()
+/// The wrapped FlutterMethodChannel
+@property(nonatomic, strong) FlutterMethodChannel *channel;
+@end
+
+@implementation DefaultMethodChannel
+
+- (instancetype)initWithChannel:(nonnull FlutterMethodChannel *)channel {
+ self = [super init];
+ if (self) {
+ _channel = channel;
+ }
+ return self;
+}
+
+- (void)invokeMethod:(nonnull NSString *)method arguments:(id _Nullable)arguments {
+ [self.channel invokeMethod:method arguments:arguments];
+}
+
+- (void)invokeMethod:(nonnull NSString *)method
+ arguments:(id _Nullable)arguments
+ result:(FlutterResult _Nullable)callback {
+ [self.channel invokeMethod:method arguments:arguments result:callback];
+}
+
+@end
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTPaymentQueueHandlerProtocol.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTPaymentQueueHandlerProtocol.h
new file mode 100644
index 0000000..f11b1a0
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTPaymentQueueHandlerProtocol.h
@@ -0,0 +1,107 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <StoreKit/StoreKit.h>
+#import "FIATransactionCache.h"
+#import "FLTPaymentQueueProtocol.h"
+#import "FLTTransactionCacheProtocol.h"
+
+NS_ASSUME_NONNULL_BEGIN
+typedef void (^TransactionsUpdated)(NSArray<SKPaymentTransaction *> *transactions);
+typedef void (^TransactionsRemoved)(NSArray<SKPaymentTransaction *> *transactions);
+typedef void (^RestoreTransactionFailed)(NSError *error);
+typedef void (^RestoreCompletedTransactionsFinished)(void);
+typedef BOOL (^ShouldAddStorePayment)(SKPayment *payment, SKProduct *product);
+typedef void (^UpdatedDownloads)(NSArray<SKDownload *> *downloads);
+
+/// A protocol that conforms to SKPaymentTransactionObserver and handles SKPaymentQueue methods
+@protocol FLTPaymentQueueHandlerProtocol <NSObject, SKPaymentTransactionObserver>
+/// An object that provides information needed to complete transactions.
+@property(nonatomic, weak, nullable) id<SKPaymentQueueDelegate> delegate API_AVAILABLE(
+ ios(13.0), macos(10.15), watchos(6.2));
+/// An object containing the location and unique identifier of an Apple App Store storefront.
+@property(nonatomic, readonly, nullable)
+ SKStorefront *storefront API_AVAILABLE(ios(13.0), macos(10.15), watchos(6.2));
+
+/// Creates a new FIAPaymentQueueHandler.
+///
+/// The "transactionsUpdated", "transactionsRemoved" and "updatedDownloads"
+/// callbacks are only called while actively observing transactions. To start
+/// observing transactions send the "startObservingPaymentQueue" message.
+/// Sending the "stopObservingPaymentQueue" message will stop actively
+/// observing transactions. When transactions are not observed they are cached
+/// to the "transactionCache" and will be delivered via the
+/// "transactionsUpdated", "transactionsRemoved" and "updatedDownloads"
+/// callbacks as soon as the "startObservingPaymentQueue" message arrives.
+///
+/// Note: cached transactions that are not processed when the application is
+/// killed will be delivered again by the App Store as soon as the application
+/// starts again.
+///
+/// @param queue The SKPaymentQueue instance connected to the App Store and
+/// responsible for processing transactions.
+/// @param transactionsUpdated Callback method that is called each time the App
+/// Store indicates transactions are updated.
+/// @param transactionsRemoved Callback method that is called each time the App
+/// Store indicates transactions are removed.
+/// @param restoreTransactionFailed Callback method that is called each time
+/// the App Store indicates transactions failed
+/// to restore.
+/// @param restoreCompletedTransactionsFinished Callback method that is called
+/// each time the App Store
+/// indicates restoring of
+/// transactions has finished.
+/// @param shouldAddStorePayment Callback method that is called each time an
+/// in-app purchase has been initiated from the
+/// App Store.
+/// @param updatedDownloads Callback method that is called each time the App
+/// Store indicates downloads are updated.
+/// @param transactionCache An empty [FIATransactionCache] instance that is
+/// responsible for keeping track of transactions that
+/// arrive when not actively observing transactions.
+- (instancetype)initWithQueue:(id<FLTPaymentQueueProtocol>)queue
+ transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated
+ transactionRemoved:(nullable TransactionsRemoved)transactionsRemoved
+ restoreTransactionFailed:(nullable RestoreTransactionFailed)restoreTransactionFailed
+ restoreCompletedTransactionsFinished:
+ (nullable RestoreCompletedTransactionsFinished)restoreCompletedTransactionsFinished
+ shouldAddStorePayment:(nullable ShouldAddStorePayment)shouldAddStorePayment
+ updatedDownloads:(nullable UpdatedDownloads)updatedDownloads
+ transactionCache:(nonnull id<FLTTransactionCacheProtocol>)transactionCache;
+
+/// Can throw exceptions if the transaction type is purchasing, should always used in a @try block.
+- (void)finishTransaction:(nonnull SKPaymentTransaction *)transaction;
+
+/// Attempt to restore transactions. Require app store receipt url.
+- (void)restoreTransactions:(nullable NSString *)applicationName;
+
+/// Displays a sheet that enables users to redeem subscription offer codes.
+- (void)presentCodeRedemptionSheet API_UNAVAILABLE(tvos, macos, watchos);
+
+/// Return all transactions that are not marked as complete.
+- (NSArray<SKPaymentTransaction *> *)getUnfinishedTransactions;
+
+/// This method needs to be called before any other methods.
+- (void)startObservingPaymentQueue;
+
+/// Call this method when the Flutter app is no longer listening
+- (void)stopObservingPaymentQueue;
+
+/// Appends a payment to the SKPaymentQueue.
+///
+/// @param payment Payment object to be added to the payment queue.
+/// @return whether "addPayment" was successful.
+- (BOOL)addPayment:(SKPayment *)payment;
+
+/// Displays the price consent sheet.
+///
+/// The price consent sheet is only displayed when the following
+/// is true:
+/// - You have increased the price of the subscription in App Store Connect.
+/// - The subscriber has not yet responded to a price consent query.
+/// Otherwise the method has no effect.
+- (void)showPriceConsentIfNeeded API_AVAILABLE(ios(13.4))API_UNAVAILABLE(tvos, macos, watchos);
+
+@end
+NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTPaymentQueueProtocol.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTPaymentQueueProtocol.h
new file mode 100644
index 0000000..4047647
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTPaymentQueueProtocol.h
@@ -0,0 +1,69 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <StoreKit/StoreKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// A protocol that wraps SKPaymentQueue
+@protocol FLTPaymentQueueProtocol <NSObject>
+
+/// An object containing the location and unique identifier of an Apple App Store storefront.
+@property(nonatomic, strong) SKStorefront *storefront API_AVAILABLE(ios(13.0));
+
+/// A list of SKPaymentTransactions, which each represents a single transaction
+@property(nonatomic, strong) NSArray<SKPaymentTransaction *> *transactions API_AVAILABLE(
+ ios(3.0), macos(10.7), watchos(6.2), visionos(1.0));
+
+/// An object that provides information needed to complete transactions.
+@property(nonatomic, weak, nullable) id<SKPaymentQueueDelegate> delegate API_AVAILABLE(
+ ios(13.0), macos(10.15), watchos(6.2), visionos(1.0));
+
+/// Remove a finished (i.e. failed or completed) transaction from the queue. Attempting to finish a
+/// purchasing transaction will throw an exception.
+- (void)finishTransaction:(nonnull SKPaymentTransaction *)transaction;
+
+/// Observers are not retained. The transactions array will only be synchronized with the server
+/// while the queue has observers. This may require that the user authenticate.
+- (void)addTransactionObserver:(id<SKPaymentTransactionObserver>)observer;
+
+/// Add a payment to the server queue. The payment is copied to add an SKPaymentTransaction to the
+/// transactions array. The same payment can be added multiple times to create multiple
+/// transactions.
+- (void)addPayment:(SKPayment *_Nonnull)payment;
+
+/// Will add completed transactions for the current user back to the queue to be re-completed.
+- (void)restoreCompletedTransactions API_AVAILABLE(ios(3.0), macos(10.7), watchos(6.2),
+ visionos(1.0));
+
+/// Will add completed transactions for the current user back to the queue to be re-completed. This
+/// version requires an identifier to the user's account.
+- (void)restoreCompletedTransactionsWithApplicationUsername:(nullable NSString *)username
+ API_AVAILABLE(ios(7.0), macos(10.9), watchos(6.2), visionos(1.0));
+
+/// Call this method to have StoreKit present a sheet enabling the user to redeem codes provided by
+/// your app. Only for iOS.
+- (void)presentCodeRedemptionSheet API_AVAILABLE(ios(14.0), visionos(1.0))
+ API_UNAVAILABLE(tvos, macos, watchos);
+
+/// If StoreKit has called your SKPaymentQueueDelegate's "paymentQueueShouldShowPriceConsent:"
+/// method and you returned NO, you can use this method to show the price consent UI at a later time
+/// that is more appropriate for your app. If there is no pending price consent, this method will do
+/// nothing.
+- (void)showPriceConsentIfNeeded API_AVAILABLE(ios(13.4), visionos(1.0))
+ API_UNAVAILABLE(tvos, macos, watchos);
+
+@end
+
+/// The default PaymentQueue that wraps SKPaymentQueue
+@interface DefaultPaymentQueue : NSObject <FLTPaymentQueueProtocol>
+
+/// Initialize this wrapper with an SKPaymentQueue
+- (instancetype)initWithQueue:(SKPaymentQueue *)queue NS_DESIGNATED_INITIALIZER;
+
+/// The default initializer is unavailable, as it this must be initlai
+- (instancetype)init NS_UNAVAILABLE;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTPaymentQueueProtocol.m b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTPaymentQueueProtocol.m
new file mode 100644
index 0000000..fd97794
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTPaymentQueueProtocol.m
@@ -0,0 +1,74 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "FLTPaymentQueueProtocol.h"
+
+@interface DefaultPaymentQueue ()
+/// The wrapped SKPaymentQueue
+@property(nonatomic, strong) SKPaymentQueue *queue;
+@end
+
+@implementation DefaultPaymentQueue
+
+@synthesize storefront;
+@synthesize delegate;
+@synthesize transactions;
+
+- (instancetype)initWithQueue:(SKPaymentQueue *)queue {
+ self = [super init];
+ if (self) {
+ _queue = queue;
+ }
+ return self;
+}
+
+- (void)addPayment:(SKPayment *_Nonnull)payment {
+ [self.queue addPayment:payment];
+}
+
+- (void)finishTransaction:(nonnull SKPaymentTransaction *)transaction {
+ [self.queue finishTransaction:transaction];
+}
+
+- (void)addTransactionObserver:(nonnull id<SKPaymentTransactionObserver>)observer {
+ [self.queue addTransactionObserver:observer];
+}
+
+- (void)restoreCompletedTransactions {
+ [self.queue restoreCompletedTransactions];
+}
+
+- (void)restoreCompletedTransactionsWithApplicationUsername:(nullable NSString *)username {
+ [self.queue restoreCompletedTransactionsWithApplicationUsername:username];
+}
+
+- (id<SKPaymentQueueDelegate>)delegate API_AVAILABLE(ios(13.0), macos(10.15), watchos(6.2),
+ visionos(1.0)) {
+ return self.queue.delegate;
+}
+
+- (NSArray<SKPaymentTransaction *> *)transactions API_AVAILABLE(ios(3.0), macos(10.7), watchos(6.2),
+ visionos(1.0)) {
+ return self.queue.transactions;
+}
+
+- (SKStorefront *)storefront API_AVAILABLE(ios(13.0)) {
+ return self.queue.storefront;
+}
+
+#if TARGET_OS_IOS
+- (void)presentCodeRedemptionSheet API_AVAILABLE(ios(14.0), visionos(1.0))
+ API_UNAVAILABLE(tvos, macos, watchos) {
+ [self.queue presentCodeRedemptionSheet];
+}
+#endif
+
+#if TARGET_OS_IOS
+- (void)showPriceConsentIfNeeded API_AVAILABLE(ios(13.4), visionos(1.0))
+ API_UNAVAILABLE(tvos, macos, watchos) {
+ [self.queue showPriceConsentIfNeeded];
+}
+#endif
+
+@end
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTRequestHandlerProtocol.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTRequestHandlerProtocol.h
new file mode 100644
index 0000000..d2359d4
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTRequestHandlerProtocol.h
@@ -0,0 +1,17 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <StoreKit/StoreKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+typedef void (^ProductRequestCompletion)(SKProductsResponse *_Nullable response,
+ NSError *_Nullable errror);
+/// A protocol that wraps SKRequest.
+@protocol FLTRequestHandlerProtocol <NSObject>
+
+/// Wrapper for SKRequest's start
+/// https://developer.apple.com/documentation/storekit/skrequest/1385534-start
+- (void)startProductRequestWithCompletionHandler:(ProductRequestCompletion)completion;
+@end
+NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTRequestHandlerProtocol.m b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTRequestHandlerProtocol.m
new file mode 100644
index 0000000..e171467
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTRequestHandlerProtocol.m
@@ -0,0 +1,27 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "FLTRequestHandlerProtocol.h"
+#import <Foundation/Foundation.h>
+#import "FIAPRequestHandler.h"
+
+@interface DefaultRequestHandler ()
+/// The wrapped FIAPRequestHandler
+@property(nonatomic, strong) FIAPRequestHandler *handler;
+@end
+
+@implementation DefaultRequestHandler
+
+- (void)startProductRequestWithCompletionHandler:(nonnull ProductRequestCompletion)completion {
+ [self.handler startProductRequestWithCompletionHandler:completion];
+}
+
+- (nonnull instancetype)initWithRequestHandler:(nonnull FIAPRequestHandler *)handler {
+ self = [super init];
+ if (self) {
+ _handler = handler;
+ }
+ return self;
+}
+@end
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTTransactionCacheProtocol.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTTransactionCacheProtocol.h
new file mode 100644
index 0000000..f7a58b3
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTTransactionCacheProtocol.h
@@ -0,0 +1,39 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "FIATransactionCache.h"
+#if TARGET_OS_OSX
+#import <FlutterMacOS/FlutterMacOS.h>
+#else
+#import <Flutter/Flutter.h>
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// A protocol that defines a cache of all transactions, both completed and in progress.
+@protocol FLTTransactionCacheProtocol <NSObject>
+
+/// Adds objects to the transaction cache.
+///
+/// If the cache already contains an array of objects on the specified key, the supplied
+/// array will be appended to the existing array.
+- (void)addObjects:(NSArray *)objects forKey:(TransactionCacheKey)key;
+
+/// Gets the array of objects stored at the given key.
+///
+/// If there are no objects associated with the given key nil is returned.
+- (NSArray *)getObjectsForKey:(TransactionCacheKey)key;
+
+/// Removes all objects from the transaction cache.
+- (void)clear;
+@end
+
+/// The default method channel that wraps FIATransactionCache
+@interface DefaultTransactionCache : NSObject <FLTTransactionCacheProtocol>
+
+/// Initialize this wrapper with an FIATransactionCache
+- (instancetype)initWithCache:(FIATransactionCache *)cache;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTTransactionCacheProtocol.m b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTTransactionCacheProtocol.m
new file mode 100644
index 0000000..3ed268e
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/Protocols/FLTTransactionCacheProtocol.m
@@ -0,0 +1,33 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "FLTTransactionCacheProtocol.h"
+
+@interface DefaultTransactionCache ()
+/// The wrapped FIATransactionCache
+@property(nonatomic, strong) FIATransactionCache *cache;
+@end
+
+@implementation DefaultTransactionCache
+
+- (void)addObjects:(nonnull NSArray *)objects forKey:(TransactionCacheKey)key {
+ [self.cache addObjects:objects forKey:key];
+}
+
+- (void)clear {
+ [self.cache clear];
+}
+
+- (nonnull NSArray *)getObjectsForKey:(TransactionCacheKey)key {
+ return [self.cache getObjectsForKey:key];
+}
+
+- (nonnull instancetype)initWithCache:(nonnull FIATransactionCache *)cache {
+ self = [super init];
+ if (self) {
+ _cache = cache;
+ }
+ return self;
+}
+@end
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/in_app_purchase_storekit-Bridging-Header.h b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/in_app_purchase_storekit-Bridging-Header.h
index f57780d..e44e5cf 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/in_app_purchase_storekit-Bridging-Header.h
+++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/in_app_purchase_storekit-Bridging-Header.h
@@ -8,4 +8,9 @@
#import "FIAPRequestHandler.h"
#import "FIAPaymentQueueHandler.h"
#import "FIATransactionCache.h"
+#import "FLTMethodChannelProtocol.h"
+#import "FLTPaymentQueueHandlerProtocol.h"
+#import "FLTPaymentQueueProtocol.h"
+#import "FLTRequestHandlerProtocol.h"
+#import "FLTTransactionCacheProtocol.h"
#import "messages.g.h"
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Podfile b/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Podfile
index 0358424..bb776ac 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Podfile
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Podfile
@@ -33,8 +33,6 @@
target 'RunnerTests' do
inherit! :search_paths
- # Matches in_app_purchase test_spec dependency.
- pod 'OCMock', '~> 3.6'
end
end
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Runner.xcodeproj/project.pbxproj b/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Runner.xcodeproj/project.pbxproj
index 5b7ba61..7d99ab6 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Runner.xcodeproj/project.pbxproj
@@ -7,24 +7,24 @@
objects = {
/* Begin PBXBuildFile section */
- 0FFCF66105590202CD84C7AA /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1630769A874F9381BC761FE1 /* libPods-Runner.a */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
- 688DE35121F2A5A100EA2684 /* TranslatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 688DE35021F2A5A100EA2684 /* TranslatorTests.m */; };
- 6896B34621E9363700D37AEF /* ProductRequestHandlerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6896B34521E9363700D37AEF /* ProductRequestHandlerTests.m */; };
- 6896B34C21EEB4B800D37AEF /* Stubs.m in Sources */ = {isa = PBXBuildFile; fileRef = 6896B34B21EEB4B800D37AEF /* Stubs.m */; };
- 7E34217B7715B1918134647A /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 18D02AB334F1C07BB9A4374A /* libPods-RunnerTests.a */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
A5279298219369C600FF69E6 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A5279297219369C600FF69E6 /* StoreKit.framework */; };
- A59001A721E69658004A3E5E /* InAppPurchasePluginTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A59001A621E69658004A3E5E /* InAppPurchasePluginTests.m */; };
+ C4667AA10A6BC70CE9A5007C /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AB9CD9DD098BDAB3D5053EE5 /* libPods-RunnerTests.a */; };
+ E680BD031412EB2D02C9190B /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21CE6E615CF661FC0E18FB0A /* libPods-Runner.a */; };
F22BF91C2BC9B40B00713878 /* SwiftStubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = F22BF91B2BC9B40B00713878 /* SwiftStubs.swift */; };
- F67646F82681D9A80048C2EA /* FIAPPaymentQueueDeleteTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F67646F72681D9A80048C2EA /* FIAPPaymentQueueDeleteTests.m */; };
- F6995BDD27CF73000050EA78 /* FIATransactionCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F6995BDC27CF73000050EA78 /* FIATransactionCacheTests.m */; };
- F78AF3142342BC89008449C7 /* PaymentQueueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F78AF3132342BC89008449C7 /* PaymentQueueTests.m */; };
+ F295AD3A2C1256DD0067C78A /* Stubs.m in Sources */ = {isa = PBXBuildFile; fileRef = F295AD392C1256DD0067C78A /* Stubs.m */; };
+ F295AD412C1256F50067C78A /* FIAPPaymentQueueDeleteTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F295AD3B2C1256F50067C78A /* FIAPPaymentQueueDeleteTests.m */; };
+ F295AD422C1256F50067C78A /* InAppPurchasePluginTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F295AD3C2C1256F50067C78A /* InAppPurchasePluginTests.m */; };
+ F295AD432C1256F50067C78A /* ProductRequestHandlerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F295AD3D2C1256F50067C78A /* ProductRequestHandlerTests.m */; };
+ F295AD442C1256F50067C78A /* FIATransactionCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F295AD3E2C1256F50067C78A /* FIATransactionCacheTests.m */; };
+ F295AD452C1256F50067C78A /* PaymentQueueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F295AD3F2C1256F50067C78A /* PaymentQueueTests.m */; };
+ F295AD462C1256F50067C78A /* TranslatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F295AD402C1256F50067C78A /* TranslatorTests.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -51,20 +51,16 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 10B860DFD91A1DF639D7BE1D /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
- 1630769A874F9381BC761FE1 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
- 18D02AB334F1C07BB9A4374A /* libPods-RunnerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
- 2550EB3A5A3E749A54ADCA2D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
+ 21CE6E615CF661FC0E18FB0A /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
- 688DE35021F2A5A100EA2684 /* TranslatorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TranslatorTests.m; sourceTree = "<group>"; };
- 6896B34521E9363700D37AEF /* ProductRequestHandlerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProductRequestHandlerTests.m; sourceTree = "<group>"; };
- 6896B34A21EEB4B800D37AEF /* Stubs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Stubs.h; sourceTree = "<group>"; };
- 6896B34B21EEB4B800D37AEF /* Stubs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Stubs.m; sourceTree = "<group>"; };
+ 6458340B2CE3497379F6B389 /* 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 = "<group>"; };
+ 7AB7758EFACBE3E1E7BDE0C6 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ 8B97B58DB1E9CF900A4617A3 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -73,18 +69,21 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- 9D681E092EB0D20D652F69FC /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
A5279297219369C600FF69E6 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
A59001A421E69658004A3E5E /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- A59001A621E69658004A3E5E /* InAppPurchasePluginTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InAppPurchasePluginTests.m; sourceTree = "<group>"; };
- A59001A821E69658004A3E5E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- E4F9651425A612301059769C /* 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 = "<group>"; };
+ AB9CD9DD098BDAB3D5053EE5 /* libPods-RunnerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ CC9E5595B2B9B9B90632DA75 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
F22BF91A2BC9B40B00713878 /* RunnerTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RunnerTests-Bridging-Header.h"; sourceTree = "<group>"; };
F22BF91B2BC9B40B00713878 /* SwiftStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftStubs.swift; sourceTree = "<group>"; };
- F67646F72681D9A80048C2EA /* FIAPPaymentQueueDeleteTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIAPPaymentQueueDeleteTests.m; sourceTree = "<group>"; };
- F6995BDC27CF73000050EA78 /* FIATransactionCacheTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FIATransactionCacheTests.m; sourceTree = "<group>"; };
+ F295AD362C1251300067C78A /* Stubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Stubs.h; path = ../../shared/RunnerTests/Stubs.h; sourceTree = "<group>"; };
+ F295AD392C1256DD0067C78A /* Stubs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Stubs.m; path = ../../shared/RunnerTests/Stubs.m; sourceTree = "<group>"; };
+ F295AD3B2C1256F50067C78A /* FIAPPaymentQueueDeleteTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FIAPPaymentQueueDeleteTests.m; path = ../../shared/RunnerTests/FIAPPaymentQueueDeleteTests.m; sourceTree = "<group>"; };
+ F295AD3C2C1256F50067C78A /* InAppPurchasePluginTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = InAppPurchasePluginTests.m; path = ../../shared/RunnerTests/InAppPurchasePluginTests.m; sourceTree = "<group>"; };
+ F295AD3D2C1256F50067C78A /* ProductRequestHandlerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProductRequestHandlerTests.m; path = ../../shared/RunnerTests/ProductRequestHandlerTests.m; sourceTree = "<group>"; };
+ F295AD3E2C1256F50067C78A /* FIATransactionCacheTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FIATransactionCacheTests.m; path = ../../shared/RunnerTests/FIATransactionCacheTests.m; sourceTree = "<group>"; };
+ F295AD3F2C1256F50067C78A /* PaymentQueueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PaymentQueueTests.m; path = ../../shared/RunnerTests/PaymentQueueTests.m; sourceTree = "<group>"; };
+ F295AD402C1256F50067C78A /* TranslatorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TranslatorTests.m; path = ../../shared/RunnerTests/TranslatorTests.m; sourceTree = "<group>"; };
F6E5D5F926131C4800C68BED /* Configuration.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = Configuration.storekit; sourceTree = "<group>"; };
- F78AF3132342BC89008449C7 /* PaymentQueueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PaymentQueueTests.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -93,7 +92,7 @@
buildActionMask = 2147483647;
files = (
A5279298219369C600FF69E6 /* StoreKit.framework in Frameworks */,
- 0FFCF66105590202CD84C7AA /* libPods-Runner.a in Frameworks */,
+ E680BD031412EB2D02C9190B /* libPods-Runner.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -101,7 +100,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 7E34217B7715B1918134647A /* libPods-RunnerTests.a in Frameworks */,
+ C4667AA10A6BC70CE9A5007C /* libPods-RunnerTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -111,10 +110,10 @@
0B4403AC68C3196AECF5EF89 /* Pods */ = {
isa = PBXGroup;
children = (
- E4F9651425A612301059769C /* Pods-Runner.debug.xcconfig */,
- 2550EB3A5A3E749A54ADCA2D /* Pods-Runner.release.xcconfig */,
- 9D681E092EB0D20D652F69FC /* Pods-RunnerTests.debug.xcconfig */,
- 10B860DFD91A1DF639D7BE1D /* Pods-RunnerTests.release.xcconfig */,
+ 6458340B2CE3497379F6B389 /* Pods-Runner.debug.xcconfig */,
+ CC9E5595B2B9B9B90632DA75 /* Pods-Runner.release.xcconfig */,
+ 7AB7758EFACBE3E1E7BDE0C6 /* Pods-RunnerTests.debug.xcconfig */,
+ 8B97B58DB1E9CF900A4617A3 /* Pods-RunnerTests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@@ -187,15 +186,14 @@
A59001A521E69658004A3E5E /* RunnerTests */ = {
isa = PBXGroup;
children = (
- A59001A821E69658004A3E5E /* Info.plist */,
- 6896B34A21EEB4B800D37AEF /* Stubs.h */,
- 6896B34B21EEB4B800D37AEF /* Stubs.m */,
- A59001A621E69658004A3E5E /* InAppPurchasePluginTests.m */,
- 6896B34521E9363700D37AEF /* ProductRequestHandlerTests.m */,
- F78AF3132342BC89008449C7 /* PaymentQueueTests.m */,
- 688DE35021F2A5A100EA2684 /* TranslatorTests.m */,
- F67646F72681D9A80048C2EA /* FIAPPaymentQueueDeleteTests.m */,
- F6995BDC27CF73000050EA78 /* FIATransactionCacheTests.m */,
+ F295AD3B2C1256F50067C78A /* FIAPPaymentQueueDeleteTests.m */,
+ F295AD3E2C1256F50067C78A /* FIATransactionCacheTests.m */,
+ F295AD3C2C1256F50067C78A /* InAppPurchasePluginTests.m */,
+ F295AD3F2C1256F50067C78A /* PaymentQueueTests.m */,
+ F295AD3D2C1256F50067C78A /* ProductRequestHandlerTests.m */,
+ F295AD402C1256F50067C78A /* TranslatorTests.m */,
+ F295AD392C1256DD0067C78A /* Stubs.m */,
+ F295AD362C1251300067C78A /* Stubs.h */,
F22BF91B2BC9B40B00713878 /* SwiftStubs.swift */,
F22BF91A2BC9B40B00713878 /* RunnerTests-Bridging-Header.h */,
);
@@ -206,8 +204,8 @@
isa = PBXGroup;
children = (
A5279297219369C600FF69E6 /* StoreKit.framework */,
- 1630769A874F9381BC761FE1 /* libPods-Runner.a */,
- 18D02AB334F1C07BB9A4374A /* libPods-RunnerTests.a */,
+ 21CE6E615CF661FC0E18FB0A /* libPods-Runner.a */,
+ AB9CD9DD098BDAB3D5053EE5 /* libPods-RunnerTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -219,14 +217,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
- EDD921296E29F853F7B69716 /* [CP] Check Pods Manifest.lock */,
+ 9AF65E7BDC9361CB3944EE9C /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
- 67CBAA37FA50343E43E988F6 /* [CP] Copy Pods Resources */,
+ 325E900B3895C722B0E09318 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -241,7 +239,7 @@
isa = PBXNativeTarget;
buildConfigurationList = A59001AD21E69658004A3E5E /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
- 95C7A5986B77A8DF76F6DF3A /* [CP] Check Pods Manifest.lock */,
+ 39A4BCA317070A14A6C5C70F /* [CP] Check Pods Manifest.lock */,
A59001A021E69658004A3E5E /* Sources */,
A59001A121E69658004A3E5E /* Frameworks */,
A59001A221E69658004A3E5E /* Resources */,
@@ -323,23 +321,7 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
- isa = PBXShellScriptBuildPhase;
- alwaysOutOfDate = 1;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
- );
- name = "Thin Binary";
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
- };
- 67CBAA37FA50343E43E988F6 /* [CP] Copy Pods Resources */ = {
+ 325E900B3895C722B0E09318 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -347,17 +329,19 @@
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/in_app_purchase_storekit/in_app_purchase_storekit_privacy.bundle",
+ "${PODS_CONFIGURATION_BUILD_DIR}/shared_preferences_foundation/shared_preferences_foundation_privacy.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/in_app_purchase_storekit_privacy.bundle",
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/shared_preferences_foundation_privacy.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 95C7A5986B77A8DF76F6DF3A /* [CP] Check Pods Manifest.lock */ = {
+ 39A4BCA317070A14A6C5C70F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -379,6 +363,22 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
+ };
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -394,7 +394,7 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
- EDD921296E29F853F7B69716 /* [CP] Check Pods Manifest.lock */ = {
+ 9AF65E7BDC9361CB3944EE9C /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -433,14 +433,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ F295AD432C1256F50067C78A /* ProductRequestHandlerTests.m in Sources */,
F22BF91C2BC9B40B00713878 /* SwiftStubs.swift in Sources */,
- F78AF3142342BC89008449C7 /* PaymentQueueTests.m in Sources */,
- F67646F82681D9A80048C2EA /* FIAPPaymentQueueDeleteTests.m in Sources */,
- 6896B34621E9363700D37AEF /* ProductRequestHandlerTests.m in Sources */,
- 688DE35121F2A5A100EA2684 /* TranslatorTests.m in Sources */,
- F6995BDD27CF73000050EA78 /* FIATransactionCacheTests.m in Sources */,
- A59001A721E69658004A3E5E /* InAppPurchasePluginTests.m in Sources */,
- 6896B34C21EEB4B800D37AEF /* Stubs.m in Sources */,
+ F295AD412C1256F50067C78A /* FIAPPaymentQueueDeleteTests.m in Sources */,
+ F295AD452C1256F50067C78A /* PaymentQueueTests.m in Sources */,
+ F295AD442C1256F50067C78A /* FIATransactionCacheTests.m in Sources */,
+ F295AD462C1256F50067C78A /* TranslatorTests.m in Sources */,
+ F295AD422C1256F50067C78A /* InAppPurchasePluginTests.m in Sources */,
+ F295AD3A2C1256DD0067C78A /* Stubs.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -636,7 +636,7 @@
};
A59001AB21E69658004A3E5E /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 9D681E092EB0D20D652F69FC /* Pods-RunnerTests.debug.xcconfig */;
+ baseConfigurationReference = 7AB7758EFACBE3E1E7BDE0C6 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
@@ -667,7 +667,7 @@
};
A59001AC21E69658004A3E5E /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 10B860DFD91A1DF639D7BE1D /* Pods-RunnerTests.release.xcconfig */;
+ baseConfigurationReference = 8B97B58DB1E9CF900A4617A3 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Runner/Configuration.storekit b/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Runner/Configuration.storekit
index 29ebbeb..58f3d43 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Runner/Configuration.storekit
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/ios/Runner/Configuration.storekit
@@ -1,4 +1,14 @@
{
+ "appPolicies" : {
+ "eula" : "",
+ "policies" : [
+ {
+ "locale" : "en_US",
+ "policyText" : "",
+ "policyURL" : ""
+ }
+ ]
+ },
"identifier" : "6073E9A3",
"nonRenewingSubscriptions" : [
@@ -118,7 +128,10 @@
"recurringSubscriptionPeriod" : "P1W",
"referenceName" : "subscription_silver",
"subscriptionGroupID" : "D0FEE8D8",
- "type" : "RecurringSubscription"
+ "type" : "RecurringSubscription",
+ "winbackOffers" : [
+
+ ]
},
{
"adHocOffers" : [
@@ -143,13 +156,16 @@
"recurringSubscriptionPeriod" : "P1M",
"referenceName" : "subscription_gold",
"subscriptionGroupID" : "D0FEE8D8",
- "type" : "RecurringSubscription"
+ "type" : "RecurringSubscription",
+ "winbackOffers" : [
+
+ ]
}
]
}
],
"version" : {
- "major" : 3,
+ "major" : 4,
"minor" : 0
}
}
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Podfile b/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Podfile
index 04238b6..0fcebff 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Podfile
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Podfile
@@ -34,8 +34,6 @@
target 'RunnerTests' do
inherit! :search_paths
-
- pod 'OCMock', '~> 3.6'
end
end
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcodeproj/project.pbxproj b/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcodeproj/project.pbxproj
index e4eb1fa..86bb211 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcodeproj/project.pbxproj
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcodeproj/project.pbxproj
@@ -265,7 +265,6 @@
F700DCFE28E652A10004836B /* Sources */,
F700DCFF28E652A10004836B /* Frameworks */,
F700DD0028E652A10004836B /* Resources */,
- E318947BE753B7BBEFC3782A /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -425,23 +424,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- E318947BE753B7BBEFC3782A /* [CP] Embed Pods Frameworks */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
- );
- name = "[CP] Embed Pods Frameworks";
- outputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks.sh\"\n";
- showEnvVarsInLog = 0;
- };
F83C62E1BF4D0A86747FA7CF /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 53f3a37..5eb222f 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -38,8 +38,7 @@
</MacroExpansion>
<Testables>
<TestableReference
- skipped = "NO"
- parallelizable = "NO">
+ skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F700DD0128E652A10004836B"
@@ -70,6 +69,9 @@
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
+ <StoreKitConfigurationFileReference
+ identifier = "../../ios/Runner/Configuration.storekit">
+ </StoreKitConfigurationFileReference>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcworkspace/contents.xcworkspacedata
index 21a3cc1..7f167c1 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcworkspace/contents.xcworkspacedata
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/macos/Runner.xcworkspace/contents.xcworkspacedata
@@ -2,6 +2,9 @@
<Workspace
version = "1.0">
<FileRef
+ location = "group:../ios/Runner/Configuration.storekit">
+ </FileRef>
+ <FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/FIAPPaymentQueueDeleteTests.m b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/FIAPPaymentQueueDeleteTests.m
index 187cc6e..1056c34 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/FIAPPaymentQueueDeleteTests.m
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/FIAPPaymentQueueDeleteTests.m
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#import "FIAObjectTranslator.h"
#import "FIAPaymentQueueHandler.h"
@@ -14,17 +13,14 @@
API_UNAVAILABLE(tvos, macos, watchos)
@interface FIAPPaymentQueueDelegateTests : XCTestCase
-@property(strong, nonatomic) FlutterMethodChannel *channel;
-@property(strong, nonatomic) SKPaymentTransaction *transaction;
-@property(strong, nonatomic) SKStorefront *storefront;
+@property(nonatomic, strong) SKPaymentTransaction *transaction;
+@property(nonatomic, strong) SKStorefront *storefront;
@end
@implementation FIAPPaymentQueueDelegateTests
- (void)setUp {
- self.channel = OCMClassMock(FlutterMethodChannel.class);
-
NSDictionary *transactionMap = @{
@"transactionIdentifier" : [NSNull null],
@"transactionState" : @(SKPaymentTransactionStatePurchasing),
@@ -45,21 +41,24 @@
}
- (void)tearDown {
- self.channel = nil;
}
- (void)testShouldContinueTransaction {
if (@available(iOS 13.0, *)) {
+ MethodChannelStub *channelStub = [[MethodChannelStub alloc] init];
+ channelStub.invokeMethodChannelWithResultsStub =
+ ^(NSString *_Nonnull method, id _Nonnull arguments, FlutterResult _Nullable result) {
+ XCTAssertEqualObjects(method, @"shouldContinueTransaction");
+ XCTAssertEqualObjects(arguments,
+ [FIAObjectTranslator getMapFromSKStorefront:self.storefront
+ andSKPaymentTransaction:self.transaction]);
+ result(@NO);
+ };
+
FIAPPaymentQueueDelegate *delegate =
- [[FIAPPaymentQueueDelegate alloc] initWithMethodChannel:self.channel];
+ [[FIAPPaymentQueueDelegate alloc] initWithMethodChannel:channelStub];
- OCMStub([self.channel
- invokeMethod:@"shouldContinueTransaction"
- arguments:[FIAObjectTranslator getMapFromSKStorefront:self.storefront
- andSKPaymentTransaction:self.transaction]
- result:([OCMArg invokeBlockWithArgs:[NSNumber numberWithBool:NO], nil])]);
-
- BOOL shouldContinue = [delegate paymentQueue:OCMClassMock(SKPaymentQueue.class)
+ BOOL shouldContinue = [delegate paymentQueue:[[SKPaymentQueueStub alloc] init]
shouldContinueTransaction:self.transaction
inStorefront:self.storefront];
@@ -69,15 +68,19 @@
- (void)testShouldContinueTransaction_should_default_to_yes {
if (@available(iOS 13.0, *)) {
+ MethodChannelStub *channelStub = [[MethodChannelStub alloc] init];
FIAPPaymentQueueDelegate *delegate =
- [[FIAPPaymentQueueDelegate alloc] initWithMethodChannel:self.channel];
+ [[FIAPPaymentQueueDelegate alloc] initWithMethodChannel:channelStub];
- OCMStub([self.channel invokeMethod:@"shouldContinueTransaction"
- arguments:[FIAObjectTranslator getMapFromSKStorefront:self.storefront
- andSKPaymentTransaction:self.transaction]
- result:[OCMArg any]]);
+ channelStub.invokeMethodChannelWithResultsStub =
+ ^(NSString *_Nonnull method, id _Nonnull arguments, FlutterResult _Nullable result) {
+ XCTAssertEqualObjects(method, @"shouldContinueTransaction");
+ XCTAssertEqualObjects(arguments,
+ [FIAObjectTranslator getMapFromSKStorefront:self.storefront
+ andSKPaymentTransaction:self.transaction]);
+ };
- BOOL shouldContinue = [delegate paymentQueue:OCMClassMock(SKPaymentQueue.class)
+ BOOL shouldContinue = [delegate paymentQueue:[[SKPaymentQueueStub alloc] init]
shouldContinueTransaction:self.transaction
inStorefront:self.storefront];
@@ -88,16 +91,19 @@
#if TARGET_OS_IOS
- (void)testShouldShowPriceConsentIfNeeded {
if (@available(iOS 13.4, *)) {
+ MethodChannelStub *channelStub = [[MethodChannelStub alloc] init];
FIAPPaymentQueueDelegate *delegate =
- [[FIAPPaymentQueueDelegate alloc] initWithMethodChannel:self.channel];
+ [[FIAPPaymentQueueDelegate alloc] initWithMethodChannel:channelStub];
- OCMStub([self.channel
- invokeMethod:@"shouldShowPriceConsent"
- arguments:nil
- result:([OCMArg invokeBlockWithArgs:[NSNumber numberWithBool:NO], nil])]);
+ channelStub.invokeMethodChannelWithResultsStub =
+ ^(NSString *_Nonnull method, id _Nonnull arguments, FlutterResult _Nullable result) {
+ XCTAssertEqualObjects(method, @"shouldShowPriceConsent");
+ XCTAssertNil(arguments);
+ result(@NO);
+ };
BOOL shouldShow =
- [delegate paymentQueueShouldShowPriceConsent:OCMClassMock(SKPaymentQueue.class)];
+ [delegate paymentQueueShouldShowPriceConsent:[[SKPaymentQueueStub alloc] init]];
XCTAssertFalse(shouldShow);
}
@@ -107,15 +113,18 @@
#if TARGET_OS_IOS
- (void)testShouldShowPriceConsentIfNeeded_should_default_to_yes {
if (@available(iOS 13.4, *)) {
+ MethodChannelStub *channelStub = [[MethodChannelStub alloc] init];
FIAPPaymentQueueDelegate *delegate =
- [[FIAPPaymentQueueDelegate alloc] initWithMethodChannel:self.channel];
+ [[FIAPPaymentQueueDelegate alloc] initWithMethodChannel:channelStub];
- OCMStub([self.channel invokeMethod:@"shouldShowPriceConsent"
- arguments:nil
- result:[OCMArg any]]);
+ channelStub.invokeMethodChannelWithResultsStub =
+ ^(NSString *_Nonnull method, id _Nonnull arguments, FlutterResult _Nullable result) {
+ XCTAssertEqualObjects(method, @"shouldShowPriceConsent");
+ XCTAssertNil(arguments);
+ };
BOOL shouldShow =
- [delegate paymentQueueShouldShowPriceConsent:OCMClassMock(SKPaymentQueue.class)];
+ [delegate paymentQueueShouldShowPriceConsent:[[SKPaymentQueueStub alloc] init]];
XCTAssertTrue(shouldShow);
}
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchasePluginTests.m b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchasePluginTests.m
index 8839bd2..1820ff8 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchasePluginTests.m
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchasePluginTests.m
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#import "FIAPaymentQueueHandler.h"
#import "RunnerTests-Swift.h"
@@ -12,8 +11,8 @@
@interface InAppPurchasePluginTest : XCTestCase
-@property(strong, nonatomic) FIAPReceiptManagerStub *receiptManagerStub;
-@property(strong, nonatomic) InAppPurchasePlugin *plugin;
+@property(nonatomic, strong) FIAPReceiptManagerStub *receiptManagerStub;
+@property(nonatomic, strong) InAppPurchasePlugin *plugin;
@end
@@ -23,8 +22,9 @@
self.receiptManagerStub = [FIAPReceiptManagerStub new];
self.plugin = [[InAppPurchasePluginStub alloc]
initWithReceiptManager:self.receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return [[FIAPRequestHandler alloc] initWithRequest:request];
+ handlerFactory:^DefaultRequestHandler *(SKRequest *request) {
+ return [[DefaultRequestHandler alloc]
+ initWithRequestHandler:[[FIAPRequestHandler alloc] initWithRequest:request]];
}];
}
@@ -40,23 +40,23 @@
- (void)testPaymentQueueStorefront {
if (@available(iOS 13, macOS 10.15, *)) {
- SKPaymentQueue *mockQueue = OCMClassMock(SKPaymentQueue.class);
NSDictionary *storefrontMap = @{
@"countryCode" : @"USA",
@"identifier" : @"unique_identifier",
};
+ PaymentQueueStub *queueStub = [[PaymentQueueStub alloc] init];
+ TransactionCacheStub *cache = [[TransactionCacheStub alloc] init];
- OCMStub(mockQueue.storefront).andReturn([[SKStorefrontStub alloc] initWithMap:storefrontMap]);
+ queueStub.storefront = [[SKStorefrontStub alloc] initWithMap:storefrontMap];
- self.plugin.paymentQueueHandler =
- [[FIAPaymentQueueHandler alloc] initWithQueue:mockQueue
- transactionsUpdated:nil
- transactionRemoved:nil
- restoreTransactionFailed:nil
- restoreCompletedTransactionsFinished:nil
- shouldAddStorePayment:nil
- updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
+ self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queueStub
+ transactionsUpdated:nil
+ transactionRemoved:nil
+ restoreTransactionFailed:nil
+ restoreCompletedTransactionsFinished:nil
+ shouldAddStorePayment:nil
+ updatedDownloads:nil
+ transactionCache:cache];
FlutterError *error;
SKStorefrontMessage *result = [self.plugin storefrontWithError:&error];
@@ -71,19 +71,17 @@
- (void)testPaymentQueueStorefrontReturnsNil {
if (@available(iOS 13, macOS 10.15, *)) {
- SKPaymentQueue *mockQueue = OCMClassMock(SKPaymentQueue.class);
+ PaymentQueueStub *queueStub = [[PaymentQueueStub alloc] init];
+ TransactionCacheStub *cache = [[TransactionCacheStub alloc] init];
- OCMStub(mockQueue.storefront).andReturn(nil);
-
- self.plugin.paymentQueueHandler =
- [[FIAPaymentQueueHandler alloc] initWithQueue:mockQueue
- transactionsUpdated:nil
- transactionRemoved:nil
- restoreTransactionFailed:nil
- restoreCompletedTransactionsFinished:nil
- shouldAddStorePayment:nil
- updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
+ self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queueStub
+ transactionsUpdated:nil
+ transactionRemoved:nil
+ restoreTransactionFailed:nil
+ restoreCompletedTransactionsFinished:nil
+ shouldAddStorePayment:nil
+ updatedDownloads:nil
+ transactionCache:cache];
FlutterError *error;
SKStorefrontMessage *resultMap = [self.plugin storefrontWithError:&error];
@@ -129,14 +127,23 @@
@"transactionTimeStamp" : @([NSDate date].timeIntervalSince1970),
};
- SKPaymentTransactionStub *paymentTransaction =
+ SKPaymentTransactionStub *paymentTransactionStub =
[[SKPaymentTransactionStub alloc] initWithMap:transactionMap];
- NSArray *array = @[ paymentTransaction ];
+ NSArray *array = @[ paymentTransactionStub ];
- FIAPaymentQueueHandler *mockHandler = OCMClassMock(FIAPaymentQueueHandler.class);
- OCMStub([mockHandler getUnfinishedTransactions]).andReturn(array);
+ PaymentQueueStub *queue = [[PaymentQueueStub alloc] init];
+ queue.transactions = array;
- self.plugin.paymentQueueHandler = mockHandler;
+ TransactionCacheStub *cache = [[TransactionCacheStub alloc] init];
+
+ self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
+ transactionsUpdated:nil
+ transactionRemoved:nil
+ restoreTransactionFailed:nil
+ restoreCompletedTransactionsFinished:nil
+ shouldAddStorePayment:nil
+ updatedDownloads:nil
+ transactionCache:cache];
FlutterError *error;
[self.plugin finishTransactionFinishMap:args error:&error];
@@ -167,13 +174,23 @@
@"transactionTimeStamp" : @([NSDate date].timeIntervalSince1970),
};
- SKPaymentTransactionStub *paymentTransaction =
+ SKPaymentTransactionStub *paymentTransactionStub =
[[SKPaymentTransactionStub alloc] initWithMap:transactionMap];
- FIAPaymentQueueHandler *mockHandler = OCMClassMock(FIAPaymentQueueHandler.class);
- OCMStub([mockHandler getUnfinishedTransactions]).andReturn(@[ paymentTransaction ]);
+ PaymentQueueStub *queueStub = [[PaymentQueueStub alloc] init];
+ queueStub.transactions = @[ paymentTransactionStub ];
- self.plugin.paymentQueueHandler = mockHandler;
+ TransactionCacheStub *cache = [[TransactionCacheStub alloc] init];
+
+ self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queueStub
+ transactionsUpdated:nil
+ transactionRemoved:nil
+ restoreTransactionFailed:nil
+ restoreCompletedTransactionsFinished:nil
+ shouldAddStorePayment:nil
+ updatedDownloads:nil
+ transactionCache:cache];
+ ;
FlutterError *error;
[self.plugin finishTransactionFinishMap:args error:&error];
@@ -186,20 +203,21 @@
XCTestExpectation *expectation =
[self expectationWithDescription:@"completion handler successfully called"];
- id mockHandler = OCMClassMock([FIAPRequestHandler class]);
+ RequestHandlerStub *handlerStub = [[RequestHandlerStub alloc] init];
InAppPurchasePlugin *plugin = [[InAppPurchasePlugin alloc]
initWithReceiptManager:_receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return mockHandler;
+ handlerFactory:^RequestHandlerStub *(SKRequest *request) {
+ return handlerStub;
}];
NSError *error = [NSError errorWithDomain:@"errorDomain"
code:0
userInfo:@{NSLocalizedDescriptionKey : @"description"}];
- OCMStub([mockHandler
- startProductRequestWithCompletionHandler:([OCMArg invokeBlockWithArgs:[NSNull null], error,
- nil])]);
+ handlerStub.startProductRequestWithCompletionHandlerStub =
+ ^(ProductRequestCompletion _Nonnull completion) {
+ completion(nil, error);
+ };
[plugin
startProductRequestProductIdentifiers:argument
@@ -220,28 +238,23 @@
XCTestExpectation *expectation =
[self expectationWithDescription:@"completion handler successfully called"];
- id mockHandler = OCMClassMock([FIAPRequestHandler class]);
-
+ RequestHandlerStub *handlerStub = [[RequestHandlerStub alloc] init];
InAppPurchasePlugin *plugin = [[InAppPurchasePlugin alloc]
initWithReceiptManager:_receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return mockHandler;
+ handlerFactory:^RequestHandlerStub *(SKRequest *request) {
+ return handlerStub;
}];
- NSError *error = [NSError errorWithDomain:@"errorDomain"
- code:0
- userInfo:@{NSLocalizedDescriptionKey : @"description"}];
-
- OCMStub([mockHandler
- startProductRequestWithCompletionHandler:([OCMArg invokeBlockWithArgs:[NSNull null],
- [NSNull null], nil])]);
+ handlerStub.startProductRequestWithCompletionHandlerStub =
+ ^(ProductRequestCompletion _Nonnull completion) {
+ completion(nil, nil);
+ };
[plugin
startProductRequestProductIdentifiers:argument
completion:^(SKProductsResponseMessage *_Nullable response,
FlutterError *_Nullable startProductRequestError) {
[expectation fulfill];
- XCTAssertNotNil(error);
XCTAssertNotNil(startProductRequestError);
XCTAssertEqualObjects(startProductRequestError.code,
@"storekit_platform_no_response");
@@ -256,15 +269,20 @@
@"simulatesAskToBuyInSandbox" : @YES,
};
- FIAPaymentQueueHandler *mockHandler = OCMClassMock(FIAPaymentQueueHandler.class);
- OCMStub([mockHandler addPayment:[OCMArg any]]).andReturn(NO);
- self.plugin.paymentQueueHandler = mockHandler;
+ PaymentQueueHandlerStub *handlerStub = [[PaymentQueueHandlerStub alloc] init];
+ self.plugin.paymentQueueHandler = handlerStub;
FlutterError *error;
+ __block NSInteger addPaymentInvokeCount = 0;
+ handlerStub.addPaymentStub = ^(SKPayment *payment) {
+ addPaymentInvokeCount += 1;
+ return NO;
+ };
+
[self.plugin addPaymentPaymentMap:argument error:&error];
- OCMVerify(times(1), [mockHandler addPayment:[OCMArg any]]);
+ XCTAssertEqual(addPaymentInvokeCount, 1);
XCTAssertEqualObjects(@"storekit_duplicate_product_object", error.code);
XCTAssertEqualObjects(@"There is a pending transaction for the same product identifier. "
@"Please either wait for it to be finished or finish it manually "
@@ -301,21 +319,24 @@
@"simulatesAskToBuyInSandbox" : @YES,
};
- FIAPaymentQueueHandler *mockHandler = OCMClassMock(FIAPaymentQueueHandler.class);
- OCMStub([mockHandler addPayment:[OCMArg any]]).andReturn(YES);
- self.plugin.paymentQueueHandler = mockHandler;
+ PaymentQueueHandlerStub *handlerStub = [[PaymentQueueHandlerStub alloc] init];
+ self.plugin.paymentQueueHandler = handlerStub;
+
+ __block NSInteger addPaymentInvokeCount = 0;
+ handlerStub.addPaymentStub = ^(SKPayment *payment) {
+ XCTAssert(payment != nil);
+ XCTAssertEqual(payment.productIdentifier, @"123");
+ XCTAssert(payment.quantity == 1);
+ addPaymentInvokeCount++;
+ return YES;
+ };
+
FlutterError *error;
[self.plugin addPaymentPaymentMap:argument error:&error];
XCTAssertNil(error);
- OCMVerify(times(1), [mockHandler addPayment:[OCMArg checkWithBlock:^BOOL(id obj) {
- SKPayment *payment = obj;
- XCTAssert(payment != nil);
- XCTAssertEqual(payment.productIdentifier, @"123");
- XCTAssert(payment.quantity == 1);
- return YES;
- }]]);
+ XCTAssertEqual(addPaymentInvokeCount, 1);
}
- (void)testAddPaymentSuccessWithPaymentDiscount {
@@ -332,43 +353,42 @@
}
};
- FIAPaymentQueueHandler *mockHandler = OCMClassMock(FIAPaymentQueueHandler.class);
- OCMStub([mockHandler addPayment:[OCMArg any]]).andReturn(YES);
- self.plugin.paymentQueueHandler = mockHandler;
+ PaymentQueueHandlerStub *handlerStub = [[PaymentQueueHandlerStub alloc] init];
+ self.plugin.paymentQueueHandler = handlerStub;
+
+ __block NSInteger addPaymentInvokeCount = 0;
+ handlerStub.addPaymentStub = ^(SKPayment *payment) {
+ if (@available(iOS 12.2, *)) {
+ SKPaymentDiscount *discount = payment.paymentDiscount;
+ XCTAssertEqual(discount.identifier, @"test_identifier");
+ XCTAssertEqual(discount.keyIdentifier, @"test_key_identifier");
+ XCTAssertEqualObjects(
+ discount.nonce,
+ [[NSUUID alloc] initWithUUIDString:@"4a11a9cc-3bc3-11ec-8d3d-0242ac130003"]);
+ XCTAssertEqual(discount.signature, @"test_signature");
+ addPaymentInvokeCount++;
+ return YES;
+ }
+ addPaymentInvokeCount++;
+ return YES;
+ };
FlutterError *error;
[self.plugin addPaymentPaymentMap:argument error:&error];
+ XCTAssertEqual(addPaymentInvokeCount, 1);
XCTAssertNil(error);
- OCMVerify(
- times(1),
- [mockHandler
- addPayment:[OCMArg checkWithBlock:^BOOL(id obj) {
- SKPayment *payment = obj;
- if (@available(iOS 12.2, *)) {
- SKPaymentDiscount *discount = payment.paymentDiscount;
-
- return [discount.identifier isEqual:@"test_identifier"] &&
- [discount.keyIdentifier isEqual:@"test_key_identifier"] &&
- [discount.nonce
- isEqual:[[NSUUID alloc]
- initWithUUIDString:@"4a11a9cc-3bc3-11ec-8d3d-0242ac130003"]] &&
- [discount.signature isEqual:@"test_signature"] &&
- [discount.timestamp isEqual:@(1635847102)];
- }
-
- return YES;
- }]]);
}
- (void)testAddPaymentFailureWithInvalidPaymentDiscount {
// Support for payment discount is only available on iOS 12.2 and higher.
if (@available(iOS 12.2, *)) {
- NSDictionary *argument = @{
+ NSDictionary *invalidDiscount = @{
@"productIdentifier" : @"123",
@"quantity" : @(1),
@"simulatesAskToBuyInSandbox" : @YES,
@"paymentDiscount" : @{
+ /// This payment discount is missing the field `identifier`, and is thus malformed
@"keyIdentifier" : @"test_key_identifier",
@"nonce" : @"4a11a9cc-3bc3-11ec-8d3d-0242ac130003",
@"signature" : @"test_signature",
@@ -376,25 +396,26 @@
}
};
- FIAPaymentQueueHandler *mockHandler = OCMClassMock(FIAPaymentQueueHandler.class);
- id translator = OCMClassMock(FIAObjectTranslator.class);
+ PaymentQueueHandlerStub *handlerStub = [[PaymentQueueHandlerStub alloc] init];
- NSString *errorMsg = @"Some error occurred";
- OCMStub(ClassMethod([translator
- getSKPaymentDiscountFromMap:[OCMArg any]
- withError:(NSString __autoreleasing **)[OCMArg setTo:errorMsg]]))
- .andReturn(nil);
- self.plugin.paymentQueueHandler = mockHandler;
+ __block NSInteger addPaymentCount = 0;
+ handlerStub.addPaymentStub = ^BOOL(SKPayment *_Nonnull payment) {
+ addPaymentCount++;
+ return YES;
+ };
+
+ self.plugin.paymentQueueHandler = handlerStub;
FlutterError *error;
- [self.plugin addPaymentPaymentMap:argument error:&error];
+ [self.plugin addPaymentPaymentMap:invalidDiscount error:&error];
XCTAssertEqualObjects(@"storekit_invalid_payment_discount_object", error.code);
XCTAssertEqualObjects(@"You have requested a payment and specified a "
- @"payment discount with invalid properties. Some error occurred",
+ @"payment discount with invalid properties. When specifying a payment "
+ @"discount the 'identifier' field is mandatory.",
error.message);
- XCTAssertEqualObjects(argument, error.details);
- OCMVerify(never(), [mockHandler addPayment:[OCMArg any]]);
+ XCTAssertEqualObjects(invalidDiscount, error.details);
+ XCTAssertEqual(0, addPaymentCount);
}
}
@@ -405,27 +426,30 @@
@"simulatesAskToBuyInSandbox" : [NSNull null],
};
- FIAPaymentQueueHandler *mockHandler = OCMClassMock(FIAPaymentQueueHandler.class);
- OCMStub([mockHandler addPayment:[OCMArg any]]).andReturn(YES);
- self.plugin.paymentQueueHandler = mockHandler;
+ PaymentQueueHandlerStub *handlerStub = [[PaymentQueueHandlerStub alloc] init];
+ self.plugin.paymentQueueHandler = handlerStub;
FlutterError *error;
+ __block NSInteger addPaymentInvokeCount = 0;
+ handlerStub.addPaymentStub = ^(SKPayment *payment) {
+ XCTAssertEqual(payment.simulatesAskToBuyInSandbox, false);
+ addPaymentInvokeCount++;
+ return YES;
+ };
+
[self.plugin addPaymentPaymentMap:argument error:&error];
- OCMVerify(times(1), [mockHandler addPayment:[OCMArg checkWithBlock:^BOOL(id obj) {
- SKPayment *payment = obj;
- return !payment.simulatesAskToBuyInSandbox;
- }]]);
+ XCTAssertEqual(addPaymentInvokeCount, 1);
}
- (void)testRestoreTransactions {
XCTestExpectation *expectation =
[self expectationWithDescription:@"result successfully restore transactions"];
- SKPaymentQueueStub *queue = [SKPaymentQueueStub new];
- queue.testState = SKPaymentTransactionStatePurchased;
+ TransactionCacheStub *cacheStub = [[TransactionCacheStub alloc] init];
+ PaymentQueueStub *queueStub = [[PaymentQueueStub alloc] init];
__block BOOL callbackInvoked = NO;
- self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
+ self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queueStub
transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
}
transactionRemoved:nil
@@ -436,8 +460,8 @@
}
shouldAddStorePayment:nil
updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
- [queue addTransactionObserver:self.plugin.paymentQueueHandler];
+ transactionCache:cacheStub];
+ [queueStub addTransactionObserver:self.plugin.paymentQueueHandler];
FlutterError *error;
[self.plugin restoreTransactionsApplicationUserName:nil error:&error];
@@ -454,8 +478,8 @@
}
- (void)testRetrieveReceiptDataNil {
- NSBundle *mockBundle = OCMPartialMock([NSBundle mainBundle]);
- OCMStub(mockBundle.appStoreReceiptURL).andReturn(nil);
+ self.receiptManagerStub.returnNilURL = YES;
+
FlutterError *error;
NSString *result = [self.plugin retrieveReceiptDataWithError:&error];
XCTAssertNil(result);
@@ -480,20 +504,21 @@
XCTestExpectation *expectation =
[self expectationWithDescription:@"completion handler successfully called"];
- id mockHandler = OCMClassMock([FIAPRequestHandler class]);
+ RequestHandlerStub *handlerStub = [[RequestHandlerStub alloc] init];
InAppPurchasePlugin *plugin = [[InAppPurchasePlugin alloc]
initWithReceiptManager:_receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return mockHandler;
+ handlerFactory:^RequestHandlerStub *(SKRequest *request) {
+ return handlerStub;
}];
NSError *recieptError = [NSError errorWithDomain:@"errorDomain"
code:0
userInfo:@{NSLocalizedDescriptionKey : @"description"}];
- OCMStub([mockHandler
- startProductRequestWithCompletionHandler:([OCMArg invokeBlockWithArgs:[NSNull null],
- recieptError, nil])]);
+ handlerStub.startProductRequestWithCompletionHandlerStub =
+ ^(ProductRequestCompletion _Nonnull completion) {
+ completion(nil, recieptError);
+ };
[plugin refreshReceiptReceiptProperties:nil
completion:^(FlutterError *_Nullable error) {
@@ -512,20 +537,21 @@
XCTestExpectation *expectation =
[self expectationWithDescription:@"completion handler successfully called"];
- id mockHandler = OCMClassMock([FIAPRequestHandler class]);
+ RequestHandlerStub *handlerStub = [[RequestHandlerStub alloc] init];
InAppPurchasePlugin *plugin = [[InAppPurchasePlugin alloc]
initWithReceiptManager:_receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return mockHandler;
+ handlerFactory:^RequestHandlerStub *(SKRequest *request) {
+ return handlerStub;
}];
NSError *recieptError = [NSError errorWithDomain:@"errorDomain"
code:0
userInfo:@{NSLocalizedDescriptionKey : @"description"}];
- OCMStub([mockHandler
- startProductRequestWithCompletionHandler:([OCMArg invokeBlockWithArgs:[NSNull null],
- recieptError, nil])]);
+ handlerStub.startProductRequestWithCompletionHandlerStub =
+ ^(ProductRequestCompletion _Nonnull completion) {
+ completion(nil, recieptError);
+ };
[plugin refreshReceiptReceiptProperties:properties
completion:^(FlutterError *_Nullable error) {
@@ -544,20 +570,21 @@
XCTestExpectation *expectation =
[self expectationWithDescription:@"completion handler successfully called"];
- id mockHandler = OCMClassMock([FIAPRequestHandler class]);
+ RequestHandlerStub *handlerStub = [[RequestHandlerStub alloc] init];
InAppPurchasePlugin *plugin = [[InAppPurchasePlugin alloc]
initWithReceiptManager:_receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return mockHandler;
+ handlerFactory:^RequestHandlerStub *(SKRequest *request) {
+ return handlerStub;
}];
NSError *recieptError = [NSError errorWithDomain:@"errorDomain"
code:0
userInfo:@{NSLocalizedDescriptionKey : @"description"}];
- OCMStub([mockHandler
- startProductRequestWithCompletionHandler:([OCMArg invokeBlockWithArgs:[NSNull null],
- recieptError, nil])]);
+ handlerStub.startProductRequestWithCompletionHandlerStub =
+ ^(ProductRequestCompletion _Nonnull completion) {
+ completion(nil, recieptError);
+ };
[plugin refreshReceiptReceiptProperties:properties
completion:^(FlutterError *_Nullable error) {
@@ -572,18 +599,24 @@
/// presentCodeRedemptionSheetWithError:error is only available on iOS
#if TARGET_OS_IOS
- (void)testPresentCodeRedemptionSheet {
- FIAPaymentQueueHandler *mockHandler = OCMClassMock([FIAPaymentQueueHandler class]);
- self.plugin.paymentQueueHandler = mockHandler;
+ PaymentQueueHandlerStub *handlerStub = [[PaymentQueueHandlerStub alloc] init];
+ self.plugin.paymentQueueHandler = handlerStub;
+
+ __block NSInteger presentCodeRedemptionSheetCount = 0;
+ handlerStub.presentCodeRedemptionSheetStub = ^{
+ presentCodeRedemptionSheetCount++;
+ };
FlutterError *error;
[self.plugin presentCodeRedemptionSheetWithError:&error];
- OCMVerify(times(1), [mockHandler presentCodeRedemptionSheet]);
+ XCTAssertEqual(1, presentCodeRedemptionSheetCount);
}
#endif
- (void)testGetPendingTransactions {
- SKPaymentQueue *mockQueue = OCMClassMock(SKPaymentQueue.class);
+ PaymentQueueStub *queueStub = [[PaymentQueueStub alloc] init];
+ TransactionCacheStub *cacheStub = [[TransactionCacheStub alloc] init];
NSDictionary *transactionMap = @{
@"transactionIdentifier" : [NSNull null],
@"transactionState" : @(SKPaymentTransactionStatePurchasing),
@@ -594,18 +627,15 @@
@"transactionTimeStamp" : @([NSDate date].timeIntervalSince1970),
@"originalTransaction" : [NSNull null],
};
- OCMStub(mockQueue.transactions).andReturn(@[ [[SKPaymentTransactionStub alloc]
- initWithMap:transactionMap] ]);
-
- self.plugin.paymentQueueHandler =
- [[FIAPaymentQueueHandler alloc] initWithQueue:mockQueue
- transactionsUpdated:nil
- transactionRemoved:nil
- restoreTransactionFailed:nil
- restoreCompletedTransactionsFinished:nil
- shouldAddStorePayment:nil
- updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
+ queueStub.transactions = @[ [[SKPaymentTransactionStub alloc] initWithMap:transactionMap] ];
+ self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queueStub
+ transactionsUpdated:nil
+ transactionRemoved:nil
+ restoreTransactionFailed:nil
+ restoreCompletedTransactionsFinished:nil
+ shouldAddStorePayment:nil
+ updatedDownloads:nil
+ transactionCache:cacheStub];
FlutterError *error;
SKPaymentTransactionStub *original =
[[SKPaymentTransactionStub alloc] initWithMap:transactionMap];
@@ -619,45 +649,50 @@
}
- (void)testStartObservingPaymentQueue {
- FIAPaymentQueueHandler *mockHandler = OCMClassMock([FIAPaymentQueueHandler class]);
- self.plugin.paymentQueueHandler = mockHandler;
+ PaymentQueueHandlerStub *handlerStub = [[PaymentQueueHandlerStub alloc] init];
+ self.plugin.paymentQueueHandler = handlerStub;
+
+ __block NSInteger startObservingCount = 0;
+ handlerStub.startObservingPaymentQueueStub = ^{
+ startObservingCount++;
+ };
FlutterError *error;
[self.plugin startObservingPaymentQueueWithError:&error];
- OCMVerify(times(1), [mockHandler startObservingPaymentQueue]);
+ XCTAssertEqual(1, startObservingCount);
}
- (void)testStopObservingPaymentQueue {
- FIAPaymentQueueHandler *mockHandler = OCMClassMock([FIAPaymentQueueHandler class]);
- self.plugin.paymentQueueHandler = mockHandler;
+ PaymentQueueHandlerStub *handlerStub = [[PaymentQueueHandlerStub alloc] init];
+ self.plugin.paymentQueueHandler = handlerStub;
+
+ __block NSInteger stopObservingCount = 0;
+ handlerStub.stopObservingPaymentQueueStub = ^{
+ stopObservingCount++;
+ };
FlutterError *error;
[self.plugin stopObservingPaymentQueueWithError:&error];
- OCMVerify(times(1), [mockHandler stopObservingPaymentQueue]);
+ XCTAssertEqual(1, stopObservingCount);
}
#if TARGET_OS_IOS
- (void)testRegisterPaymentQueueDelegate {
+ TransactionCacheStub *cacheStub = [[TransactionCacheStub alloc] init];
+ PaymentQueueStub *queueStub = [[PaymentQueueStub alloc] init];
if (@available(iOS 13, *)) {
- self.plugin.paymentQueueHandler =
- [[FIAPaymentQueueHandler alloc] initWithQueue:[SKPaymentQueueStub new]
- transactionsUpdated:nil
- transactionRemoved:nil
- restoreTransactionFailed:nil
- restoreCompletedTransactionsFinished:nil
- shouldAddStorePayment:nil
- updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
+ self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queueStub
+ transactionsUpdated:nil
+ transactionRemoved:nil
+ restoreTransactionFailed:nil
+ restoreCompletedTransactionsFinished:nil
+ shouldAddStorePayment:nil
+ updatedDownloads:nil
+ transactionCache:cacheStub];
- self.plugin.registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar));
-
- id<FlutterPluginRegistrar> registrarMock = OCMProtocolMock(@protocol(FlutterPluginRegistrar));
- self.plugin.registrar = registrarMock;
-
- id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
- OCMStub([registrarMock messenger]).andReturn(binaryMessengerMock);
+ self.plugin.registrar = [[FlutterPluginRegistrarStub alloc] init];
// Verify the delegate is nil before we register one.
XCTAssertNil(self.plugin.paymentQueueHandler.delegate);
@@ -672,21 +707,28 @@
- (void)testRemovePaymentQueueDelegate {
if (@available(iOS 13, *)) {
- self.plugin.paymentQueueHandler =
- [[FIAPaymentQueueHandler alloc] initWithQueue:[SKPaymentQueueStub new]
- transactionsUpdated:nil
- transactionRemoved:nil
- restoreTransactionFailed:nil
- restoreCompletedTransactionsFinished:nil
- shouldAddStorePayment:nil
- updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
- self.plugin.paymentQueueHandler.delegate = OCMProtocolMock(@protocol(SKPaymentQueueDelegate));
+ TransactionCacheStub *cacheStub = [[TransactionCacheStub alloc] init];
+ PaymentQueueStub *queueStub = [[PaymentQueueStub alloc] init];
+ self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queueStub
+ transactionsUpdated:nil
+ transactionRemoved:nil
+ restoreTransactionFailed:nil
+ restoreCompletedTransactionsFinished:nil
+ shouldAddStorePayment:nil
+ updatedDownloads:nil
+ transactionCache:cacheStub];
+
+ self.plugin.registrar = [[FlutterPluginRegistrarStub alloc] init];
+
+ // Verify the delegate is nil before we register one.
+ XCTAssertNil(self.plugin.paymentQueueHandler.delegate);
+
+ FlutterError *error;
+ [self.plugin registerPaymentQueueDelegateWithError:&error];
// Verify the delegate is not nil before removing it.
XCTAssertNotNil(self.plugin.paymentQueueHandler.delegate);
- FlutterError *error;
[self.plugin removePaymentQueueDelegateWithError:&error];
// Verify the delegate is nill after removing it.
@@ -708,21 +750,30 @@
InAppPurchasePlugin *plugin = [[InAppPurchasePluginStub alloc]
initWithReceiptManager:self.receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return [[FIAPRequestHandler alloc] initWithRequest:request];
+ handlerFactory:^DefaultRequestHandler *(SKRequest *request) {
+ return [[DefaultRequestHandler alloc]
+ initWithRequestHandler:[[FIAPRequestHandler alloc] initWithRequest:request]];
}];
- FlutterMethodChannel *mockChannel = OCMClassMock([FlutterMethodChannel class]);
- plugin.transactionObserverCallbackChannel = mockChannel;
- OCMStub([mockChannel invokeMethod:[OCMArg any] arguments:[OCMArg any]]);
+ MethodChannelStub *channelStub = [[MethodChannelStub alloc] init];
+ __block NSInteger invokeMethodCount = 0;
- SKPaymentTransactionStub *paymentTransaction =
+ channelStub.invokeMethodChannelStub = ^(NSString *_Nonnull method, id _Nonnull arguments) {
+ XCTAssertEqualObjects(@"updatedTransactions", method);
+ XCTAssertNotNil(arguments);
+ invokeMethodCount++;
+ };
+
+ // (TODO: louisehsu) Change this to inject the channel, like requestHandler
+ plugin.transactionObserverCallbackChannel = channelStub;
+
+ SKPaymentTransactionStub *paymentTransactionStub =
[[SKPaymentTransactionStub alloc] initWithMap:transactionMap];
- NSArray *array = [NSArray arrayWithObjects:paymentTransaction, nil];
+ NSArray *array = [NSArray arrayWithObjects:paymentTransactionStub, nil];
NSMutableArray *maps = [NSMutableArray new];
- [maps addObject:[FIAObjectTranslator getMapFromSKPaymentTransaction:paymentTransaction]];
+ [maps addObject:[FIAObjectTranslator getMapFromSKPaymentTransaction:paymentTransactionStub]];
[plugin handleTransactionsUpdated:array];
- OCMVerify(times(1), [mockChannel invokeMethod:@"updatedTransactions" arguments:[OCMArg any]]);
+ XCTAssertEqual(invokeMethodCount, 1);
}
- (void)testHandleTransactionsRemoved {
@@ -738,52 +789,76 @@
InAppPurchasePlugin *plugin = [[InAppPurchasePluginStub alloc]
initWithReceiptManager:self.receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return [[FIAPRequestHandler alloc] initWithRequest:request];
+ handlerFactory:^DefaultRequestHandler *(SKRequest *request) {
+ return [[DefaultRequestHandler alloc]
+ initWithRequestHandler:[[FIAPRequestHandler alloc] initWithRequest:request]];
}];
- FlutterMethodChannel *mockChannel = OCMClassMock([FlutterMethodChannel class]);
- plugin.transactionObserverCallbackChannel = mockChannel;
- OCMStub([mockChannel invokeMethod:[OCMArg any] arguments:[OCMArg any]]);
-
- SKPaymentTransactionStub *paymentTransaction =
+ SKPaymentTransactionStub *paymentTransactionStub =
[[SKPaymentTransactionStub alloc] initWithMap:transactionMap];
- NSArray *array = [NSArray arrayWithObjects:paymentTransaction, nil];
+ NSArray *array = [NSArray arrayWithObjects:paymentTransactionStub, nil];
NSMutableArray *maps = [NSMutableArray new];
- [maps addObject:[FIAObjectTranslator getMapFromSKPaymentTransaction:paymentTransaction]];
+ [maps addObject:[FIAObjectTranslator getMapFromSKPaymentTransaction:paymentTransactionStub]];
+
+ MethodChannelStub *channelStub = [[MethodChannelStub alloc] init];
+ __block NSInteger invokeMethodCount = 0;
+
+ channelStub.invokeMethodChannelStub = ^(NSString *_Nonnull method, id _Nonnull arguments) {
+ XCTAssertEqualObjects(@"removedTransactions", method);
+ XCTAssertEqualObjects(maps, arguments);
+ invokeMethodCount++;
+ };
+
+ // (TODO: louisehsu) Change this to inject the channel, like requestHandler
+ plugin.transactionObserverCallbackChannel = channelStub;
[plugin handleTransactionsRemoved:array];
- OCMVerify(times(1), [mockChannel invokeMethod:@"removedTransactions" arguments:maps]);
+ XCTAssertEqual(invokeMethodCount, 1);
}
- (void)testHandleTransactionRestoreFailed {
InAppPurchasePlugin *plugin = [[InAppPurchasePluginStub alloc]
initWithReceiptManager:self.receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return [[FIAPRequestHandler alloc] initWithRequest:request];
+ handlerFactory:^DefaultRequestHandler *(SKRequest *request) {
+ return [[DefaultRequestHandler alloc]
+ initWithRequestHandler:[[FIAPRequestHandler alloc] initWithRequest:request]];
}];
- FlutterMethodChannel *mockChannel = OCMClassMock([FlutterMethodChannel class]);
- plugin.transactionObserverCallbackChannel = mockChannel;
- OCMStub([mockChannel invokeMethod:[OCMArg any] arguments:[OCMArg any]]);
-
+ MethodChannelStub *channelStub = [[MethodChannelStub alloc] init];
+ __block NSInteger invokeMethodCount = 0;
NSError *error = [NSError errorWithDomain:@"error" code:0 userInfo:nil];
+
+ channelStub.invokeMethodChannelStub = ^(NSString *_Nonnull method, id _Nonnull arguments) {
+ XCTAssertEqualObjects(@"restoreCompletedTransactionsFailed", method);
+ XCTAssertEqualObjects([FIAObjectTranslator getMapFromNSError:error], arguments);
+ invokeMethodCount++;
+ };
+
+ // (TODO: louisehsu) Change this to inject the channel, like requestHandler
+ plugin.transactionObserverCallbackChannel = channelStub;
+
[plugin handleTransactionRestoreFailed:error];
- OCMVerify(times(1), [mockChannel invokeMethod:@"restoreCompletedTransactionsFailed"
- arguments:[FIAObjectTranslator getMapFromNSError:error]]);
+ XCTAssertEqual(invokeMethodCount, 1);
}
- (void)testRestoreCompletedTransactionsFinished {
InAppPurchasePlugin *plugin = [[InAppPurchasePluginStub alloc]
initWithReceiptManager:self.receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return [[FIAPRequestHandler alloc] initWithRequest:request];
+ handlerFactory:^DefaultRequestHandler *(SKRequest *request) {
+ return [[DefaultRequestHandler alloc]
+ initWithRequestHandler:[[FIAPRequestHandler alloc] initWithRequest:request]];
}];
- FlutterMethodChannel *mockChannel = OCMClassMock([FlutterMethodChannel class]);
- plugin.transactionObserverCallbackChannel = mockChannel;
- OCMStub([mockChannel invokeMethod:[OCMArg any] arguments:[OCMArg any]]);
+ MethodChannelStub *channelStub = [[MethodChannelStub alloc] init];
+ __block NSInteger invokeMethodCount = 0;
+ channelStub.invokeMethodChannelStub = ^(NSString *_Nonnull method, id _Nonnull arguments) {
+ XCTAssertEqualObjects(@"paymentQueueRestoreCompletedTransactionsFinished", method);
+ XCTAssertNil(arguments);
+ invokeMethodCount++;
+ };
+
+ // (TODO: louisehsu) Change this to inject the channel, like requestHandler
+ plugin.transactionObserverCallbackChannel = channelStub;
[plugin restoreCompletedTransactionsFinished];
- OCMVerify(times(1), [mockChannel invokeMethod:@"paymentQueueRestoreCompletedTransactionsFinished"
- arguments:nil]);
+ XCTAssertEqual(invokeMethodCount, 1);
}
- (void)testShouldAddStorePayment {
@@ -804,41 +879,65 @@
};
SKMutablePayment *payment = [FIAObjectTranslator getSKMutablePaymentFromMap:paymentMap];
- SKProductStub *product = [[SKProductStub alloc] initWithMap:productMap];
+ SKProductStub *productStub = [[SKProductStub alloc] initWithMap:productMap];
InAppPurchasePlugin *plugin = [[InAppPurchasePluginStub alloc]
initWithReceiptManager:self.receiptManagerStub
- handlerFactory:^FIAPRequestHandler *(SKRequest *request) {
- return [[FIAPRequestHandler alloc] initWithRequest:request];
+ handlerFactory:^DefaultRequestHandler *(SKRequest *request) {
+ return [[DefaultRequestHandler alloc]
+ initWithRequestHandler:[[FIAPRequestHandler alloc] initWithRequest:request]];
}];
- FlutterMethodChannel *mockChannel = OCMClassMock([FlutterMethodChannel class]);
- plugin.transactionObserverCallbackChannel = mockChannel;
- OCMStub([mockChannel invokeMethod:[OCMArg any] arguments:[OCMArg any]]);
NSDictionary *args = @{
@"payment" : [FIAObjectTranslator getMapFromSKPayment:payment],
- @"product" : [FIAObjectTranslator getMapFromSKProduct:product]
+ @"product" : [FIAObjectTranslator getMapFromSKProduct:productStub]
};
- BOOL result = [plugin shouldAddStorePaymentWithPayment:payment product:product];
+ MethodChannelStub *channelStub = [[MethodChannelStub alloc] init];
+
+ __block NSInteger invokeMethodCount = 0;
+ channelStub.invokeMethodChannelStub = ^(NSString *_Nonnull method, id _Nonnull arguments) {
+ XCTAssertEqualObjects(@"shouldAddStorePayment", method);
+ XCTAssertEqualObjects(args, arguments);
+ invokeMethodCount++;
+ };
+
+ // (TODO: louisehsu) Change this to inject the channel, like requestHandler
+ plugin.transactionObserverCallbackChannel = channelStub;
+
+ BOOL result = [plugin shouldAddStorePaymentWithPayment:payment product:productStub];
XCTAssertEqual(result, NO);
- OCMVerify(times(1), [mockChannel invokeMethod:@"shouldAddStorePayment" arguments:args]);
+ XCTAssertEqual(invokeMethodCount, 1);
}
#if TARGET_OS_IOS
- (void)testShowPriceConsentIfNeeded {
- FIAPaymentQueueHandler *mockQueueHandler = OCMClassMock(FIAPaymentQueueHandler.class);
- self.plugin.paymentQueueHandler = mockQueueHandler;
+ TransactionCacheStub *cacheStub = [[TransactionCacheStub alloc] init];
+ PaymentQueueStub *queueStub = [[PaymentQueueStub alloc] init];
+ self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queueStub
+ transactionsUpdated:nil
+ transactionRemoved:nil
+ restoreTransactionFailed:nil
+ restoreCompletedTransactionsFinished:nil
+ shouldAddStorePayment:nil
+ updatedDownloads:nil
+ transactionCache:cacheStub];
FlutterError *error;
+ __block NSInteger showPriceConsentIfNeededCount = 0;
+
+ queueStub.showPriceConsentIfNeededStub = ^(void) {
+ showPriceConsentIfNeededCount++;
+ };
+
[self.plugin showPriceConsentIfNeededWithError:&error];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpartial-availability"
if (@available(iOS 13.4, *)) {
- OCMVerify(times(1), [mockQueueHandler showPriceConsentIfNeeded]);
+ XCTAssertEqual(showPriceConsentIfNeededCount, 1);
} else {
- OCMVerify(never(), [mockQueueHandler showPriceConsentIfNeeded]);
+ XCTAssertEqual(showPriceConsentIfNeededCount, 0);
}
#pragma clang diagnostic pop
}
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/PaymentQueueTests.m b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/PaymentQueueTests.m
index 2f8d585..0c6d51a 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/PaymentQueueTests.m
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/PaymentQueueTests.m
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#import "Stubs.h"
@@ -10,10 +9,10 @@
@interface PaymentQueueTest : XCTestCase
-@property(strong, nonatomic) NSDictionary *periodMap;
-@property(strong, nonatomic) NSDictionary *discountMap;
-@property(strong, nonatomic) NSDictionary *productMap;
-@property(strong, nonatomic) NSDictionary *productResponseMap;
+@property(nonatomic, strong) NSDictionary *periodMap;
+@property(nonatomic, strong) NSDictionary *discountMap;
+@property(nonatomic, strong) NSDictionary *productMap;
+@property(nonatomic, strong) NSDictionary *productResponseMap;
@end
@@ -45,7 +44,7 @@
- (void)testTransactionPurchased {
XCTestExpectation *expectation =
[self expectationWithDescription:@"expect to get purchased transcation."];
- SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
+ PaymentQueueStub *queue = [[PaymentQueueStub alloc] init];
queue.testState = SKPaymentTransactionStatePurchased;
__block SKPaymentTransactionStub *tran;
FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
@@ -61,20 +60,20 @@
return YES;
}
updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
+ transactionCache:[[TransactionCacheStub alloc] init]];
SKPayment *payment =
[SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
[handler startObservingPaymentQueue];
[handler addPayment:payment];
[self waitForExpectations:@[ expectation ] timeout:5];
XCTAssertEqual(tran.transactionState, SKPaymentTransactionStatePurchased);
- XCTAssertEqual(tran.transactionIdentifier, @"fakeID");
+ XCTAssertEqualObjects(tran.transactionIdentifier, @"fakeID");
}
- (void)testTransactionFailed {
XCTestExpectation *expectation =
[self expectationWithDescription:@"expect to get failed transcation."];
- SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
+ PaymentQueueStub *queue = [[PaymentQueueStub alloc] init];
queue.testState = SKPaymentTransactionStateFailed;
__block SKPaymentTransactionStub *tran;
FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
@@ -90,7 +89,7 @@
return YES;
}
updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
+ transactionCache:[[TransactionCacheStub alloc] init]];
SKPayment *payment =
[SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
@@ -104,7 +103,7 @@
- (void)testTransactionRestored {
XCTestExpectation *expectation =
[self expectationWithDescription:@"expect to get restored transcation."];
- SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
+ PaymentQueueStub *queue = [[PaymentQueueStub alloc] init];
queue.testState = SKPaymentTransactionStateRestored;
__block SKPaymentTransactionStub *tran;
FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
@@ -120,7 +119,7 @@
return YES;
}
updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
+ transactionCache:[[TransactionCacheStub alloc] init]];
SKPayment *payment =
[SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
@@ -128,13 +127,13 @@
[handler addPayment:payment];
[self waitForExpectations:@[ expectation ] timeout:5];
XCTAssertEqual(tran.transactionState, SKPaymentTransactionStateRestored);
- XCTAssertEqual(tran.transactionIdentifier, @"fakeID");
+ XCTAssertEqualObjects(tran.transactionIdentifier, @"fakeID");
}
- (void)testTransactionPurchasing {
XCTestExpectation *expectation =
[self expectationWithDescription:@"expect to get purchasing transcation."];
- SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
+ PaymentQueueStub *queue = [[PaymentQueueStub alloc] init];
queue.testState = SKPaymentTransactionStatePurchasing;
__block SKPaymentTransactionStub *tran;
FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
@@ -150,7 +149,7 @@
return YES;
}
updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
+ transactionCache:[[TransactionCacheStub alloc] init]];
SKPayment *payment =
[SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
@@ -164,7 +163,7 @@
- (void)testTransactionDeferred {
XCTestExpectation *expectation =
[self expectationWithDescription:@"expect to get deffered transcation."];
- SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
+ PaymentQueueStub *queue = [[PaymentQueueStub alloc] init];
queue.testState = SKPaymentTransactionStateDeferred;
__block SKPaymentTransactionStub *tran;
FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
@@ -180,7 +179,7 @@
return YES;
}
updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
+ transactionCache:[[TransactionCacheStub alloc] init]];
SKPayment *payment =
[SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
[handler startObservingPaymentQueue];
@@ -193,7 +192,7 @@
- (void)testFinishTransaction {
XCTestExpectation *expectation =
[self expectationWithDescription:@"handler.transactions should be empty."];
- SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
+ PaymentQueueStub *queue = [[PaymentQueueStub alloc] init];
queue.testState = SKPaymentTransactionStateDeferred;
__block FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
@@ -211,7 +210,7 @@
return YES;
}
updatedDownloads:nil
- transactionCache:OCMClassMock(FIATransactionCache.class)];
+ transactionCache:[[TransactionCacheStub alloc] init]];
SKPayment *payment =
[SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
[handler startObservingPaymentQueue];
@@ -220,9 +219,9 @@
}
- (void)testStartObservingPaymentQueueShouldNotProcessTransactionsWhenCacheIsEmpty {
- FIATransactionCache *mockCache = OCMClassMock(FIATransactionCache.class);
+ TransactionCacheStub *cacheStub = [[TransactionCacheStub alloc] init];
FIAPaymentQueueHandler *handler =
- [[FIAPaymentQueueHandler alloc] initWithQueue:[[SKPaymentQueueStub alloc] init]
+ [[FIAPaymentQueueHandler alloc] initWithQueue:[[PaymentQueueStub alloc] init]
transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
XCTFail("transactionsUpdated callback should not be called when cache is empty.");
}
@@ -237,20 +236,41 @@
updatedDownloads:^(NSArray<SKDownload *> *_Nonnull downloads) {
XCTFail("updatedDownloads callback should not be called when cache is empty.");
}
- transactionCache:mockCache];
+ transactionCache:cacheStub];
+
+ __block NSInteger TransactionCacheKeyUpdatedTransactionsInvokedCount = 0;
+ __block NSInteger TransactionCacheKeyUpdatedDownloadsInvokedCount = 0;
+ __block NSInteger TransactionCacheKeyRemovedTransactionsInvokedCount = 0;
+
+ cacheStub.getObjectsForKeyStub = ^NSArray *_Nonnull(TransactionCacheKey key) {
+ switch (key) {
+ case TransactionCacheKeyUpdatedTransactions:
+ TransactionCacheKeyUpdatedTransactionsInvokedCount++;
+ break;
+ case TransactionCacheKeyUpdatedDownloads:
+ TransactionCacheKeyUpdatedDownloadsInvokedCount++;
+ break;
+ case TransactionCacheKeyRemovedTransactions:
+ TransactionCacheKeyRemovedTransactionsInvokedCount++;
+ break;
+ default:
+ XCTFail("Invalid transaction state was invoked.");
+ }
+ return nil;
+ };
[handler startObservingPaymentQueue];
- OCMVerify(times(1), [mockCache getObjectsForKey:TransactionCacheKeyUpdatedTransactions]);
- OCMVerify(times(1), [mockCache getObjectsForKey:TransactionCacheKeyUpdatedDownloads]);
- OCMVerify(times(1), [mockCache getObjectsForKey:TransactionCacheKeyRemovedTransactions]);
+ XCTAssertEqual(1, TransactionCacheKeyUpdatedTransactionsInvokedCount);
+ XCTAssertEqual(1, TransactionCacheKeyUpdatedDownloadsInvokedCount);
+ XCTAssertEqual(1, TransactionCacheKeyRemovedTransactionsInvokedCount);
}
- (void)
testStartObservingPaymentQueueShouldNotProcessTransactionsWhenCacheContainsEmptyTransactionArrays {
- FIATransactionCache *mockCache = OCMClassMock(FIATransactionCache.class);
+ TransactionCacheStub *cacheStub = [[TransactionCacheStub alloc] init];
FIAPaymentQueueHandler *handler =
- [[FIAPaymentQueueHandler alloc] initWithQueue:[[SKPaymentQueueStub alloc] init]
+ [[FIAPaymentQueueHandler alloc] initWithQueue:[[PaymentQueueStub alloc] init]
transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
XCTFail("transactionsUpdated callback should not be called when cache is empty.");
}
@@ -265,17 +285,36 @@
updatedDownloads:^(NSArray<SKDownload *> *_Nonnull downloads) {
XCTFail("updatedDownloads callback should not be called when cache is empty.");
}
- transactionCache:mockCache];
+ transactionCache:cacheStub];
- OCMStub([mockCache getObjectsForKey:TransactionCacheKeyUpdatedTransactions]).andReturn(@[]);
- OCMStub([mockCache getObjectsForKey:TransactionCacheKeyUpdatedDownloads]).andReturn(@[]);
- OCMStub([mockCache getObjectsForKey:TransactionCacheKeyRemovedTransactions]).andReturn(@[]);
+ __block NSInteger TransactionCacheKeyUpdatedTransactionsInvokedCount = 0;
+ __block NSInteger TransactionCacheKeyUpdatedDownloadsInvokedCount = 0;
+ __block NSInteger TransactionCacheKeyRemovedTransactionsInvokedCount = 0;
+
+ cacheStub.getObjectsForKeyStub = ^NSArray *_Nonnull(TransactionCacheKey key) {
+ switch (key) {
+ case TransactionCacheKeyUpdatedTransactions:
+ TransactionCacheKeyUpdatedTransactionsInvokedCount++;
+ return @[];
+ break;
+ case TransactionCacheKeyUpdatedDownloads:
+ TransactionCacheKeyUpdatedDownloadsInvokedCount++;
+ return @[];
+ break;
+ case TransactionCacheKeyRemovedTransactions:
+ TransactionCacheKeyRemovedTransactionsInvokedCount++;
+ return @[];
+ break;
+ default:
+ XCTFail("Invalid transaction state was invoked.");
+ }
+ };
[handler startObservingPaymentQueue];
- OCMVerify(times(1), [mockCache getObjectsForKey:TransactionCacheKeyUpdatedTransactions]);
- OCMVerify(times(1), [mockCache getObjectsForKey:TransactionCacheKeyUpdatedDownloads]);
- OCMVerify(times(1), [mockCache getObjectsForKey:TransactionCacheKeyRemovedTransactions]);
+ XCTAssertEqual(1, TransactionCacheKeyUpdatedTransactionsInvokedCount);
+ XCTAssertEqual(1, TransactionCacheKeyUpdatedDownloadsInvokedCount);
+ XCTAssertEqual(1, TransactionCacheKeyRemovedTransactionsInvokedCount);
}
- (void)testStartObservingPaymentQueueShouldProcessTransactionsForItemsInCache {
@@ -288,17 +327,17 @@
XCTestExpectation *updateDownloadsExpectation =
[self expectationWithDescription:
@"downloadsUpdated callback should be called with one transaction."];
- SKPaymentTransaction *mockTransaction = OCMClassMock(SKPaymentTransaction.class);
- SKDownload *mockDownload = OCMClassMock(SKDownload.class);
- FIATransactionCache *mockCache = OCMClassMock(FIATransactionCache.class);
+ SKPaymentTransaction *transactionStub = [[SKPaymentTransactionStub alloc] init];
+ SKDownload *downloadStub = [[SKDownload alloc] init];
+ TransactionCacheStub *cacheStub = [[TransactionCacheStub alloc] init];
FIAPaymentQueueHandler *handler =
- [[FIAPaymentQueueHandler alloc] initWithQueue:[[SKPaymentQueueStub alloc] init]
+ [[FIAPaymentQueueHandler alloc] initWithQueue:[[PaymentQueueStub alloc] init]
transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
- XCTAssertEqualObjects(transactions, @[ mockTransaction ]);
+ XCTAssertEqualObjects(transactions, @[ transactionStub ]);
[updateTransactionsExpectation fulfill];
}
transactionRemoved:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
- XCTAssertEqualObjects(transactions, @[ mockTransaction ]);
+ XCTAssertEqualObjects(transactions, @[ transactionStub ]);
[removeTransactionsExpectation fulfill];
}
restoreTransactionFailed:nil
@@ -307,20 +346,38 @@
return YES;
}
updatedDownloads:^(NSArray<SKDownload *> *_Nonnull downloads) {
- XCTAssertEqualObjects(downloads, @[ mockDownload ]);
+ XCTAssertEqualObjects(downloads, @[ downloadStub ]);
[updateDownloadsExpectation fulfill];
}
- transactionCache:mockCache];
+ transactionCache:cacheStub];
- OCMStub([mockCache getObjectsForKey:TransactionCacheKeyUpdatedTransactions]).andReturn(@[
- mockTransaction
- ]);
- OCMStub([mockCache getObjectsForKey:TransactionCacheKeyUpdatedDownloads]).andReturn(@[
- mockDownload
- ]);
- OCMStub([mockCache getObjectsForKey:TransactionCacheKeyRemovedTransactions]).andReturn(@[
- mockTransaction
- ]);
+ __block NSInteger TransactionCacheKeyUpdatedTransactionsInvokedCount = 0;
+ __block NSInteger TransactionCacheKeyUpdatedDownloadsInvokedCount = 0;
+ __block NSInteger TransactionCacheKeyRemovedTransactionsInvokedCount = 0;
+
+ cacheStub.getObjectsForKeyStub = ^NSArray *_Nonnull(TransactionCacheKey key) {
+ switch (key) {
+ case TransactionCacheKeyUpdatedTransactions:
+ TransactionCacheKeyUpdatedTransactionsInvokedCount++;
+ return @[ transactionStub ];
+ break;
+ case TransactionCacheKeyUpdatedDownloads:
+ TransactionCacheKeyUpdatedDownloadsInvokedCount++;
+ return @[ downloadStub ];
+ break;
+ case TransactionCacheKeyRemovedTransactions:
+ TransactionCacheKeyRemovedTransactionsInvokedCount++;
+ return @[ transactionStub ];
+ break;
+ default:
+ XCTFail("Invalid transaction state was invoked.");
+ }
+ };
+
+ __block NSInteger clearInvokedCount = 0;
+ cacheStub.clearStub = ^{
+ clearInvokedCount++;
+ };
[handler startObservingPaymentQueue];
@@ -328,15 +385,16 @@
updateTransactionsExpectation, removeTransactionsExpectation, updateDownloadsExpectation
]
timeout:5];
- OCMVerify(times(1), [mockCache getObjectsForKey:TransactionCacheKeyUpdatedTransactions]);
- OCMVerify(times(1), [mockCache getObjectsForKey:TransactionCacheKeyUpdatedDownloads]);
- OCMVerify(times(1), [mockCache getObjectsForKey:TransactionCacheKeyRemovedTransactions]);
- OCMVerify(times(1), [mockCache clear]);
+
+ XCTAssertEqual(1, TransactionCacheKeyUpdatedTransactionsInvokedCount);
+ XCTAssertEqual(1, TransactionCacheKeyUpdatedDownloadsInvokedCount);
+ XCTAssertEqual(1, TransactionCacheKeyRemovedTransactionsInvokedCount);
+ XCTAssertEqual(1, clearInvokedCount);
}
- (void)testTransactionsShouldBeCachedWhenNotObserving {
- SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
- FIATransactionCache *mockCache = OCMClassMock(FIATransactionCache.class);
+ PaymentQueueStub *queue = [[PaymentQueueStub alloc] init];
+ TransactionCacheStub *cacheStub = [[TransactionCacheStub alloc] init];
FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
XCTFail("transactionsUpdated callback should not be called when cache is empty.");
@@ -352,18 +410,36 @@
updatedDownloads:^(NSArray<SKDownload *> *_Nonnull downloads) {
XCTFail("updatedDownloads callback should not be called when cache is empty.");
}
- transactionCache:mockCache];
+ transactionCache:cacheStub];
SKPayment *payment =
[SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
+
+ __block NSInteger TransactionCacheKeyUpdatedTransactionsInvokedCount = 0;
+ __block NSInteger TransactionCacheKeyUpdatedDownloadsInvokedCount = 0;
+ __block NSInteger TransactionCacheKeyRemovedTransactionsInvokedCount = 0;
+
+ cacheStub.addObjectsStub = ^(NSArray *_Nonnull objects, TransactionCacheKey key) {
+ switch (key) {
+ case TransactionCacheKeyUpdatedTransactions:
+ TransactionCacheKeyUpdatedTransactionsInvokedCount++;
+ break;
+ case TransactionCacheKeyUpdatedDownloads:
+ TransactionCacheKeyUpdatedDownloadsInvokedCount++;
+ break;
+ case TransactionCacheKeyRemovedTransactions:
+ TransactionCacheKeyRemovedTransactionsInvokedCount++;
+ break;
+ default:
+ XCTFail("Invalid transaction state was invoked.");
+ }
+ };
+
[handler addPayment:payment];
- OCMVerify(times(1), [mockCache addObjects:[OCMArg any]
- forKey:TransactionCacheKeyUpdatedTransactions]);
- OCMVerify(never(), [mockCache addObjects:[OCMArg any]
- forKey:TransactionCacheKeyUpdatedDownloads]);
- OCMVerify(never(), [mockCache addObjects:[OCMArg any]
- forKey:TransactionCacheKeyRemovedTransactions]);
+ XCTAssertEqual(1, TransactionCacheKeyUpdatedTransactionsInvokedCount);
+ XCTAssertEqual(0, TransactionCacheKeyUpdatedDownloadsInvokedCount);
+ XCTAssertEqual(0, TransactionCacheKeyRemovedTransactionsInvokedCount);
}
- (void)testTransactionsShouldNotBeCachedWhenObserving {
@@ -376,18 +452,18 @@
XCTestExpectation *updateDownloadsExpectation =
[self expectationWithDescription:
@"downloadsUpdated callback should be called with one transaction."];
- SKPaymentTransaction *mockTransaction = OCMClassMock(SKPaymentTransaction.class);
- SKDownload *mockDownload = OCMClassMock(SKDownload.class);
- SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
+ SKPaymentTransaction *transactionStub = [[SKPaymentTransactionStub alloc] init];
+ SKDownload *downloadStub = [[SKDownload alloc] init];
+ PaymentQueueStub *queue = [[PaymentQueueStub alloc] init];
queue.testState = SKPaymentTransactionStatePurchased;
- FIATransactionCache *mockCache = OCMClassMock(FIATransactionCache.class);
+ TransactionCacheStub *cacheStub = [[TransactionCacheStub alloc] init];
FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
- XCTAssertEqualObjects(transactions, @[ mockTransaction ]);
+ XCTAssertEqualObjects(transactions, @[ transactionStub ]);
[updateTransactionsExpectation fulfill];
}
transactionRemoved:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
- XCTAssertEqualObjects(transactions, @[ mockTransaction ]);
+ XCTAssertEqualObjects(transactions, @[ transactionStub ]);
[removeTransactionsExpectation fulfill];
}
restoreTransactionFailed:nil
@@ -396,25 +472,44 @@
return YES;
}
updatedDownloads:^(NSArray<SKDownload *> *_Nonnull downloads) {
- XCTAssertEqualObjects(downloads, @[ mockDownload ]);
+ XCTAssertEqualObjects(downloads, @[ downloadStub ]);
[updateDownloadsExpectation fulfill];
}
- transactionCache:mockCache];
+ transactionCache:cacheStub];
+
+ SKPaymentQueueStub *paymentQueueStub = [[SKPaymentQueueStub alloc] init];
[handler startObservingPaymentQueue];
- [handler paymentQueue:queue updatedTransactions:@[ mockTransaction ]];
- [handler paymentQueue:queue removedTransactions:@[ mockTransaction ]];
- [handler paymentQueue:queue updatedDownloads:@[ mockDownload ]];
+ [handler paymentQueue:paymentQueueStub updatedTransactions:@[ transactionStub ]];
+ [handler paymentQueue:paymentQueueStub removedTransactions:@[ transactionStub ]];
+ [handler paymentQueue:paymentQueueStub updatedDownloads:@[ downloadStub ]];
[self waitForExpectations:@[
updateTransactionsExpectation, removeTransactionsExpectation, updateDownloadsExpectation
]
timeout:5];
- OCMVerify(never(), [mockCache addObjects:[OCMArg any]
- forKey:TransactionCacheKeyUpdatedTransactions]);
- OCMVerify(never(), [mockCache addObjects:[OCMArg any]
- forKey:TransactionCacheKeyUpdatedDownloads]);
- OCMVerify(never(), [mockCache addObjects:[OCMArg any]
- forKey:TransactionCacheKeyRemovedTransactions]);
+
+ __block NSInteger TransactionCacheKeyUpdatedTransactionsInvokedCount = 0;
+ __block NSInteger TransactionCacheKeyUpdatedDownloadsInvokedCount = 0;
+ __block NSInteger TransactionCacheKeyRemovedTransactionsInvokedCount = 0;
+
+ cacheStub.addObjectsStub = ^(NSArray *_Nonnull objects, TransactionCacheKey key) {
+ switch (key) {
+ case TransactionCacheKeyUpdatedTransactions:
+ TransactionCacheKeyUpdatedTransactionsInvokedCount++;
+ break;
+ case TransactionCacheKeyUpdatedDownloads:
+ TransactionCacheKeyUpdatedDownloadsInvokedCount++;
+ break;
+ case TransactionCacheKeyRemovedTransactions:
+ TransactionCacheKeyRemovedTransactionsInvokedCount++;
+ break;
+ default:
+ XCTFail("Invalid transaction state was invoked.");
+ }
+ };
+ XCTAssertEqual(0, TransactionCacheKeyUpdatedTransactionsInvokedCount);
+ XCTAssertEqual(0, TransactionCacheKeyUpdatedDownloadsInvokedCount);
+ XCTAssertEqual(0, TransactionCacheKeyRemovedTransactionsInvokedCount);
}
@end
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.h b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.h
index daad506..8e7769c 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.h
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.h
@@ -4,6 +4,12 @@
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
+#import "FIATransactionCache.h"
+#import "FLTMethodChannelProtocol.h"
+#import "FLTPaymentQueueHandlerProtocol.h"
+#import "FLTPaymentQueueProtocol.h"
+#import "FLTRequestHandlerProtocol.h"
+#import "FLTTransactionCacheProtocol.h"
@import in_app_purchase_storekit;
@@ -24,7 +30,7 @@
@end
@interface SKProductRequestStub : SKProductsRequest
-@property(assign, nonatomic) BOOL returnError;
+@property(nonatomic, assign) BOOL returnError;
- (instancetype)initWithProductIdentifiers:(NSSet<NSString *> *)productIdentifiers;
- (instancetype)initWithFailureError:(NSError *)error;
@end
@@ -33,12 +39,9 @@
- (instancetype)initWithMap:(NSDictionary *)map;
@end
-@interface SKRequestStub : SKRequest
-@end
-
@interface SKPaymentQueueStub : SKPaymentQueue
-@property(assign, nonatomic) SKPaymentTransactionState testState;
-@property(strong, nonatomic, nullable) id<SKPaymentTransactionObserver> observer;
+@property(nonatomic, assign) SKPaymentTransactionState testState;
+@property(nonatomic, strong, nullable) id<SKPaymentTransactionObserver> observer;
@end
@interface SKPaymentTransactionStub : SKPaymentTransaction
@@ -58,7 +61,9 @@
@interface FIAPReceiptManagerStub : FIAPReceiptManager
// Indicates whether getReceiptData of this stub is going to return an error.
// Setting this to true will let getReceiptData give a basic NSError and return nil.
-@property(assign, nonatomic) BOOL returnError;
+@property(nonatomic, assign) BOOL returnError;
+// Indicates whether the receipt url will be nil.
+@property(nonatomic, assign) BOOL returnNilURL;
@end
@interface SKReceiptRefreshRequestStub : SKReceiptRefreshRequest
@@ -70,4 +75,116 @@
- (instancetype)initWithMap:(NSDictionary *)map;
@end
+// An interface representing a stubbed DefaultPaymentQueue
+@interface PaymentQueueStub : NSObject <FLTPaymentQueueProtocol>
+
+// FLTPaymentQueueProtocol properties
+@property(nonatomic, assign) SKPaymentTransactionState paymentState;
+@property(nonatomic, strong, nullable) id<SKPaymentTransactionObserver> observer;
+@property(nonatomic, strong, readwrite) SKStorefront *storefront API_AVAILABLE(ios(13.0));
+@property(nonatomic, strong, readwrite) NSArray<SKPaymentTransaction *> *transactions API_AVAILABLE(
+ ios(3.0), macos(10.7), watchos(6.2), visionos(1.0));
+
+// Test Properties
+@property(nonatomic, assign)
+ SKPaymentTransactionState testState; // Set this property to set a test Transaction state, then
+ // call addPayment to add it to the queue.
+@property(nonatomic, strong, nonnull)
+ SKPaymentQueue *realQueue; // This is a reference to the real SKPaymentQueue
+
+// Stubs
+@property(nonatomic, copy, nullable) void (^showPriceConsentIfNeededStub)(void);
+@property(nonatomic, copy, nullable) void (^restoreTransactionsStub)(NSString *);
+@property(nonatomic, copy, nullable) void (^startObservingPaymentQueueStub)(void);
+@property(nonatomic, copy, nullable) void (^stopObservingPaymentQueueStub)(void);
+@property(nonatomic, copy, nullable) void (^presentCodeRedemptionSheetStub)(void);
+@property(nonatomic, copy, nullable)
+ NSArray<SKPaymentTransaction *> * (^getUnfinishedTransactionsStub)(void);
+
+@end
+
+// An interface representing a stubbed DefaultTransactionCache
+@interface TransactionCacheStub : NSObject <FLTTransactionCacheProtocol>
+
+// Stubs
+@property(nonatomic, copy, nullable) NSArray * (^getObjectsForKeyStub)(TransactionCacheKey key);
+@property(nonatomic, copy, nullable) void (^clearStub)(void);
+@property(nonatomic, copy, nullable) void (^addObjectsStub)(NSArray *, TransactionCacheKey);
+
+@end
+
+// An interface representing a stubbed DefaultMethodChannel
+@interface MethodChannelStub : NSObject <FLTMethodChannelProtocol>
+
+// Stubs
+@property(nonatomic, copy, nullable) void (^invokeMethodChannelStub)(NSString *method, id arguments)
+ ;
+@property(nonatomic, copy, nullable) void (^invokeMethodChannelWithResultsStub)
+ (NSString *method, id arguments, FlutterResult _Nullable);
+
+@end
+
+// An interface representing a stubbed DefaultPaymentQueueHandler
+@interface PaymentQueueHandlerStub
+ : NSObject <SKPaymentTransactionObserver, FLTPaymentQueueHandlerProtocol>
+
+// Stubs
+@property(nonatomic, copy, nullable) BOOL (^addPaymentStub)(SKPayment *payment);
+@property(nonatomic, copy, nullable) void (^showPriceConsentIfNeededStub)(void);
+@property(nonatomic, copy, nullable) void (^stopObservingPaymentQueueStub)(void);
+@property(nonatomic, copy, nullable) void (^startObservingPaymentQueueStub)(void);
+@property(nonatomic, copy, nullable) void (^presentCodeRedemptionSheetStub)(void);
+@property(nonatomic, copy, nullable) void (^restoreTransactions)(NSString *);
+@property(nonatomic, copy, nullable)
+ NSArray<SKPaymentTransaction *> * (^getUnfinishedTransactionsStub)(void);
+@property(nonatomic, copy, nullable) void (^finishTransactionStub)(SKPaymentTransaction *);
+@property(nonatomic, copy, nullable) void (^paymentQueueUpdatedTransactionsStub)
+ (SKPaymentQueue *, NSArray<SKPaymentTransaction *> *);
+
+@end
+
+// An interface representing a stubbed DefaultRequestHandler
+@interface RequestHandlerStub : NSObject <FLTRequestHandlerProtocol>
+
+// Stubs
+@property(nonatomic, copy, nullable) void (^startProductRequestWithCompletionHandlerStub)
+ (ProductRequestCompletion);
+
+@end
+
+#if TARGET_OS_IOS
+@interface FlutterPluginRegistrarStub : NSObject <FlutterPluginRegistrar>
+
+// Stubs
+@property(nonatomic, copy, nullable) void (^addApplicationDelegateStub)(NSObject<FlutterPlugin> *);
+@property(nonatomic, copy, nullable) void (^addMethodCallDelegateStub)
+ (NSObject<FlutterPlugin> *, FlutterMethodChannel *);
+@property(nonatomic, copy, nullable) NSString * (^lookupKeyForAssetStub)(NSString *);
+@property(nonatomic, copy, nullable) NSString * (^lookupKeyForAssetFromPackageStub)
+ (NSString *, NSString *);
+@property(nonatomic, copy, nullable) NSObject<FlutterBinaryMessenger> * (^messengerStub)(void);
+@property(nonatomic, copy, nullable) void (^publishStub)(NSObject *);
+@property(nonatomic, copy, nullable) void (^registerViewFactoryStub)
+ (NSObject<FlutterPlatformViewFactory> *, NSString *);
+@property(nonatomic, copy, nullable) NSObject<FlutterTextureRegistry> * (^texturesStub)(void);
+@property(nonatomic, copy, nullable)
+ void (^registerViewFactoryWithGestureRecognizersBlockingPolicyStub)
+ (NSObject<FlutterPlatformViewFactory> *, NSString *,
+ FlutterPlatformViewGestureRecognizersBlockingPolicy);
+@end
+#endif
+
+@interface FlutterBinaryMessengerStub : NSObject <FlutterBinaryMessenger>
+
+// Stubs
+@property(nonatomic, copy, nullable) void (^cleanUpConnectionStub)(FlutterBinaryMessengerConnection)
+ ;
+@property(nonatomic, copy, nullable) void (^sendOnChannelMessageStub)(NSString *, NSData *);
+@property(nonatomic, copy, nullable) void (^sendOnChannelMessageBinaryReplyStub)
+ (NSString *, NSData *, FlutterBinaryReply);
+@property(nonatomic, copy, nullable)
+ FlutterBinaryMessengerConnection (^setMessageHandlerOnChannelBinaryMessageHandlerStub)
+ (NSString *, FlutterBinaryMessageHandler);
+@end
+
NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.m b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.m
index 8c8b297..6c7d246 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.m
+++ b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/Stubs.m
@@ -3,6 +3,14 @@
// found in the LICENSE file.
#import "Stubs.h"
+#import <Foundation/Foundation.h>
+#import <StoreKit/StoreKit.h>
+
+#if TARGET_OS_OSX
+#import <FlutterMacOS/FlutterMacOS.h>
+#else
+#import <Flutter/Flutter.h>
+#endif
@implementation SKProductSubscriptionPeriodStub
@@ -87,8 +95,8 @@
@interface SKProductRequestStub ()
-@property(strong, nonatomic) NSSet *identifers;
-@property(strong, nonatomic) NSError *error;
+@property(nonatomic, strong) NSSet *identifers;
+@property(nonatomic, strong) NSError *error;
@end
@@ -271,6 +279,14 @@
return [[NSData alloc] initWithBase64EncodedString:originalString options:kNilOptions];
}
+- (NSURL *)receiptURL {
+ if (self.returnNilURL) {
+ return nil;
+ } else {
+ return [[NSBundle mainBundle] appStoreReceiptURL];
+ }
+}
+
@end
@implementation SKReceiptRefreshRequestStub {
@@ -309,5 +325,325 @@
}
return self;
}
+@end
+
+@implementation PaymentQueueStub
+
+@synthesize transactions;
+@synthesize delegate;
+
+- (void)finishTransaction:(SKPaymentTransaction *)transaction {
+ [self.observer paymentQueue:self.realQueue removedTransactions:@[ transaction ]];
+}
+
+- (void)addPayment:(SKPayment *_Nonnull)payment {
+ SKPaymentTransactionStub *transaction =
+ [[SKPaymentTransactionStub alloc] initWithState:self.testState payment:payment];
+ [self.observer paymentQueue:self.realQueue updatedTransactions:@[ transaction ]];
+}
+
+- (void)addTransactionObserver:(nonnull id<SKPaymentTransactionObserver>)observer {
+ self.observer = observer;
+}
+
+- (void)restoreCompletedTransactions {
+ [self.observer paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)self];
+}
+
+- (void)restoreCompletedTransactionsWithApplicationUsername:(nullable NSString *)username {
+ [self.observer paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)self];
+}
+
+- (NSArray<SKPaymentTransaction *> *_Nonnull)getUnfinishedTransactions {
+ if (self.getUnfinishedTransactionsStub) {
+ return self.getUnfinishedTransactionsStub();
+ } else {
+ return @[];
+ }
+}
+
+#if TARGET_OS_IOS
+- (void)presentCodeRedemptionSheet {
+ if (self.presentCodeRedemptionSheetStub) {
+ self.presentCodeRedemptionSheetStub();
+ }
+}
+#endif
+
+#if TARGET_OS_IOS
+- (void)showPriceConsentIfNeeded {
+ if (self.showPriceConsentIfNeededStub) {
+ self.showPriceConsentIfNeededStub();
+ }
+}
+#endif
+
+- (void)restoreTransactions:(nullable NSString *)applicationName {
+ if (self.restoreTransactionsStub) {
+ self.restoreTransactionsStub(applicationName);
+ }
+}
+
+- (void)startObservingPaymentQueue {
+ if (self.startObservingPaymentQueueStub) {
+ self.startObservingPaymentQueueStub();
+ }
+}
+
+- (void)stopObservingPaymentQueue {
+ if (self.stopObservingPaymentQueueStub) {
+ self.stopObservingPaymentQueueStub();
+ }
+}
+
+- (void)removeTransactionObserver:(id<SKPaymentTransactionObserver>)observer {
+ self.observer = nil;
+}
+@end
+
+@implementation MethodChannelStub
+- (void)invokeMethod:(nonnull NSString *)method arguments:(id _Nullable)arguments {
+ if (self.invokeMethodChannelStub) {
+ self.invokeMethodChannelStub(method, arguments);
+ }
+}
+
+- (void)invokeMethod:(nonnull NSString *)method
+ arguments:(id _Nullable)arguments
+ result:(FlutterResult _Nullable)callback {
+ if (self.invokeMethodChannelWithResultsStub) {
+ self.invokeMethodChannelWithResultsStub(method, arguments, callback);
+ }
+}
@end
+
+@implementation TransactionCacheStub
+- (void)addObjects:(nonnull NSArray *)objects forKey:(TransactionCacheKey)key {
+ if (self.addObjectsStub) {
+ self.addObjectsStub(objects, key);
+ }
+}
+
+- (void)clear {
+ if (self.clearStub) {
+ self.clearStub();
+ }
+}
+
+- (nonnull NSArray *)getObjectsForKey:(TransactionCacheKey)key {
+ if (self.getObjectsForKeyStub) {
+ return self.getObjectsForKeyStub(key);
+ }
+ return @[];
+}
+@end
+
+@implementation PaymentQueueHandlerStub
+
+@synthesize storefront;
+@synthesize delegate;
+
+- (void)paymentQueue:(nonnull SKPaymentQueue *)queue
+ updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions {
+ if (self.paymentQueueUpdatedTransactionsStub) {
+ self.paymentQueueUpdatedTransactionsStub(queue, transactions);
+ }
+}
+
+#if TARGET_OS_IOS
+- (void)showPriceConsentIfNeeded {
+ if (self.showPriceConsentIfNeededStub) {
+ self.showPriceConsentIfNeededStub();
+ }
+}
+#endif
+
+- (BOOL)addPayment:(nonnull SKPayment *)payment {
+ if (self.addPaymentStub) {
+ return self.addPaymentStub(payment);
+ } else {
+ return NO;
+ }
+}
+
+- (void)finishTransaction:(nonnull SKPaymentTransaction *)transaction {
+ if (self.finishTransactionStub) {
+ self.finishTransactionStub(transaction);
+ }
+}
+
+- (nonnull NSArray<SKPaymentTransaction *> *)getUnfinishedTransactions {
+ if (self.getUnfinishedTransactionsStub) {
+ return self.getUnfinishedTransactionsStub();
+ } else {
+ return @[];
+ }
+}
+
+- (nonnull instancetype)initWithQueue:(nonnull id<FLTPaymentQueueProtocol>)queue
+ transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated
+ transactionRemoved:(nullable TransactionsRemoved)transactionsRemoved
+ restoreTransactionFailed:(nullable RestoreTransactionFailed)restoreTransactionFailed
+ restoreCompletedTransactionsFinished:
+ (nullable RestoreCompletedTransactionsFinished)restoreCompletedTransactionsFinished
+ shouldAddStorePayment:(nullable ShouldAddStorePayment)shouldAddStorePayment
+ updatedDownloads:(nullable UpdatedDownloads)updatedDownloads
+ transactionCache:(nonnull id<FLTTransactionCacheProtocol>)transactionCache {
+ return [[PaymentQueueHandlerStub alloc] init];
+}
+
+#if TARGET_OS_IOS
+- (void)presentCodeRedemptionSheet {
+ if (self.presentCodeRedemptionSheetStub) {
+ self.presentCodeRedemptionSheetStub();
+ }
+}
+#endif
+
+- (void)restoreTransactions:(nullable NSString *)applicationName {
+ if (self.restoreTransactions) {
+ self.restoreTransactions(applicationName);
+ }
+}
+
+- (void)startObservingPaymentQueue {
+ if (self.startObservingPaymentQueueStub) {
+ self.startObservingPaymentQueueStub();
+ }
+}
+
+- (void)stopObservingPaymentQueue {
+ if (self.stopObservingPaymentQueueStub) {
+ self.stopObservingPaymentQueueStub();
+ }
+}
+
+- (nonnull instancetype)initWithQueue:(nonnull id<FLTPaymentQueueProtocol>)queue
+ transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated
+ transactionRemoved:(nullable TransactionsRemoved)transactionsRemoved
+ restoreTransactionFailed:(nullable RestoreTransactionFailed)restoreTransactionFailed
+ restoreCompletedTransactionsFinished:
+ (nullable RestoreCompletedTransactionsFinished)restoreCompletedTransactionsFinished
+ shouldAddStorePayment:(nullable ShouldAddStorePayment)shouldAddStorePayment
+ updatedDownloads:(nullable UpdatedDownloads)updatedDownloads {
+ return [[PaymentQueueHandlerStub alloc] init];
+}
+
+@end
+
+@implementation RequestHandlerStub
+
+- (void)startProductRequestWithCompletionHandler:(nonnull ProductRequestCompletion)completion {
+ if (self.startProductRequestWithCompletionHandlerStub) {
+ self.startProductRequestWithCompletionHandlerStub(completion);
+ }
+}
+@end
+
+/// This mock is only used in iOS tests
+#if TARGET_OS_IOS
+
+// This FlutterPluginRegistrar is a protocol, so to make a stub it has to be implemented.
+@implementation FlutterPluginRegistrarStub
+
+- (void)addApplicationDelegate:(nonnull NSObject<FlutterPlugin> *)delegate {
+ if (self.addApplicationDelegateStub) {
+ self.addApplicationDelegateStub(delegate);
+ }
+}
+
+- (void)addMethodCallDelegate:(nonnull NSObject<FlutterPlugin> *)delegate
+ channel:(nonnull FlutterMethodChannel *)channel {
+ if (self.addMethodCallDelegateStub) {
+ self.addMethodCallDelegateStub(delegate, channel);
+ }
+}
+
+- (nonnull NSString *)lookupKeyForAsset:(nonnull NSString *)asset {
+ if (self.lookupKeyForAssetStub) {
+ return self.lookupKeyForAssetStub(asset);
+ }
+ return nil;
+}
+
+- (nonnull NSString *)lookupKeyForAsset:(nonnull NSString *)asset
+ fromPackage:(nonnull NSString *)package {
+ if (self.lookupKeyForAssetFromPackageStub) {
+ return self.lookupKeyForAssetFromPackageStub(asset, package);
+ }
+ return nil;
+}
+
+- (nonnull NSObject<FlutterBinaryMessenger> *)messenger {
+ if (self.messengerStub) {
+ return self.messengerStub();
+ }
+ return [[FlutterBinaryMessengerStub alloc] init]; // Or default behavior
+}
+
+- (void)publish:(nonnull NSObject *)value {
+ if (self.publishStub) {
+ self.publishStub(value);
+ }
+}
+
+- (void)registerViewFactory:(nonnull NSObject<FlutterPlatformViewFactory> *)factory
+ withId:(nonnull NSString *)factoryId {
+ if (self.registerViewFactoryStub) {
+ self.registerViewFactoryStub(factory, factoryId);
+ }
+}
+
+- (nonnull NSObject<FlutterTextureRegistry> *)textures {
+ if (self.texturesStub) {
+ return self.texturesStub();
+ }
+ return nil;
+}
+
+- (void)registerViewFactory:(nonnull NSObject<FlutterPlatformViewFactory> *)factory
+ withId:(nonnull NSString *)factoryId
+ gestureRecognizersBlockingPolicy:
+ (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizersBlockingPolicy {
+ if (self.registerViewFactoryWithGestureRecognizersBlockingPolicyStub) {
+ self.registerViewFactoryWithGestureRecognizersBlockingPolicyStub(
+ factory, factoryId, gestureRecognizersBlockingPolicy);
+ }
+}
+
+@end
+
+// This FlutterBinaryMessenger is a protocol, so to make a stub it has to be implemented.
+@implementation FlutterBinaryMessengerStub
+- (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection {
+ if (self.cleanUpConnectionStub) {
+ self.cleanUpConnectionStub(connection);
+ }
+}
+
+- (void)sendOnChannel:(nonnull NSString *)channel message:(NSData *_Nullable)message {
+ if (self.sendOnChannelMessageStub) {
+ self.sendOnChannelMessageStub(channel, message);
+ }
+}
+
+- (void)sendOnChannel:(nonnull NSString *)channel
+ message:(NSData *_Nullable)message
+ binaryReply:(FlutterBinaryReply _Nullable)callback {
+ if (self.sendOnChannelMessageBinaryReplyStub) {
+ self.sendOnChannelMessageBinaryReplyStub(channel, message, callback);
+ }
+}
+
+- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(nonnull NSString *)channel
+ binaryMessageHandler:
+ (FlutterBinaryMessageHandler _Nullable)handler {
+ if (self.setMessageHandlerOnChannelBinaryMessageHandlerStub) {
+ return self.setMessageHandlerOnChannelBinaryMessageHandlerStub(channel, handler);
+ }
+ return 0;
+}
+@end
+
+#endif
diff --git a/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml
index b960beb..bcb2807 100644
--- a/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml
+++ b/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml
@@ -2,7 +2,7 @@
description: An implementation for the iOS and macOS platforms of the Flutter `in_app_purchase` plugin. This uses the StoreKit Framework.
repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_storekit
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
-version: 0.3.16
+version: 0.3.17
environment:
sdk: ^3.2.3