Skip to content

fix: map PlatformException to proper ErrorCode in all methods#621

Merged
hyochan merged 4 commits intomainfrom
fix/map-platform-exception-error-codes
Feb 27, 2026
Merged

fix: map PlatformException to proper ErrorCode in all methods#621
hyochan merged 4 commits intomainfrom
fix/map-platform-exception-error-codes

Conversation

@hyochan
Copy link
Copy Markdown
Owner

@hyochan hyochan commented Feb 26, 2026

Summary

  • Map PlatformException error codes from native iOS/Android to correct ErrorCode values using existing ErrorCodeUtils.fromPlatformCode() infrastructure
  • Previously all PlatformException errors were hardcoded to ErrorCode.ServiceError, losing the actual error code (e.g., user-cancelled -> UserCancelled)
  • Added _purchaseErrorFromPlatformException helper and updated 11 methods

Changes

Dart Library (lib/)

  • Add _purchaseErrorFromPlatformException helper method
  • Update catch blocks in: initConnection, endConnection, requestPurchase, getAvailablePurchases, getStorefront, getStorefrontIOS, presentCodeRedemptionSheetIOS, showManageSubscriptionsIOS, _fetchProductsInternal, getActiveSubscriptions, isEligibleForExternalPurchaseCustomLinkIOS

Tests (test/)

  • Add 5 new tests verifying error code mapping (user-cancelled, service-error, E_SERVICE_ERROR, E_NETWORK_ERROR, item-unavailable)
  • Update existing tests to use proper platform error codes instead of generic 'platform' / '500'

Closes #619

Test plan

  • dart format --page-width 80 --set-exit-if-changed passes
  • flutter analyze passes
  • flutter test passes (213 tests)

Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Centralized and standardized platform error handling across in-app purchase flows, mapping platform errors to consistent PurchaseError codes and adding clearer, operation-specific messages.
  • Tests

    • Added comprehensive unit tests for platform-error → PurchaseError mappings, updated tests to reflect more granular platform error codes, and added tests for purchase property behaviors.
  • Documentation

    • Added code-coverage guidance and pre-commit coverage instructions.

PlatformException from native iOS/Android was being caught generically
and always mapped to ErrorCode.ServiceError, losing the actual error
code (e.g., user-cancelled). Now uses ErrorCodeUtils.fromPlatformCode()
to preserve the correct error code across 11 methods.

Closes #619

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a926c05 and 2559cd9.

📒 Files selected for processing (1)
  • CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • CLAUDE.md

📝 Walkthrough

Walkthrough

Introduces a centralized PlatformException→PurchaseError translator and applies it across initialization, connection, purchase, product, storefront, and subscription flows; adds unit tests updating mocked platform error codes and new PurchaseHelpers tests; documentation adds Codecov guidance.

Changes

Cohort / File(s) Summary
Core Error Translation
lib/flutter_inapp_purchase.dart
Adds a private helper to map PlatformExceptionPurchaseError (operation-aware, platform-aware) and replaces scattered PlatformException handling across init, connection, purchase, product fetch, storefront, subscription, and related methods.
Error Mapping Tests
test/errors_unit_test.dart
Adds comprehensive unit tests verifying mapping of many PlatformException codes (e.g., user-cancelled, service-error, E_NETWORK_ERROR, item-unavailable) to PurchaseError across multiple APIs.
Channel & iOS Tests
test/flutter_inapp_purchase_channel_test.dart, test/ios_methods_test.dart
Updates mocked platform error codes in tests from generic to specific codes (not-prepared, service-error, E_SERVICE_ERROR, etc.) to reflect refined mapping behavior.
Purchase Helpers Tests
test/purchase_helpers_test.dart
Adds unit tests for PurchaseHelpers extension covering transactionId resolution, platform-specific state/fields, quantity, and acknowledgement behaviour.
Docs / CI
CLAUDE.md
Documentation-only additions: Codecov coverage guidance and pre-commit coverage check instructions; no functional code changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

👨🏻‍🔧 bugfix

Poem

🐰 A hop, a catch, a tidy mend,
Platform errors now gently penned.
Cancels named right, faults put to bed,
Tests snug in burrows, worries shed.
Hooray — the in-app meadow’s fed!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: map PlatformException to proper ErrorCode in all methods' accurately describes the main change—implementing centralized PlatformException-to-ErrorCode mapping across multiple IAP methods.
Linked Issues check ✅ Passed The PR fully addresses issue #619 by implementing PlatformException-to-ErrorCode mapping (including UserCancelled, ServiceError, NetworkError, ItemUnavailable) and adds comprehensive tests verifying the mappings work correctly across all methods.
Out of Scope Changes check ✅ Passed All changes are in scope: error mapping implementation in flutter_inapp_purchase.dart, error-code mapping tests in errors_unit_test.dart, test updates for proper error codes, and documentation updates in CLAUDE.md are all related to the error handling objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/map-platform-exception-error-codes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the error handling within the in-app purchase plugin by ensuring that native platform exceptions are accurately translated into specific ErrorCode values. Previously, all PlatformException instances were caught and re-thrown as a generic ServiceError, which obscured the actual cause of the failure. By introducing a dedicated helper and integrating it into numerous methods, the plugin now provides more granular and informative error reporting, making debugging and user feedback more precise.

Highlights

  • Improved Error Handling: Implemented a mechanism to map native iOS/Android PlatformException error codes to specific ErrorCode values, replacing the previous generic ErrorCode.ServiceError.
  • New Helper Method: Introduced _purchaseErrorFromPlatformException to centralize the conversion of PlatformException to PurchaseError with appropriate ErrorCode.
  • Extensive Method Updates: Updated 11 methods across the FlutterInappPurchase class to utilize the new error mapping helper for PlatformException.
  • Enhanced Test Coverage: Added 5 new tests specifically to verify the correct mapping of various PlatformException error codes (e.g., user-cancelled, service-error, network-error, item-unavailable).
  • Refined Existing Tests: Modified existing tests to use more accurate platform-specific error codes instead of generic ones, improving test realism.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • lib/flutter_inapp_purchase.dart
    • Added _purchaseErrorFromPlatformException helper method.
    • Updated catch blocks in initConnection, endConnection, requestPurchase, getAvailablePurchases, getStorefront, getStorefrontIOS, presentCodeRedemptionSheetIOS, showManageSubscriptionsIOS, _fetchProductsInternal, getActiveSubscriptions, and isEligibleForExternalPurchaseCustomLinkIOS to use the new error mapping.
  • test/errors_unit_test.dart
    • Added new imports for Platform, PlatformException, and FlutterInappPurchase.
    • Introduced a new test group for PlatformException error code mapping.
    • Added 5 new tests to verify specific PlatformException codes map to correct ErrorCode values (e.g., user-cancelled to UserCancelled, E_NETWORK_ERROR to NetworkError).
  • test/flutter_inapp_purchase_channel_test.dart
    • Updated mock PlatformException codes in initConnection, endConnection, and getAvailableItems tests to use more specific error codes like not-prepared and service-error.
  • test/ios_methods_test.dart
    • Updated the mock PlatformException code in the isEligibleForExternalPurchaseCustomLinkIOS test from 500 to service-error.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant improvement in error handling by consistently mapping PlatformExceptions to specific ErrorCodes. The new _purchaseErrorFromPlatformException helper centralizes this logic, enhancing maintainability. The accompanying test additions and updates are thorough and ensure the new functionality is well-covered. The changes are well-implemented, but I've noted one minor inconsistency in an error handling pattern that could be aligned with the rest of the changes for better code consistency.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
lib/flutter_inapp_purchase.dart (1)

1722-1737: Preserve mapped platform on the emitted PurchaseError.

Line 1732 builds PurchaseError without setting platform, even though platform is already determined for code mapping. Passing it explicitly keeps error metadata consistent with the mapped code.

♻️ Proposed tweak
   PurchaseError _purchaseErrorFromPlatformException(
     PlatformException error,
     String operation,
   ) {
-    final errorCode = errors.ErrorCodeUtils.fromPlatformCode(
-      error.code,
-      _platform.isIOS || _platform.isMacOS
-          ? gentype.IapPlatform.IOS
-          : gentype.IapPlatform.Android,
-    );
+    final platform = _platform.isIOS || _platform.isMacOS
+        ? gentype.IapPlatform.IOS
+        : gentype.IapPlatform.Android;
+    final errorCode = errors.ErrorCodeUtils.fromPlatformCode(
+      error.code,
+      platform,
+    );
     return PurchaseError(
       code: errorCode,
+      platform: platform,
       message: 'Failed to $operation [${error.code}]: '
           '${error.message ?? error.details}',
     );
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/flutter_inapp_purchase.dart` around lines 1722 - 1737, In
_purchaseErrorFromPlatformException, you determine the mapped platform for error
codes but don’t set it on the returned PurchaseError; compute and store the
chosen platform (the gentype.IapPlatform value used in
errors.ErrorCodeUtils.fromPlatformCode) in a local variable and pass it into the
PurchaseError constructor as the platform field so the emitted PurchaseError
includes the same platform metadata as the mapped error code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lib/flutter_inapp_purchase.dart`:
- Around line 1722-1737: In _purchaseErrorFromPlatformException, you determine
the mapped platform for error codes but don’t set it on the returned
PurchaseError; compute and store the chosen platform (the gentype.IapPlatform
value used in errors.ErrorCodeUtils.fromPlatformCode) in a local variable and
pass it into the PurchaseError constructor as the platform field so the emitted
PurchaseError includes the same platform metadata as the mapped error code.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de0a16c and 90dff9c.

📒 Files selected for processing (4)
  • lib/flutter_inapp_purchase.dart
  • test/errors_unit_test.dart
  • test/flutter_inapp_purchase_channel_test.dart
  • test/ios_methods_test.dart

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 27, 2026

Codecov Report

❌ Patch coverage is 70.45455% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.94%. Comparing base (de0a16c) to head (2559cd9).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/flutter_inapp_purchase.dart 70.45% 13 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #621      +/-   ##
==========================================
+ Coverage   68.11%   69.94%   +1.83%     
==========================================
  Files           7        7              
  Lines        1521     1554      +33     
==========================================
+ Hits         1036     1087      +51     
+ Misses        485      467      -18     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Add platform field to PurchaseError from _purchaseErrorFromPlatformException
- Unify getActiveSubscriptions to use on PlatformException catch pattern
- Add tests for endConnection, getStorefront, getStorefrontIOS,
  presentCodeRedemptionSheetIOS, showManageSubscriptionsIOS,
  getActiveSubscriptions, isEligibleForExternalPurchaseCustomLinkIOS
- Add test verifying platform field is set on mapped errors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
lib/flutter_inapp_purchase.dart (1)

1721-1739: Consider using getCurrentPlatform() for platform detection.

The helper method correctly maps PlatformException to PurchaseError using ErrorCodeUtils.fromPlatformCode. However, based on learnings, prefer using errors.getCurrentPlatform() over inline platform conditionals for consistent runtime platform reporting in error handling.

♻️ Suggested refactor
  PurchaseError _purchaseErrorFromPlatformException(
    PlatformException error,
    String operation,
  ) {
-   final platform = _platform.isIOS || _platform.isMacOS
-       ? gentype.IapPlatform.IOS
-       : gentype.IapPlatform.Android;
+   final platform = errors.getCurrentPlatform();
    final errorCode = errors.ErrorCodeUtils.fromPlatformCode(
      error.code,
      platform,
    );

Based on learnings: "In flutter_inapp_purchase project, prefer using iap_err.getCurrentPlatform() in error handling over hardcoded platform constants to ensure accurate runtime platform reporting in error messages and debugging."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/flutter_inapp_purchase.dart` around lines 1721 - 1739, In
_purchaseErrorFromPlatformException replace the inline platform detection
(_platform.isIOS || _platform.isMacOS ? gentype.IapPlatform.IOS :
gentype.IapPlatform.Android) with the canonical runtime helper
errors.getCurrentPlatform() (or the appropriate getCurrentPlatform() exported by
the errors/iap_err module) and pass that platform into
errors.ErrorCodeUtils.fromPlatformCode and the PurchaseError.platform field so
runtime platform reporting is consistent for ErrorCodeUtils.fromPlatformCode and
the returned PurchaseError.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lib/flutter_inapp_purchase.dart`:
- Around line 1721-1739: In _purchaseErrorFromPlatformException replace the
inline platform detection (_platform.isIOS || _platform.isMacOS ?
gentype.IapPlatform.IOS : gentype.IapPlatform.Android) with the canonical
runtime helper errors.getCurrentPlatform() (or the appropriate
getCurrentPlatform() exported by the errors/iap_err module) and pass that
platform into errors.ErrorCodeUtils.fromPlatformCode and the
PurchaseError.platform field so runtime platform reporting is consistent for
ErrorCodeUtils.fromPlatformCode and the returned PurchaseError.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 90dff9c and 57bafb7.

📒 Files selected for processing (2)
  • lib/flutter_inapp_purchase.dart
  • test/errors_unit_test.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/errors_unit_test.dart

- Add 20 tests for PurchaseHelpers extension (0% -> 100% coverage)
- Add codecov management section to CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CLAUDE.md`:
- Around line 101-106: The fenced code block in the numbered list item is
missing blank lines above and below (MD031); edit the CLAUDE.md list item
containing the fenced block with the two commands (flutter test --coverage and
dart run tool/filter_coverage.dart) to insert an empty line before the opening
``` and an empty line after the closing ``` so the block is surrounded by blank
lines.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57bafb7 and a926c05.

📒 Files selected for processing (2)
  • CLAUDE.md
  • test/purchase_helpers_test.dart

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@hyochan hyochan merged commit 79d0f7d into main Feb 27, 2026
8 checks passed
@hyochan hyochan deleted the fix/map-platform-exception-error-codes branch February 27, 2026 04:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Map user-cancelled PlatformException to PurchaseError on purchase flow cancellation

1 participant