[in_app_purchase_storekit] Add show manage subscriptions path - #12454
[in_app_purchase_storekit] Add show manage subscriptions path#12454Hari-07 wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the showManageSubscriptions method to the InAppPurchaseStoreKitPlatformAddition class, enabling users to manage subscriptions via the App Store sheet on iOS 15+ using StoreKit 2. The changes include the Swift implementation, Pigeon-generated code, an example app button, and corresponding unit tests. Feedback recommends moving UIKit property access inside the @MainActor task block in Swift to ensure thread safety, and catching potential exceptions in the example app's onPressed callback to prevent unhandled asynchronous errors.
| guard let windowScene = self.registrar?.viewController?.view.window?.windowScene else { | ||
| let error = PigeonError( | ||
| code: "storekit2_missing_key_window_scene", | ||
| message: "Failed to fetch key window scene", | ||
| details: "registrar.viewController.view.window.windowScene returned nil." | ||
| ) | ||
| completion(.failure(error)) | ||
| return | ||
| } | ||
| Task { @MainActor in | ||
| do { | ||
| try await AppStore.showManageSubscriptions(in: windowScene) | ||
| completion(.success(())) | ||
| } catch { | ||
| completion(.failure(error)) | ||
| } | ||
| } |
There was a problem hiding this comment.
Accessing UIKit properties such as viewController, view, window, and windowScene must be done on the main thread (@MainActor). Currently, the guard statement retrieves the windowScene before entering the @MainActor task block, which can lead to thread-safety issues or crashes if this method is invoked from a background thread. Moving the entire guard statement inside the @MainActor task ensures safe UI-related operations.
| guard let windowScene = self.registrar?.viewController?.view.window?.windowScene else { | |
| let error = PigeonError( | |
| code: "storekit2_missing_key_window_scene", | |
| message: "Failed to fetch key window scene", | |
| details: "registrar.viewController.view.window.windowScene returned nil." | |
| ) | |
| completion(.failure(error)) | |
| return | |
| } | |
| Task { @MainActor in | |
| do { | |
| try await AppStore.showManageSubscriptions(in: windowScene) | |
| completion(.success(())) | |
| } catch { | |
| completion(.failure(error)) | |
| } | |
| } | |
| Task { @MainActor in | |
| guard let windowScene = self.registrar?.viewController?.view.window?.windowScene else { | |
| let error = PigeonError( | |
| code: "storekit2_missing_key_window_scene", | |
| message: "Failed to fetch key window scene", | |
| details: "registrar.viewController.view.window.windowScene returned nil." | |
| ) | |
| completion(.failure(error)) | |
| return | |
| } | |
| do { | |
| try await AppStore.showManageSubscriptions(in: windowScene) | |
| completion(.success(())) | |
| } catch { | |
| completion(.failure(error)) | |
| } | |
| } |
There was a problem hiding this comment.
I think this is more correct but I was reflecting the pattern in presentOfferCodeRedeemSheet. Happy to update this one or both
| backgroundColor: Theme.of(context).colorScheme.primary, | ||
| foregroundColor: Colors.white, | ||
| ), | ||
| onPressed: () => _iapStoreKitPlatformAddition.showManageSubscriptions(), |
There was a problem hiding this comment.
The showManageSubscriptions method returns a Future<void> and can throw an exception (for example, on unsupported platforms like macOS or iOS versions below 15). Since this future is not awaited or caught in the onPressed callback, any thrown error will result in an unhandled asynchronous exception. It is highly recommended to catch the error and display a user-friendly message (e.g., using a SnackBar) to handle these expected platform limitations gracefully.
onPressed: () async {
try {
await _iapStoreKitPlatformAddition.showManageSubscriptions();
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
}
}
},There was a problem hiding this comment.
I think this is ok for the internal example
|
I wasn't sure if we need to do something in |
Adds a new
showManageSubscriptionsmethod which wraps around storekit's showManageSubscriptions(in:)Fixes flutter/flutter#159664
Pre-Review Checklist
[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2