Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/in_app_purchase/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## 0.2.1+5

* Define clang module for iOS.
* Fix iOS build warning.

## 0.2.1+4

Expand Down
4 changes: 3 additions & 1 deletion packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

@property(strong, nonatomic) FIAPaymentQueueHandler *paymentQueueHandler;

- (instancetype)initWithReceiptManager:(FIAPReceiptManager *)receiptManager;
- (instancetype)initWithReceiptManager:(FIAPReceiptManager *)receiptManager
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;

@end
83 changes: 34 additions & 49 deletions packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ @interface InAppPurchasePlugin ()

// Holding strong references to FIAPRequestHandlers. Remove the handlers from the set after
// the request is finished.
@property(strong, nonatomic) NSMutableSet *requestHandlers;
@property(strong, nonatomic, readonly) NSMutableSet *requestHandlers;

// After querying the product, the available products will be saved in the map to be used
// for purchase.
@property(copy, nonatomic) NSMutableDictionary *productsCache;
@property(strong, nonatomic, readonly) NSMutableDictionary *productsCache;

// Call back channel to dart used for when a listener function is triggered.
@property(strong, nonatomic) FlutterMethodChannel *callbackChannel;
@property(strong, nonatomic) NSObject<FlutterTextureRegistry> *registry;
@property(strong, nonatomic) NSObject<FlutterBinaryMessenger> *messenger;
@property(strong, nonatomic) NSObject<FlutterPluginRegistrar> *registrar;
@property(strong, nonatomic, readonly) FlutterMethodChannel *callbackChannel;
@property(strong, nonatomic, readonly) NSObject<FlutterTextureRegistry> *registry;
@property(strong, nonatomic, readonly) NSObject<FlutterBinaryMessenger> *messenger;
@property(strong, nonatomic, readonly) NSObject<FlutterPluginRegistrar> *registrar;

@property(strong, nonatomic) FIAPReceiptManager *receiptManager;
@property(strong, nonatomic, readonly) FIAPReceiptManager *receiptManager;

@end

Expand All @@ -40,39 +40,40 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
}

- (instancetype)initWithReceiptManager:(FIAPReceiptManager *)receiptManager {
self = [self init];
self.receiptManager = receiptManager;
self = [super init];
_receiptManager = receiptManager;
_requestHandlers = [NSMutableSet new];
_productsCache = [NSMutableDictionary new];
Comment on lines +45 to +46
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curious, what is the benefit of initialize them in at initialization v.s. the lazy init that we used to have?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this particular case the lazy getter wasn't threadsafe. Also this class assumes these collections are instantiated, but there's nothing stopping a subclass from overriding the getter to do something wonky that doesn't call super or set up the ivar (probably unlikely). To me it looked like it was lazily instantiated because there was no designated initializer decoration on the init methods, so there was no one canonical spot where these collections could be relied on to be instantiated.

Assuming this object is queue confined (I don't know if that's actually enforced or just convention) it's fine to keep it lazily instantiated, and I can change it back if you prefer!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation. What you have now is good! LGTM again.

return self;
}

- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
self = [self initWithReceiptManager:[FIAPReceiptManager new]];
self.registrar = registrar;
self.registry = [registrar textures];
self.messenger = [registrar messenger];
_registrar = registrar;
_registry = [registrar textures];
_messenger = [registrar messenger];

__weak typeof(self) weakSelf = self;
self.paymentQueueHandler =
[[FIAPaymentQueueHandler alloc] initWithQueue:[SKPaymentQueue defaultQueue]
transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
[weakSelf handleTransactionsUpdated:transactions];
}
transactionRemoved:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
[weakSelf handleTransactionsRemoved:transactions];
}
restoreTransactionFailed:^(NSError *_Nonnull error) {
[weakSelf handleTransactionRestoreFailed:error];
}
restoreCompletedTransactionsFinished:^{
[weakSelf restoreCompletedTransactionsFinished];
}
shouldAddStorePayment:^BOOL(SKPayment *payment, SKProduct *product) {
return [weakSelf shouldAddStorePayment:payment product:product];
}
updatedDownloads:^void(NSArray<SKDownload *> *_Nonnull downloads) {
[weakSelf updatedDownloads:downloads];
}];
self.callbackChannel =
_paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:[SKPaymentQueue defaultQueue]
transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
[weakSelf handleTransactionsUpdated:transactions];
}
transactionRemoved:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
[weakSelf handleTransactionsRemoved:transactions];
}
restoreTransactionFailed:^(NSError *_Nonnull error) {
[weakSelf handleTransactionRestoreFailed:error];
}
restoreCompletedTransactionsFinished:^{
[weakSelf restoreCompletedTransactionsFinished];
}
shouldAddStorePayment:^BOOL(SKPayment *payment, SKProduct *product) {
return [weakSelf shouldAddStorePayment:payment product:product];
}
updatedDownloads:^void(NSArray<SKDownload *> *_Nonnull downloads) {
[weakSelf updatedDownloads:downloads];
}];
_callbackChannel =
[FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/in_app_purchase_callback"
binaryMessenger:[registrar messenger]];
return self;
Expand Down Expand Up @@ -320,20 +321,4 @@ - (SKReceiptRefreshRequest *)getRefreshReceiptRequest:(NSDictionary *)properties
return [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:properties];
}

#pragma mark - getter

- (NSSet *)requestHandlers {
if (!_requestHandlers) {
_requestHandlers = [NSMutableSet new];
}
return _requestHandlers;
}

- (NSMutableDictionary *)productsCache {
if (!_productsCache) {
_productsCache = [NSMutableDictionary new];
}
return _productsCache;
}

@end
1 change: 0 additions & 1 deletion script/lint_darwin_plugins.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ function lint_package() {
# TODO: These packages have analyzer warnings. Remove plugins from this list as issues are fixed.
local skip_analysis_packages=(
"camera.podspec" # https://github.com/flutter/flutter/issues/42673
"in_app_purchase.podspec" # https://github.com/flutter/flutter/issues/42679
)
find "${package_dir}" -type f -name "*\.podspec" | while read podspec; do
local podspecBasename=$(basename "${podspec}")
Expand Down