# Flutter storefront adapter

The optional `appvision_iap_flutter` package connects Flutter's official `in_app_purchase` plugin to the `appvision_iap_client` Dart core. Its current package version is 0.3.0 and it consumes core 0.5.0. The adapter requires Dart 3.12 and Flutter 3.44 or later according to the checked-in manifest.

## Add source dependencies

Public pub.dev publication is disabled in this preview. With an approved local source checkout, configure your app's paths and override the core package consistently:

```yaml
dependencies:
  flutter:
    sdk: flutter
  in_app_purchase: ^3.3.0
  appvision_iap_flutter:
    path: ../cherrysub/sdk/flutter

dependency_overrides:
  appvision_iap_client:
    path: ../cherrysub/sdk/dart
```

Adjust paths to your project. Run `flutter pub get`. The Flutter adapter re-exports the core SDK; it does not replace your app's billing UI or authenticated backend.

## Configure the Dart client

Use an `InMemoryCustomerTokenProvider` and `IapClient` as shown in the [Dart guide](/docs/dart), importing:

```dart
import 'package:appvision_iap_flutter/appvision_iap_flutter.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
```

Use `iap_pk_` and your authenticated token broker. Load `iap.currentProductSet(user.id)`, keep packages for the current platform, and resolve their store product details using the purchase plugin.

## Process the purchase stream

Subscribe to the plugin's purchase updates for both newly purchased and restored transactions. Handle pending/error/cancel states in your UI without treating them as verified access.

```dart
for (final PurchaseDetails purchase in purchases) {
  if (purchase.status == PurchaseStatus.purchased ||
      purchase.status == PurchaseStatus.restored) {
    await iap.submitAndCompletePurchaseDetails(
      appUserId: user.id,
      purchase: purchase,
      googleProductType: purchase.verificationData.source == 'google_play'
          ? GoogleProductType.subscription
          : null,
    );
  }
}
```

Replace `subscription` with the correct product type for a Google one-time product; this example is a subscription handler.

## Store-specific evidence and completion

Apple purchases must be `SK2PurchaseDetails`, whose server verification data is the StoreKit transaction JWS. A StoreKit 1 purchase detail is not an interchangeable payload. Google purchases must be `GooglePlayPurchaseDetails`, whose server data is the purchase token.

Only `purchased` and `restored` are accepted. `completePurchase` runs after the backend accepts the evidence, and failure leaves the transaction unfinished for recovery. Do not independently complete the same purchase earlier in another callback.

After acceptance, fetch the subscriber and update your UI from its access map. Your app owns consumable policy, stream subscription cleanup, and presentation of unavailable products or store errors.

## Authentication and account changes

The core provider caches per authenticated user and refreshes before expiry. Invalidate the departing user on logout, clear local access UI, and obtain a new token for the next account before restoring purchases. If your policy requires token revocation, perform it on the backend too.

No SDK customer token is persisted automatically. Do not store an `iap_sk_` or service-account JSON in Flutter assets or compile-time client defines.

## Validate

Run the adapter's `flutter test` and the core Dart tests when modifying source integration. Test Apple StoreKit 2 and Google Play separately, including restored/pending purchases, backend failure before completion, one-time versus subscription product type, and logout during token refresh. [Purchase lifecycle](/docs/receipts-and-restores) · [Testing](/docs/testing).
