Skip to content

Commit 8175f76

Browse files
author
Chris Yang
authored
[in_app_purchase] add storefront in skpaymentqueuewrapper (#5348)
Add `Future<SKStorefrontWrapper?> storefront()` method in SKPaymentQueue wrapper fixes flutter/flutter#137560
1 parent 0cd2378 commit 8175f76

File tree

8 files changed

+131
-2
lines changed

8 files changed

+131
-2
lines changed

Diff for: packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.3.7
2+
3+
* Adds `Future<SKStorefrontWrapper?> storefront()` in SKPaymentQueueWrapper class.
4+
15
## 0.3.6+7
26

37
* Updates example code for current versions of Flutter.

Diff for: packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPaymentQueueHandler.h

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ typedef void (^UpdatedDownloads)(NSArray<SKDownload *> *downloads);
2121

2222
@property(NS_NONATOMIC_IOSONLY, weak, nullable) id<SKPaymentQueueDelegate> delegate API_AVAILABLE(
2323
ios(13.0), macos(10.15), watchos(6.2));
24+
@property(nonatomic, readonly, nullable)
25+
SKStorefront *storefront API_AVAILABLE(ios(13.0), macos(10.15), watchos(6.2));
2426

2527
/// Creates a new FIAPaymentQueueHandler initialized with an empty
2628
/// FIATransactionCache.

Diff for: packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/FIAPaymentQueueHandler.m

+4
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,8 @@ - (BOOL)paymentQueue:(SKPaymentQueue *)queue
233233
return self.queue.transactions;
234234
}
235235

236+
- (SKStorefront *)storefront {
237+
return self.queue.storefront;
238+
}
239+
236240
@end

Diff for: packages/in_app_purchase/in_app_purchase_storekit/darwin/Classes/InAppPurchasePlugin.m

+18
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
8989
[self canMakePayments:result];
9090
} else if ([@"-[SKPaymentQueue transactions]" isEqualToString:call.method]) {
9191
[self getPendingTransactions:result];
92+
} else if ([@"-[SKPaymentQueue storefront]" isEqualToString:call.method]) {
93+
[self getStorefront:result];
9294
} else if ([@"-[InAppPurchasePlugin startProductRequest:result:]" isEqualToString:call.method]) {
9395
[self handleProductRequestMethodCall:call result:result];
9496
} else if ([@"-[InAppPurchasePlugin addPayment:result:]" isEqualToString:call.method]) {
@@ -139,6 +141,22 @@ - (void)getPendingTransactions:(FlutterResult)result {
139141
result(transactionMaps);
140142
}
141143

144+
- (void)getStorefront:(FlutterResult)result {
145+
if (@available(iOS 13.0, macOS 10.15, *)) {
146+
SKStorefront *storefront = self.paymentQueueHandler.storefront;
147+
if (!storefront) {
148+
result(nil);
149+
return;
150+
}
151+
result([FIAObjectTranslator getMapFromSKStorefront:storefront]);
152+
return;
153+
}
154+
155+
NSLog(@"storefront is not avaialbe in iOS below 13.0 or macOS below 10.15.");
156+
result(nil);
157+
return;
158+
}
159+
142160
- (void)handleProductRequestMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
143161
if (![call.arguments isKindOfClass:[NSArray class]]) {
144162
result([FlutterError errorWithCode:@"storekit_invalid_argument"

Diff for: packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchasePluginTests.m

+65
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,71 @@ - (void)testGetPendingTransactions {
419419
XCTAssertEqualObjects(resultArray, @[ transactionMap ]);
420420
}
421421

422+
- (void)testPaymentQueueStorefront {
423+
if (@available(iOS 13, macOS 10.15, *)) {
424+
// storefront is not nil
425+
XCTestExpectation *expectation = [self expectationWithDescription:@"expect success"];
426+
FlutterMethodCall *call =
427+
[FlutterMethodCall methodCallWithMethodName:@"-[SKPaymentQueue storefront]" arguments:nil];
428+
SKPaymentQueue *mockQueue = OCMClassMock(SKPaymentQueue.class);
429+
NSDictionary *storefrontMap = @{
430+
@"countryCode" : @"USA",
431+
@"identifier" : @"unique_identifier",
432+
};
433+
OCMStub(mockQueue.storefront).andReturn([[SKStorefrontStub alloc] initWithMap:storefrontMap]);
434+
435+
__block NSDictionary *resultMap;
436+
self.plugin.paymentQueueHandler =
437+
[[FIAPaymentQueueHandler alloc] initWithQueue:mockQueue
438+
transactionsUpdated:nil
439+
transactionRemoved:nil
440+
restoreTransactionFailed:nil
441+
restoreCompletedTransactionsFinished:nil
442+
shouldAddStorePayment:nil
443+
updatedDownloads:nil
444+
transactionCache:OCMClassMock(FIATransactionCache.class)];
445+
[self.plugin handleMethodCall:call
446+
result:^(id r) {
447+
resultMap = r;
448+
[expectation fulfill];
449+
}];
450+
[self waitForExpectations:@[ expectation ] timeout:5];
451+
XCTAssertEqualObjects(resultMap, storefrontMap);
452+
} else {
453+
NSLog(@"Skip testPaymentQueueStorefront for iOS lower than 13.0 or macOS lower than 10.15.");
454+
}
455+
}
456+
457+
- (void)testPaymentQueueStorefrontReturnsNil {
458+
if (@available(iOS 13, macOS 10.15, *)) {
459+
XCTestExpectation *expectation = [self expectationWithDescription:@"expect success"];
460+
FlutterMethodCall *call =
461+
[FlutterMethodCall methodCallWithMethodName:@"-[SKPaymentQueue storefront]" arguments:nil];
462+
SKPaymentQueue *mockQueue = OCMClassMock(SKPaymentQueue.class);
463+
OCMStub(mockQueue.storefront).andReturn(nil);
464+
465+
__block NSDictionary *resultMap;
466+
self.plugin.paymentQueueHandler =
467+
[[FIAPaymentQueueHandler alloc] initWithQueue:mockQueue
468+
transactionsUpdated:nil
469+
transactionRemoved:nil
470+
restoreTransactionFailed:nil
471+
restoreCompletedTransactionsFinished:nil
472+
shouldAddStorePayment:nil
473+
updatedDownloads:nil
474+
transactionCache:OCMClassMock(FIATransactionCache.class)];
475+
[self.plugin handleMethodCall:call
476+
result:^(id r) {
477+
resultMap = r;
478+
[expectation fulfill];
479+
}];
480+
[self waitForExpectations:@[ expectation ] timeout:5];
481+
XCTAssertNil(resultMap);
482+
} else {
483+
NSLog(@"Skip testPaymentQueueStorefront for iOS lower than 13.0 or macOS lower than 10.15.");
484+
}
485+
}
486+
422487
- (void)testStartObservingPaymentQueue {
423488
XCTestExpectation *expectation =
424489
[self expectationWithDescription:@"Should return success result"];

Diff for: packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart

+13-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,19 @@ class SKPaymentQueueWrapper {
4141
SKPaymentQueueDelegateWrapper? _paymentQueueDelegate;
4242
SKTransactionObserverWrapper? _observer;
4343

44-
/// Calls [`-[SKPaymentQueue transactions]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506026-transactions?language=objc)
44+
/// Calls [`[SKPaymentQueue storefront]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/3182430-storefront?language=objc).
45+
///
46+
/// Returns `null` if the user's device is below iOS 13.0 or macOS 10.15.
47+
Future<SKStorefrontWrapper?> storefront() async {
48+
final Map<String, dynamic>? storefrontMap = await channel
49+
.invokeMapMethod<String, dynamic>('-[SKPaymentQueue storefront]');
50+
if (storefrontMap == null) {
51+
return null;
52+
}
53+
return SKStorefrontWrapper.fromJson(storefrontMap);
54+
}
55+
56+
/// Calls [`-[SKPaymentQueue transactions]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506026-transactions?language=objc).
4557
Future<List<SKPaymentTransactionWrapper>> transactions() async {
4658
return _getTransactionList((await channel
4759
.invokeListMethod<dynamic>('-[SKPaymentQueue transactions]'))!);

Diff for: packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: in_app_purchase_storekit
22
description: An implementation for the iOS and macOS platforms of the Flutter `in_app_purchase` plugin. This uses the StoreKit Framework.
33
repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_storekit
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
5-
version: 0.3.6+7
5+
version: 0.3.7
66

77
environment:
88
sdk: ">=2.19.0 <4.0.0"

Diff for: packages/in_app_purchase/in_app_purchase_storekit/test/store_kit_wrappers/sk_methodchannel_apis_test.dart

+24
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,22 @@ void main() {
108108
expect(await SKPaymentQueueWrapper.canMakePayments(), false);
109109
});
110110

111+
test('storefront returns valid SKStoreFrontWrapper object', () async {
112+
final SKPaymentQueueWrapper queue = SKPaymentQueueWrapper();
113+
expect(
114+
await queue.storefront(),
115+
SKStorefrontWrapper.fromJson(const <String, dynamic>{
116+
'countryCode': 'USA',
117+
'identifier': 'unique_identifier',
118+
}));
119+
});
120+
121+
test('storefront returns null', () async {
122+
fakeStoreKitPlatform.testReturnNull = true;
123+
final SKPaymentQueueWrapper queue = SKPaymentQueueWrapper();
124+
expect(await queue.storefront(), isNull);
125+
});
126+
111127
test('transactions should return a valid list of transactions', () async {
112128
expect(await SKPaymentQueueWrapper().transactions(), isNotEmpty);
113129
});
@@ -250,6 +266,14 @@ class FakeStoreKitPlatform {
250266
case '-[SKPaymentQueue transactions]':
251267
return Future<List<dynamic>>.value(
252268
<dynamic>[buildTransactionMap(dummyTransaction)]);
269+
case '-[SKPaymentQueue storefront]':
270+
if (testReturnNull) {
271+
return Future<dynamic>.value();
272+
}
273+
return Future<Map<String, dynamic>>.value(const <String, dynamic>{
274+
'countryCode': 'USA',
275+
'identifier': 'unique_identifier',
276+
});
253277
case '-[InAppPurchasePlugin addPayment:result:]':
254278
payments.add(SKPaymentWrapper.fromJson(Map<String, dynamic>.from(
255279
call.arguments as Map<dynamic, dynamic>)));

0 commit comments

Comments
 (0)