Skip to content

Commit 8c1ef69

Browse files
LouiseHsuandroidseb
authored andcommitted
[in_app_purchase] add Storefront.countryCode() and AppStore.sync() (flutter#8900)
Fixes flutter/flutter#159631 and fixes flutter/flutter#165659 Adds iap support for accessing store front country code and manual transaction syncing. ## Pre-Review Checklist
1 parent 797db36 commit 8c1ef69

File tree

14 files changed

+497
-27
lines changed

14 files changed

+497
-27
lines changed

packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.3.22
2+
3+
* Adds `sync()` and `countryCode()`.
4+
15
## 0.3.21
26

37
* Adds Swift Package Manager compatibility.

packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/InAppPurchasePlugin+StoreKit2.swift

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import StoreKit
66

77
@available(iOS 15.0, macOS 12.0, *)
88
extension InAppPurchasePlugin: InAppPurchase2API {
9-
109
// MARK: - Pigeon Functions
1110

1211
/// Wrapper method around StoreKit2's canMakePayments() method
@@ -146,6 +145,43 @@ extension InAppPurchasePlugin: InAppPurchase2API {
146145
}
147146
}
148147

148+
/// Wrapper method around StoreKit2's countryCode() method
149+
/// https://developer.apple.com/documentation/storekit/storefront/countrycode
150+
func countryCode(completion: @escaping (Result<String, Error>) -> Void) {
151+
Task {
152+
guard let currentStorefront = await Storefront.current else {
153+
let error = PigeonError(
154+
code: "storekit2_failed_to_fetch_country_code",
155+
message: "Storekit has failed to fetch the country code.",
156+
details: "Storefront.current returned nil.")
157+
completion(.failure(error))
158+
return
159+
}
160+
completion(.success(currentStorefront.countryCode))
161+
return
162+
}
163+
}
164+
165+
/// Wrapper method around StoreKit2's sync() method
166+
/// https://developer.apple.com/documentation/storekit/appstore/sync()
167+
/// When called, a system prompt will ask users to enter their authentication details
168+
func sync(completion: @escaping (Result<Void, Error>) -> Void) {
169+
Task {
170+
do {
171+
try await AppStore.sync()
172+
completion(.success(()))
173+
return
174+
} catch {
175+
let pigeonError = PigeonError(
176+
code: "storekit2_failed_to_sync_to_app_store",
177+
message: "Storekit has failed to sync to the app store.",
178+
details: "\(error)")
179+
completion(.failure(pigeonError))
180+
return
181+
}
182+
}
183+
}
184+
149185
/// This Task listens to Transation.updates as shown here
150186
/// https://developer.apple.com/documentation/storekit/transaction/3851206-updates
151187
/// This function should be called as soon as the app starts to avoid missing any Transactions done outside of the app.

packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/sk2_pigeon.g.swift

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2013 The Flutter Authors. All rights reserved.
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
4-
// Autogenerated from Pigeon (v22.7.3), do not edit directly.
4+
// Autogenerated from Pigeon (v25.1.0), do not edit directly.
55
// See also: https://pub.dev/packages/pigeon
66

77
import Foundation
@@ -18,9 +18,9 @@ import Foundation
1818
final class PigeonError: Error {
1919
let code: String
2020
let message: String?
21-
let details: Any?
21+
let details: Sendable?
2222

23-
init(code: String, message: String?, details: Any?) {
23+
init(code: String, message: String?, details: Sendable?) {
2424
self.code = code
2525
self.message = message
2626
self.details = details
@@ -521,6 +521,8 @@ protocol InAppPurchase2API {
521521
func startListeningToTransactions() throws
522522
func stopListeningToTransactions() throws
523523
func restorePurchases(completion: @escaping (Result<Void, Error>) -> Void)
524+
func countryCode(completion: @escaping (Result<String, Error>) -> Void)
525+
func sync(completion: @escaping (Result<Void, Error>) -> Void)
524526
}
525527

526528
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@@ -676,6 +678,41 @@ class InAppPurchase2APISetup {
676678
} else {
677679
restorePurchasesChannel.setMessageHandler(nil)
678680
}
681+
let countryCodeChannel = FlutterBasicMessageChannel(
682+
name:
683+
"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchase2API.countryCode\(channelSuffix)",
684+
binaryMessenger: binaryMessenger, codec: codec)
685+
if let api = api {
686+
countryCodeChannel.setMessageHandler { _, reply in
687+
api.countryCode { result in
688+
switch result {
689+
case .success(let res):
690+
reply(wrapResult(res))
691+
case .failure(let error):
692+
reply(wrapError(error))
693+
}
694+
}
695+
}
696+
} else {
697+
countryCodeChannel.setMessageHandler(nil)
698+
}
699+
let syncChannel = FlutterBasicMessageChannel(
700+
name: "dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchase2API.sync\(channelSuffix)",
701+
binaryMessenger: binaryMessenger, codec: codec)
702+
if let api = api {
703+
syncChannel.setMessageHandler { _, reply in
704+
api.sync { result in
705+
switch result {
706+
case .success:
707+
reply(wrapResult(nil))
708+
case .failure(let error):
709+
reply(wrapError(error))
710+
}
711+
}
712+
}
713+
} else {
714+
syncChannel.setMessageHandler(nil)
715+
}
679716
}
680717
}
681718
/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.
@@ -713,7 +750,7 @@ class InAppPurchase2CallbackAPI: InAppPurchase2CallbackAPIProtocol {
713750
let details: String? = nilOrValue(listResponse[2])
714751
completion(.failure(PigeonError(code: code, message: message, details: details)))
715752
} else {
716-
completion(.success(Void()))
753+
completion(.success(()))
717754
}
718755
}
719756
}

packages/in_app_purchase/in_app_purchase_storekit/lib/src/in_app_purchase_storekit_platform.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ class InAppPurchaseStoreKitPlatform extends InAppPurchasePlatform {
241241
/// See: https://developer.apple.com/documentation/storekit/skstorefront?language=objc
242242
@override
243243
Future<String> countryCode() async {
244+
if (_useStoreKit2) {
245+
return Storefront().countryCode();
246+
}
244247
return (await _skPaymentQueueWrapper.storefront())?.countryCode ?? '';
245248
}
246249

packages/in_app_purchase/in_app_purchase_storekit/lib/src/in_app_purchase_storekit_platform_addition.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,25 @@
33
// found in the LICENSE file.
44

55
import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
6-
import '../in_app_purchase_storekit.dart';
76

7+
import '../in_app_purchase_storekit.dart';
8+
import '../store_kit_2_wrappers.dart';
89
import '../store_kit_wrappers.dart';
910

1011
/// Contains InApp Purchase features that are only available on iOS.
1112
class InAppPurchaseStoreKitPlatformAddition
1213
extends InAppPurchasePlatformAddition {
14+
/// Synchronizes your app’s transaction information and subscription status
15+
/// with information from the App Store.
16+
/// Storekit 2 only
17+
Future<void> sync() {
18+
return AppStore().sync();
19+
}
20+
1321
/// Present Code Redemption Sheet.
1422
///
1523
/// Available on devices running iOS 14 and iPadOS 14 and later.
24+
/// Available for StoreKit 1 and 2
1625
Future<void> presentCodeRedemptionSheet() {
1726
return SKPaymentQueueWrapper().presentCodeRedemptionSheet();
1827
}

0 commit comments

Comments
 (0)