-
-
Notifications
You must be signed in to change notification settings - Fork 633
Description
Describe the bug
The initCustomerSheet method has a misleading return type (Future<CustomerSheetResult?>) that doesn't match its actual behavior or the React Native SDK implementation.
Current behavior:
- Type definition:
Future<CustomerSheetResult?>(includespaymentOption,paymentMethod,errorfields) - Actual return value: Always
nullon success, throws exception on error - React Native SDK:
Promise<{ error?: StripeError }>(error only)
The CustomerSheetResult type suggests payment option information will be returned, but it never is. This creates confusion for developers who expect to receive payment selection data from initialization.
To Reproduce
Steps to reproduce the behavior:
- Call
initCustomerSheetand check the return value:
final result = await Stripe.instance.initCustomerSheet(
customerSheetInitParams: CustomerSheetInitParams(
customerId: customerId,
customerEphemeralKeySecret: ephemeralKey,
merchantDisplayName: 'Test',
),
);
print(result); // Always null- Call
retrieveCustomerSheetPaymentOptionSelectionimmediately after:
final selection = await Stripe.instance.retrieveCustomerSheetPaymentOptionSelection();
print(selection); // Can contain payment option data- Observe that
initCustomerSheetreturnsnulleven when payment options exist, whileretrieveCustomerSheetPaymentOptionSelectioncan retrieve them right after.
Expected behavior
The return type should match the actual behavior and align with React Native SDK:
Future<void> initCustomerSheet(...) // Throws exception on errorSmartphone / tablet
- Device: N/A (API design issue)
- OS: iOS, Android (both platforms affected)
- Package version: Current main branch
- Flutter version: All versions
Additional context
Root cause analysis:
The Flutter implementation has a misleading type definition and unnecessary complexity:
// Current implementation
Future<CustomerSheetResult?> initCustomerSheet(...) async {
final result = await _methodChannel.invokeMethod(...);
if (result is List) {
return null; // iOS case
} else {
return _parseCustomerSheetResult(result); // Android case
}
}Issues:
- Misleading type:
CustomerSheetResult?suggests payment data might be returned, but it never is - Unnecessary parsing: Calls
_parseCustomerSheetResulteven though result is always empty on success - Platform-specific logic: Special handling for iOS (array) vs Android (map)
Native implementations return empty values on success:
- iOS: Empty array
[] - Android: Empty map
WritableNativeMap()
Both indicate success, but the Flutter layer treats them differently and returns null in both cases anyway.
React Native SDK comparison:
React Native correctly returns only error information:
const { error } = await CustomerSheet.initialize({...});Source: https://stripe.dev/stripe-react-native/api-reference/variables/CustomerSheet.html
Evidence that return value is not used:
Even the official example ignores the return value:
// example/lib/screens/customer_sheet/customer_sheet_screen.dart:90
await Stripe.instance.initCustomerSheet(
customerSheetInitParams: CustomerSheetInitParams(/* ... */),
);
// No variable assignmentProposed fix:
Future<void> initCustomerSheet(
CustomerSheetInitParams params,
) async {
final result = await _methodChannel.invokeMethod('initCustomerSheet', {
'params': params.toJson(),
'customerAdapterOverrides': {},
});
// Check for errors only
// iOS returns empty array, Android returns empty map on success - both are fine
if (result is Map<String, dynamic> && result['error'] != null) {
result['runtimeType'] = 'failed';
throw StripeException.fromJson(result);
}
}Changes:
- Return type:
Future<CustomerSheetResult?>→Future<void> - Simplified to error-checking only (no unnecessary parsing)
- Works with both iOS (array) and Android (map) seamlessly
- Update documentation if needed
Note: Native implementations (iOS/Android) don't need to be changed. The fix is purely on the Flutter side.