[in_app_purchase] Implementation of the app facing package (#3877)

* Start with app-facing package

* Update to pub version of platform interface

* Update CHANGELOG with feedback from PR

* Fix some spelling mistakes

* Update CHANGELOG with feedback from PR

* Update README with new features

* Update dependencies and links in documentation

* Remove iOS test from example project

* Remove test target from Podfile

* Remove test from Xcode scheme
diff --git a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md
index 45b8b76..5e369b8 100644
--- a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md
+++ b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md
@@ -1,3 +1,35 @@
+## 0.6.0
+
+As part of implementing federated architecture and making the interface compatible for other platforms this version contains the following **breaking changes**:
+
+* Changes to the platform agnostic interface:
+  * If you used `InAppPurchaseConnection.instance` to access generic In App Purchase APIs, please use `InAppPurchase.instance` instead;
+  * The `InAppPurchaseConnection.purchaseUpdatedStream` has been renamed to `InAppPurchase.purchaseStream`;
+  * The `InAppPurchaseConnection.queryPastPurchases` method has been removed. Instead, you should use `InAppPurchase.restorePurchases`. This method emits each restored purchase on the `InAppPurchase.purchaseStream`, the `PurchaseDetails` object will be marked with a `status` of `PurchaseStatus.restored`;
+  * The `InAppPurchase.completePurchase` method no longer returns an instance `BillingWrapperResult` class (which was Android specific). Instead it will return a completed `Future` if the method executed successfully, in case of errors it will complete with an `InAppPurchaseException` describing the error.
+* Android specific changes:
+  * The Android specific `InAppPurchaseConnection.consumePurchase` and `InAppPurchaseConnection.enablePendingPurchases` methods have been removed from the platform agnostic interface and moved to the Android specific `InAppPurchaseAndroidPlatformAddition` class:
+    * `InAppPurchaseAndroidPlatformAddition.enablePendingPurchases` is a static method that should be called when initializing your App. Access the method like this: `InAppPurchaseAndroidPlatformAddition.enablePendingPurchases()` (make sure to add the following import: `import 'package:in_app_purchase_android/in_app_purchase_android.dart';`);
+    * To use the `InAppPurchaseAndroidPlatformAddition.consumePurchase` method, acquire an instance using the `InAppPurchase.getPlatformAddition` method. For example:
+  ```dart
+  // Acquire the InAppPurchaseAndroidPlatformAddition instance.
+  InAppPurchaseAndroidPlatformAddition androidAddition = InAppPurchase.instance.getPlatformAddition<InAppPurchaseAndroidPlatformAddition>();
+  // Consume an Android purchase.
+  BillingResultWrapper billingResult = await androidAddition.consumePurchase(purchase);
+  ```
+  * The [billing_client_wrappers](https://pub.dev/documentation/in_app_purchase_android/latest/billing_client_wrappers/billing_client_wrappers-library.html) have been moved into the [in_app_purchase_android](https://pub.dev/packages/in_app_purchase_android) package. They are still available through the [in_app_purchase](https://pub.dev/packages/in_app_purchase) plugin but to use them it is necessary to import the correct package when using them: `import 'package:in_app_purchase_android/billing_client_wrappers.dart';`;
+* iOS specific changes:
+  * The iOS specific methods `InAppPurchaseConnection.presentCodeRedemptionSheet` and `InAppPurchaseConnection.refreshPurchaseVerificationData` methods have been removed from the platform agnostic interface and moved into the iOS specific `InAppPurchaseIosPlatformAddition` class. To use them acquire an instance through the `InAppPurchase.getPlatformAddition` method like so:
+  ```dart
+  // Acquire the InAppPurchaseIosPlatformAddition instance.
+  InAppPurchaseIosPlatformAddition iosAddition = InAppPurchase.instance.getPlatformAddition<InAppPurchaseIosPlatformAddition>();
+  // Present the code redemption sheet.
+  await iosAddition.presentCodeRedemptionSheet();
+  // Refresh purchase verification data.
+  PurchaseVerificationData? verificationData = await iosAddition.refreshPurchaseVerificationData(); 
+  ```
+  * The [store_kit_wrappers](https://pub.dev/documentation/in_app_purchase_ios/latest/store_kit_wrappers/store_kit_wrappers-library.html) have been moved into the [in_app_purchase_ios](https://pub.dev/packages/in_app_purchase_ios) package. They are still available in the [in_app_purchase](https://pub.dev/packages/in_app_purchase) plugin, but to use them it is necessary to import the correct package when using them: `import 'package:in_app_purchase_ios/store_kit_wrappers.dart';`;
+
 ## 0.5.2
 
 * Added `rawPrice` and `currencyCode` to the ProductDetails model.
diff --git a/packages/in_app_purchase/in_app_purchase/README.md b/packages/in_app_purchase/in_app_purchase/README.md
index 7e433a0..74b90fe 100644
--- a/packages/in_app_purchase/in_app_purchase/README.md
+++ b/packages/in_app_purchase/in_app_purchase/README.md
@@ -44,8 +44,8 @@
 1. A generic, idiomatic Flutter API: [in_app_purchase](https://pub.dev/documentation/in_app_purchase/latest/in_app_purchase/in_app_purchase-library.html).
    This API supports most use cases for loading and making purchases.
 
-2. Platform-specific Dart APIs: [store_kit_wrappers](https://pub.dev/documentation/in_app_purchase/latest/store_kit_wrappers/store_kit_wrappers-library.html)
-   and [billing_client_wrappers](https://pub.dev/documentation/in_app_purchase/latest/billing_client_wrappers/billing_client_wrappers-library.html).
+2. Platform-specific Dart APIs: [store_kit_wrappers](https://pub.dev/documentation/in_app_purchase_ios/latest/store_kit_wrappers/store_kit_wrappers-library.html)
+   and [billing_client_wrappers](https://pub.dev/documentation/in_app_purchase_android/latest/billing_client_wrappers/billing_client_wrappers-library.html).
    These APIs expose platform-specific behavior and allow for more fine-tuned
    control when needed. However, if you use one of these APIs, your
    purchase-handling logic is significantly different for the different
@@ -70,13 +70,17 @@
 The following initialization code is required for Google Play:
 
 ```dart
+// Import `in_app_purchase_android.dart` to be able to access the 
+// `InAppPurchaseAndroidPlatformAddition` class.
+import 'package:in_app_purchase_android/in_app_purchase_android.dart';
+
 void main() {
   // Inform the plugin that this app supports pending purchases on Android.
   // An error will occur on Android if you access the plugin `instance`
   // without this call.
-  //
-  // On iOS this is a no-op.
-  InAppPurchaseConnection.enablePendingPurchases();
+  if (defaultTargetPlatform == TargetPlatform.android) {
+    InAppPurchaseAndroidPlatformAddition.enablePendingPurchases();
+  }
   runApp(MyApp());
 }
 ```
@@ -98,7 +102,7 @@
   @override
   void initState() {
     final Stream purchaseUpdated =
-        InAppPurchaseConnection.instance.purchaseUpdatedStream;
+        InAppPurchase.instance.purchaseStream;
     _subscription = purchaseUpdated.listen((purchaseDetailsList) {
       _listenToPurchaseUpdated(purchaseDetailsList);
     }, onDone: () {
@@ -126,7 +130,8 @@
     } else {
       if (purchaseDetails.status == PurchaseStatus.error) {
         _handleError(purchaseDetails.error!);
-      } else if (purchaseDetails.status == PurchaseStatus.purchased) {
+      } else if (purchaseDetails.status == PurchaseStatus.purchased || 
+                 purchaseDetails.status == PurchaseStatus.restored) {
         bool valid = await _verifyPurchase(purchaseDetails);
         if (valid) {
           _deliverProduct(purchaseDetails);
@@ -136,7 +141,7 @@
         }
       }
       if (purchaseDetails.pendingCompletePurchase) {
-        await InAppPurchaseConnection.instance
+        await InAppPurchase.instance
             .completePurchase(purchaseDetails);
       }
     }
@@ -147,7 +152,7 @@
 ### Connecting to the underlying store
 
 ```dart
-final bool available = await InAppPurchaseConnection.instance.isAvailable();
+final bool available = await InAppPurchase.instance.isAvailable();
 if (!available) {
   // The store cannot be reached or accessed. Update the UI accordingly.
 }
@@ -160,38 +165,25 @@
 // `Set<String> _kIds = <String>['product1', 'product2'].toSet()`.
 const Set<String> _kIds = <String>{'product1', 'product2'};
 final ProductDetailsResponse response =
-    await InAppPurchaseConnection.instance.queryProductDetails(_kIds);
+    await InAppPurchase.instance.queryProductDetails(_kIds);
 if (response.notFoundIDs.isNotEmpty) {
   // Handle the error.
 }
 List<ProductDetails> products = response.productDetails;
 ```
 
-### Loading previous purchases
+### Restoring previous purchases
 
-In the following example, implement `_verifyPurchase` so that it verifies the
-purchase following the best practices for each underlying store:
+Restored purchases will be emitted on the `InAppPurchase.purchaseStream`, make
+sure to validate restored purchases following the best practices for each 
+underlying store:
 
 * [Verifying App Store purchases](https://developer.apple.com/documentation/storekit/in-app_purchase/validating_receipts_with_the_app_store)
 * [Verifying Google Play purchases](https://developer.android.com/google/play/billing/security#verify)
 
 
 ```dart
-final QueryPurchaseDetailsResponse response =
-    await InAppPurchaseConnection.instance.queryPastPurchases();
-if (response.error != null) {
-  // Handle the error.
-}
-for (PurchaseDetails purchase in response.pastPurchases) {
-  // Verify the purchase following best practices for each underlying store.
-  _verifyPurchase(purchase);
-  // Deliver the purchase to the user in your app.
-  _deliverPurchase(purchase);
-  if (purchase.pendingCompletePurchase) {
-    // Mark that you've delivered the purchase. This is mandatory.
-    InAppPurchaseConnection.instance.completePurchase(purchase);
-  }
-}
+await InAppPurchase.instance.restorePurchases();
 ```
 
 Note that the App Store does not have any APIs for querying consumable
@@ -203,30 +195,30 @@
 ### Making a purchase
 
 Both underlying stores handle consumable and non-consumable products differently. If
-you're using `InAppPurchaseConnection`, you need to make a distinction here and
+you're using `InAppPurchase`, you need to make a distinction here and
 call the right purchase method for each type.
 
 ```dart
-final ProductDetails productDetails = ... // Saved earlier from queryPastPurchases().
+final ProductDetails productDetails = ... // Saved earlier from queryProductDetails().
 final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
 if (_isConsumable(productDetails)) {
-  InAppPurchaseConnection.instance.buyConsumable(purchaseParam: purchaseParam);
+  InAppPurchase.instance.buyConsumable(purchaseParam: purchaseParam);
 } else {
-  InAppPurchaseConnection.instance.buyNonConsumable(purchaseParam: purchaseParam);
+  InAppPurchase.instance.buyNonConsumable(purchaseParam: purchaseParam);
 }
 // From here the purchase flow will be handled by the underlying store.
-// Updates will be delivered to the `InAppPurchaseConnection.instance.purchaseUpdatedStream`.
+// Updates will be delivered to the `InAppPurchase.instance.purchaseStream`.
 ```
 
 ### Completing a purchase
 
-The `InAppPurchaseConnection.purchaseUpdatedStream` will send purchase updates after
-you initiate the purchase flow using `InAppPurchaseConnection.buyConsumable` or `InAppPurchaseConnection.buyNonConsumable`.
-After delivering the content to the user, call
-`InAppPurchaseConnection.completePurchase` to tell the App Store and
-Google Play that the purchase has been finished.
+The `InAppPurchase.purchaseStream` will send purchase updates after
+you initiate the purchase flow using `InAppPurchase.buyConsumable` 
+or `InAppPurchase.buyNonConsumable`. After delivering the content to 
+the user, call `InAppPurchase.completePurchase` to tell the App Store
+and Google Play that the purchase has been finished.
 
-> **Warning:** Failure to call `InAppPurchaseConnection.completePurchase` and
+> **Warning:** Failure to call `InAppPurchase.completePurchase` and
 > get a successful response within 3 days of the purchase will result a refund.
 
 ### Upgrading or downgrading an existing in-app subscription
@@ -234,8 +226,8 @@
 To upgrade/downgrade an existing in-app subscription in Google Play,
 you need to provide an instance of `ChangeSubscriptionParam` with the old
 `PurchaseDetails` that the user needs to migrate from, and an optional
-`ProrationMode` with the `PurchaseParam` object while calling
-`InAppPurchaseConnection.buyNonConsumable`.
+`ProrationMode` with the `GooglePlayPurchaseParam` object while calling
+`InAppPurchase.buyNonConsumable`.
 
 The App Store does not require this because it provides a subscription
 grouping mechanism. Each subscription you offer must be assigned to a
@@ -246,12 +238,12 @@
 
 ```dart
 final PurchaseDetails oldPurchaseDetails = ...;
-PurchaseParam purchaseParam = PurchaseParam(
+PurchaseParam purchaseParam = GooglePlayPurchaseParam(
     productDetails: productDetails,
     changeSubscriptionParam: ChangeSubscriptionParam(
         oldPurchaseDetails: oldPurchaseDetails,
         prorationMode: ProrationMode.immediateWithTimeProration));
-InAppPurchaseConnection.instance
+InAppPurchase.instance
     .buyNonConsumable(purchaseParam: purchaseParam);
 ```
 
@@ -262,18 +254,18 @@
 redeeming offer codes, see [Implementing Offer Codes in Your App](https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/implementing_offer_codes_in_your_app).
 
 ```dart
-InAppPurchaseConnection.instance.presentCodeRedemptionSheet();
+InAppPurchaseIosPlatformAddition iosPlatformAddition = 
+  InAppPurchase.getPlatformAddition<InAppPurchaseIosPlatformAddition>();
+iosPlatformAddition.presentCodeRedemptionSheet();
 ```
 
-## Contributing to this plugin
+> **note:** The `InAppPurchaseIosPlatformAddition` is defined in the `in_app_purchase_ios.dart` 
+> file so you need to import it into the file you will be using `InAppPurchaseIosPlatformAddition`:
+> ```dart
+> import 'package:in_app_purchase_ios/in_app_purchase_ios.dart';
+> ```
 
-This plugin uses
-[json_serializable](https://pub.dev/packages/json_serializable) for the
-many data structs passed between the underlying platform layers and Dart. After
-editing any of the serialized data structs, rebuild the serializers by running
-`flutter packages pub run build_runner build --delete-conflicting-outputs`.
-`flutter packages pub run build_runner watch --delete-conflicting-outputs` will
-watch the filesystem for changes.
+## Contributing to this plugin
 
 If you would like to contribute to the plugin, check out our
 [contribution guide](https://github.com/flutter/plugins/blob/master/CONTRIBUTING.md).
diff --git a/packages/in_app_purchase/in_app_purchase/android/build.gradle b/packages/in_app_purchase/in_app_purchase/android/build.gradle
deleted file mode 100644
index a36f701..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/build.gradle
+++ /dev/null
@@ -1,48 +0,0 @@
-group 'io.flutter.plugins.inapppurchase'
-version '1.0-SNAPSHOT'
-
-buildscript {
-    repositories {
-        google()
-        jcenter()
-    }
-
-    dependencies {
-        classpath 'com.android.tools.build:gradle:3.3.0'
-    }
-}
-
-rootProject.allprojects {
-    repositories {
-        google()
-        jcenter()
-    }
-}
-
-apply plugin: 'com.android.library'
-
-android {
-    compileSdkVersion 29
-
-    defaultConfig {
-        minSdkVersion 16
-        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
-    }
-    lintOptions {
-        disable 'InvalidPackage'
-    }
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_8
-        targetCompatibility JavaVersion.VERSION_1_8
-    }
-}
-
-dependencies {
-    implementation 'androidx.annotation:annotation:1.0.0'
-    implementation 'com.android.billingclient:billing:3.0.2'
-    testImplementation 'junit:junit:4.12'
-    testImplementation 'org.json:json:20180813'
-    testImplementation 'org.mockito:mockito-core:3.6.0'
-    androidTestImplementation 'androidx.test:runner:1.1.1'
-    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/gradle.properties b/packages/in_app_purchase/in_app_purchase/android/gradle.properties
deleted file mode 100644
index 8bd86f6..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/gradle.properties
+++ /dev/null
@@ -1 +0,0 @@
-org.gradle.jvmargs=-Xmx1536M
diff --git a/packages/in_app_purchase/in_app_purchase/android/gradle/wrapper/gradle-wrapper.properties b/packages/in_app_purchase/in_app_purchase/android/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 73eba35..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Mon Oct 29 10:30:44 PDT 2018
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/packages/in_app_purchase/in_app_purchase/android/settings.gradle b/packages/in_app_purchase/in_app_purchase/android/settings.gradle
deleted file mode 100644
index 58efd2e..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/settings.gradle
+++ /dev/null
@@ -1 +0,0 @@
-rootProject.name = 'in_app_purchase'
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/main/AndroidManifest.xml b/packages/in_app_purchase/in_app_purchase/android/src/main/AndroidManifest.xml
deleted file mode 100644
index ae902de..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-  package="io.flutter.plugins.inapppurchase">
-</manifest>
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java
deleted file mode 100644
index 7b21cbf..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactory.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package io.flutter.plugins.inapppurchase;
-
-import android.content.Context;
-import androidx.annotation.NonNull;
-import com.android.billingclient.api.BillingClient;
-import io.flutter.plugin.common.MethodChannel;
-
-/** Responsible for creating a {@link BillingClient} object. */
-interface BillingClientFactory {
-
-  /**
-   * Creates and returns a {@link BillingClient}.
-   *
-   * @param context The context used to create the {@link BillingClient}.
-   * @param channel The method channel used to create the {@link BillingClient}.
-   * @param enablePendingPurchases Whether to enable pending purchases. Throws an exception if it is
-   *     false.
-   * @return The {@link BillingClient} object that is created.
-   */
-  BillingClient createBillingClient(
-      @NonNull Context context, @NonNull MethodChannel channel, boolean enablePendingPurchases);
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java
deleted file mode 100644
index c256d2c..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/BillingClientFactoryImpl.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package io.flutter.plugins.inapppurchase;
-
-import android.content.Context;
-import com.android.billingclient.api.BillingClient;
-import io.flutter.plugin.common.MethodChannel;
-
-/** The implementation for {@link BillingClientFactory} for the plugin. */
-final class BillingClientFactoryImpl implements BillingClientFactory {
-
-  @Override
-  public BillingClient createBillingClient(
-      Context context, MethodChannel channel, boolean enablePendingPurchases) {
-    BillingClient.Builder builder = BillingClient.newBuilder(context);
-    if (enablePendingPurchases) {
-      builder.enablePendingPurchases();
-    }
-    return builder.setListener(new PluginPurchaseListener(channel)).build();
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java
deleted file mode 100644
index e4719f0..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package io.flutter.plugins.inapppurchase;
-
-import android.app.Activity;
-import android.app.Application;
-import android.content.Context;
-import androidx.annotation.VisibleForTesting;
-import com.android.billingclient.api.BillingClient;
-import io.flutter.embedding.engine.plugins.FlutterPlugin;
-import io.flutter.embedding.engine.plugins.activity.ActivityAware;
-import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
-import io.flutter.plugin.common.BinaryMessenger;
-import io.flutter.plugin.common.MethodChannel;
-
-/** Wraps a {@link BillingClient} instance and responds to Dart calls for it. */
-public class InAppPurchasePlugin implements FlutterPlugin, ActivityAware {
-
-  @VisibleForTesting
-  static final class MethodNames {
-    static final String IS_READY = "BillingClient#isReady()";
-    static final String START_CONNECTION =
-        "BillingClient#startConnection(BillingClientStateListener)";
-    static final String END_CONNECTION = "BillingClient#endConnection()";
-    static final String ON_DISCONNECT = "BillingClientStateListener#onBillingServiceDisconnected()";
-    static final String QUERY_SKU_DETAILS =
-        "BillingClient#querySkuDetailsAsync(SkuDetailsParams, SkuDetailsResponseListener)";
-    static final String LAUNCH_BILLING_FLOW =
-        "BillingClient#launchBillingFlow(Activity, BillingFlowParams)";
-    static final String ON_PURCHASES_UPDATED =
-        "PurchasesUpdatedListener#onPurchasesUpdated(int, List<Purchase>)";
-    static final String QUERY_PURCHASES = "BillingClient#queryPurchases(String)";
-    static final String QUERY_PURCHASE_HISTORY_ASYNC =
-        "BillingClient#queryPurchaseHistoryAsync(String, PurchaseHistoryResponseListener)";
-    static final String CONSUME_PURCHASE_ASYNC =
-        "BillingClient#consumeAsync(String, ConsumeResponseListener)";
-    static final String ACKNOWLEDGE_PURCHASE =
-        "BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)";
-
-    private MethodNames() {};
-  }
-
-  private MethodChannel methodChannel;
-  private MethodCallHandlerImpl methodCallHandler;
-
-  /** Plugin registration. */
-  @SuppressWarnings("deprecation")
-  public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) {
-    InAppPurchasePlugin plugin = new InAppPurchasePlugin();
-    plugin.setupMethodChannel(registrar.activity(), registrar.messenger(), registrar.context());
-    ((Application) registrar.context().getApplicationContext())
-        .registerActivityLifecycleCallbacks(plugin.methodCallHandler);
-  }
-
-  @Override
-  public void onAttachedToEngine(FlutterPlugin.FlutterPluginBinding binding) {
-    setupMethodChannel(
-        /*activity=*/ null, binding.getBinaryMessenger(), binding.getApplicationContext());
-  }
-
-  @Override
-  public void onDetachedFromEngine(FlutterPlugin.FlutterPluginBinding binding) {
-    teardownMethodChannel();
-  }
-
-  @Override
-  public void onAttachedToActivity(ActivityPluginBinding binding) {
-    methodCallHandler.setActivity(binding.getActivity());
-  }
-
-  @Override
-  public void onDetachedFromActivity() {
-    methodCallHandler.setActivity(null);
-    methodCallHandler.onDetachedFromActivity();
-  }
-
-  @Override
-  public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
-    onAttachedToActivity(binding);
-  }
-
-  @Override
-  public void onDetachedFromActivityForConfigChanges() {
-    methodCallHandler.setActivity(null);
-  }
-
-  private void setupMethodChannel(Activity activity, BinaryMessenger messenger, Context context) {
-    methodChannel = new MethodChannel(messenger, "plugins.flutter.io/in_app_purchase");
-    methodCallHandler =
-        new MethodCallHandlerImpl(activity, context, methodChannel, new BillingClientFactoryImpl());
-    methodChannel.setMethodCallHandler(methodCallHandler);
-  }
-
-  private void teardownMethodChannel() {
-    methodChannel.setMethodCallHandler(null);
-    methodChannel = null;
-    methodCallHandler = null;
-  }
-
-  @VisibleForTesting
-  void setMethodCallHandler(MethodCallHandlerImpl methodCallHandler) {
-    this.methodCallHandler = methodCallHandler;
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java
deleted file mode 100644
index cfcb81a..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java
+++ /dev/null
@@ -1,382 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package io.flutter.plugins.inapppurchase;
-
-import static io.flutter.plugins.inapppurchase.Translator.fromPurchaseHistoryRecordList;
-import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesResult;
-import static io.flutter.plugins.inapppurchase.Translator.fromSkuDetailsList;
-
-import android.app.Activity;
-import android.app.Application;
-import android.content.Context;
-import android.os.Bundle;
-import android.util.Log;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import com.android.billingclient.api.AcknowledgePurchaseParams;
-import com.android.billingclient.api.AcknowledgePurchaseResponseListener;
-import com.android.billingclient.api.BillingClient;
-import com.android.billingclient.api.BillingClientStateListener;
-import com.android.billingclient.api.BillingFlowParams;
-import com.android.billingclient.api.BillingFlowParams.ProrationMode;
-import com.android.billingclient.api.BillingResult;
-import com.android.billingclient.api.ConsumeParams;
-import com.android.billingclient.api.ConsumeResponseListener;
-import com.android.billingclient.api.PurchaseHistoryRecord;
-import com.android.billingclient.api.PurchaseHistoryResponseListener;
-import com.android.billingclient.api.SkuDetails;
-import com.android.billingclient.api.SkuDetailsParams;
-import com.android.billingclient.api.SkuDetailsResponseListener;
-import io.flutter.plugin.common.MethodCall;
-import io.flutter.plugin.common.MethodChannel;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/** Handles method channel for the plugin. */
-class MethodCallHandlerImpl
-    implements MethodChannel.MethodCallHandler, Application.ActivityLifecycleCallbacks {
-
-  private static final String TAG = "InAppPurchasePlugin";
-  private static final String LOAD_SKU_DOC_URL =
-      "https://github.com/flutter/plugins/blob/master/packages/in_app_purchase/README.md#loading-products-for-sale";
-
-  @Nullable private BillingClient billingClient;
-  private final BillingClientFactory billingClientFactory;
-
-  @Nullable private Activity activity;
-  private final Context applicationContext;
-  private final MethodChannel methodChannel;
-
-  private HashMap<String, SkuDetails> cachedSkus = new HashMap<>();
-
-  /** Constructs the MethodCallHandlerImpl */
-  MethodCallHandlerImpl(
-      @Nullable Activity activity,
-      @NonNull Context applicationContext,
-      @NonNull MethodChannel methodChannel,
-      @NonNull BillingClientFactory billingClientFactory) {
-    this.billingClientFactory = billingClientFactory;
-    this.applicationContext = applicationContext;
-    this.activity = activity;
-    this.methodChannel = methodChannel;
-  }
-
-  /**
-   * Sets the activity. Should be called as soon as the the activity is available. When the activity
-   * becomes unavailable, call this method again with {@code null}.
-   */
-  void setActivity(@Nullable Activity activity) {
-    this.activity = activity;
-  }
-
-  @Override
-  public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
-
-  @Override
-  public void onActivityStarted(Activity activity) {}
-
-  @Override
-  public void onActivityResumed(Activity activity) {}
-
-  @Override
-  public void onActivityPaused(Activity activity) {}
-
-  @Override
-  public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
-
-  @Override
-  public void onActivityDestroyed(Activity activity) {
-    if (this.activity == activity && this.applicationContext != null) {
-      ((Application) this.applicationContext).unregisterActivityLifecycleCallbacks(this);
-      endBillingClientConnection();
-    }
-  }
-
-  @Override
-  public void onActivityStopped(Activity activity) {}
-
-  void onDetachedFromActivity() {
-    endBillingClientConnection();
-  }
-
-  @Override
-  public void onMethodCall(MethodCall call, MethodChannel.Result result) {
-    switch (call.method) {
-      case InAppPurchasePlugin.MethodNames.IS_READY:
-        isReady(result);
-        break;
-      case InAppPurchasePlugin.MethodNames.START_CONNECTION:
-        startConnection(
-            (int) call.argument("handle"),
-            (boolean) call.argument("enablePendingPurchases"),
-            result);
-        break;
-      case InAppPurchasePlugin.MethodNames.END_CONNECTION:
-        endConnection(result);
-        break;
-      case InAppPurchasePlugin.MethodNames.QUERY_SKU_DETAILS:
-        List<String> skusList = call.argument("skusList");
-        querySkuDetailsAsync((String) call.argument("skuType"), skusList, result);
-        break;
-      case InAppPurchasePlugin.MethodNames.LAUNCH_BILLING_FLOW:
-        launchBillingFlow(
-            (String) call.argument("sku"),
-            (String) call.argument("accountId"),
-            (String) call.argument("obfuscatedProfileId"),
-            (String) call.argument("oldSku"),
-            (String) call.argument("purchaseToken"),
-            call.hasArgument("prorationMode")
-                ? (int) call.argument("prorationMode")
-                : ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY,
-            result);
-        break;
-      case InAppPurchasePlugin.MethodNames.QUERY_PURCHASES:
-        queryPurchases((String) call.argument("skuType"), result);
-        break;
-      case InAppPurchasePlugin.MethodNames.QUERY_PURCHASE_HISTORY_ASYNC:
-        queryPurchaseHistoryAsync((String) call.argument("skuType"), result);
-        break;
-      case InAppPurchasePlugin.MethodNames.CONSUME_PURCHASE_ASYNC:
-        consumeAsync((String) call.argument("purchaseToken"), result);
-        break;
-      case InAppPurchasePlugin.MethodNames.ACKNOWLEDGE_PURCHASE:
-        acknowledgePurchase((String) call.argument("purchaseToken"), result);
-        break;
-      default:
-        result.notImplemented();
-    }
-  }
-
-  private void endConnection(final MethodChannel.Result result) {
-    endBillingClientConnection();
-    result.success(null);
-  }
-
-  private void endBillingClientConnection() {
-    if (billingClient != null) {
-      billingClient.endConnection();
-      billingClient = null;
-    }
-  }
-
-  private void isReady(MethodChannel.Result result) {
-    if (billingClientError(result)) {
-      return;
-    }
-
-    result.success(billingClient.isReady());
-  }
-
-  private void querySkuDetailsAsync(
-      final String skuType, final List<String> skusList, final MethodChannel.Result result) {
-    if (billingClientError(result)) {
-      return;
-    }
-
-    SkuDetailsParams params =
-        SkuDetailsParams.newBuilder().setType(skuType).setSkusList(skusList).build();
-    billingClient.querySkuDetailsAsync(
-        params,
-        new SkuDetailsResponseListener() {
-          @Override
-          public void onSkuDetailsResponse(
-              BillingResult billingResult, List<SkuDetails> skuDetailsList) {
-            updateCachedSkus(skuDetailsList);
-            final Map<String, Object> skuDetailsResponse = new HashMap<>();
-            skuDetailsResponse.put("billingResult", Translator.fromBillingResult(billingResult));
-            skuDetailsResponse.put("skuDetailsList", fromSkuDetailsList(skuDetailsList));
-            result.success(skuDetailsResponse);
-          }
-        });
-  }
-
-  private void launchBillingFlow(
-      String sku,
-      @Nullable String accountId,
-      @Nullable String obfuscatedProfileId,
-      @Nullable String oldSku,
-      @Nullable String purchaseToken,
-      int prorationMode,
-      MethodChannel.Result result) {
-    if (billingClientError(result)) {
-      return;
-    }
-
-    SkuDetails skuDetails = cachedSkus.get(sku);
-    if (skuDetails == null) {
-      result.error(
-          "NOT_FOUND",
-          String.format(
-              "Details for sku %s are not available. It might because skus were not fetched prior to the call. Please fetch the skus first. An example of how to fetch the skus could be found here: %s",
-              sku, LOAD_SKU_DOC_URL),
-          null);
-      return;
-    }
-
-    if (oldSku == null
-        && prorationMode != ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY) {
-      result.error(
-          "IN_APP_PURCHASE_REQUIRE_OLD_SKU",
-          "launchBillingFlow failed because oldSku is null. You must provide a valid oldSku in order to use a proration mode.",
-          null);
-      return;
-    } else if (oldSku != null && !cachedSkus.containsKey(oldSku)) {
-      result.error(
-          "IN_APP_PURCHASE_INVALID_OLD_SKU",
-          String.format(
-              "Details for sku %s are not available. It might because skus were not fetched prior to the call. Please fetch the skus first. An example of how to fetch the skus could be found here: %s",
-              oldSku, LOAD_SKU_DOC_URL),
-          null);
-      return;
-    }
-
-    if (activity == null) {
-      result.error(
-          "ACTIVITY_UNAVAILABLE",
-          "Details for sku "
-              + sku
-              + " are not available. This method must be run with the app in foreground.",
-          null);
-      return;
-    }
-
-    BillingFlowParams.Builder paramsBuilder =
-        BillingFlowParams.newBuilder().setSkuDetails(skuDetails);
-    if (accountId != null && !accountId.isEmpty()) {
-      paramsBuilder.setObfuscatedAccountId(accountId);
-    }
-    if (obfuscatedProfileId != null && !obfuscatedProfileId.isEmpty()) {
-      paramsBuilder.setObfuscatedProfileId(obfuscatedProfileId);
-    }
-    if (oldSku != null && !oldSku.isEmpty()) {
-      paramsBuilder.setOldSku(oldSku, purchaseToken);
-    }
-    // The proration mode value has to match one of the following declared in
-    // https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode
-    paramsBuilder.setReplaceSkusProrationMode(prorationMode);
-    result.success(
-        Translator.fromBillingResult(
-            billingClient.launchBillingFlow(activity, paramsBuilder.build())));
-  }
-
-  private void consumeAsync(String purchaseToken, final MethodChannel.Result result) {
-    if (billingClientError(result)) {
-      return;
-    }
-
-    ConsumeResponseListener listener =
-        new ConsumeResponseListener() {
-          @Override
-          public void onConsumeResponse(BillingResult billingResult, String outToken) {
-            result.success(Translator.fromBillingResult(billingResult));
-          }
-        };
-    ConsumeParams.Builder paramsBuilder =
-        ConsumeParams.newBuilder().setPurchaseToken(purchaseToken);
-
-    ConsumeParams params = paramsBuilder.build();
-
-    billingClient.consumeAsync(params, listener);
-  }
-
-  private void queryPurchases(String skuType, MethodChannel.Result result) {
-    if (billingClientError(result)) {
-      return;
-    }
-
-    // Like in our connect call, consider the billing client responding a "success" here regardless
-    // of status code.
-    result.success(fromPurchasesResult(billingClient.queryPurchases(skuType)));
-  }
-
-  private void queryPurchaseHistoryAsync(String skuType, final MethodChannel.Result result) {
-    if (billingClientError(result)) {
-      return;
-    }
-
-    billingClient.queryPurchaseHistoryAsync(
-        skuType,
-        new PurchaseHistoryResponseListener() {
-          @Override
-          public void onPurchaseHistoryResponse(
-              BillingResult billingResult, List<PurchaseHistoryRecord> purchasesList) {
-            final Map<String, Object> serialized = new HashMap<>();
-            serialized.put("billingResult", Translator.fromBillingResult(billingResult));
-            serialized.put(
-                "purchaseHistoryRecordList", fromPurchaseHistoryRecordList(purchasesList));
-            result.success(serialized);
-          }
-        });
-  }
-
-  private void startConnection(
-      final int handle, final boolean enablePendingPurchases, final MethodChannel.Result result) {
-    if (billingClient == null) {
-      billingClient =
-          billingClientFactory.createBillingClient(
-              applicationContext, methodChannel, enablePendingPurchases);
-    }
-
-    billingClient.startConnection(
-        new BillingClientStateListener() {
-          private boolean alreadyFinished = false;
-
-          @Override
-          public void onBillingSetupFinished(BillingResult billingResult) {
-            if (alreadyFinished) {
-              Log.d(TAG, "Tried to call onBilllingSetupFinished multiple times.");
-              return;
-            }
-            alreadyFinished = true;
-            // Consider the fact that we've finished a success, leave it to the Dart side to
-            // validate the responseCode.
-            result.success(Translator.fromBillingResult(billingResult));
-          }
-
-          @Override
-          public void onBillingServiceDisconnected() {
-            final Map<String, Object> arguments = new HashMap<>();
-            arguments.put("handle", handle);
-            methodChannel.invokeMethod(InAppPurchasePlugin.MethodNames.ON_DISCONNECT, arguments);
-          }
-        });
-  }
-
-  private void acknowledgePurchase(String purchaseToken, final MethodChannel.Result result) {
-    if (billingClientError(result)) {
-      return;
-    }
-    AcknowledgePurchaseParams params =
-        AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchaseToken).build();
-    billingClient.acknowledgePurchase(
-        params,
-        new AcknowledgePurchaseResponseListener() {
-          @Override
-          public void onAcknowledgePurchaseResponse(BillingResult billingResult) {
-            result.success(Translator.fromBillingResult(billingResult));
-          }
-        });
-  }
-
-  private void updateCachedSkus(@Nullable List<SkuDetails> skuDetailsList) {
-    if (skuDetailsList == null) {
-      return;
-    }
-
-    for (SkuDetails skuDetails : skuDetailsList) {
-      cachedSkus.put(skuDetails.getSku(), skuDetails);
-    }
-  }
-
-  private boolean billingClientError(MethodChannel.Result result) {
-    if (billingClient != null) {
-      return false;
-    }
-
-    result.error("UNAVAILABLE", "BillingClient is unset. Try reconnecting.", null);
-    return true;
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java
deleted file mode 100644
index 54c775d..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/PluginPurchaseListener.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package io.flutter.plugins.inapppurchase;
-
-import static io.flutter.plugins.inapppurchase.Translator.fromBillingResult;
-import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesList;
-
-import androidx.annotation.Nullable;
-import com.android.billingclient.api.BillingResult;
-import com.android.billingclient.api.Purchase;
-import com.android.billingclient.api.PurchasesUpdatedListener;
-import io.flutter.plugin.common.MethodChannel;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-class PluginPurchaseListener implements PurchasesUpdatedListener {
-  private final MethodChannel channel;
-
-  PluginPurchaseListener(MethodChannel channel) {
-    this.channel = channel;
-  }
-
-  @Override
-  public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> purchases) {
-    final Map<String, Object> callbackArgs = new HashMap<>();
-    callbackArgs.put("billingResult", fromBillingResult(billingResult));
-    callbackArgs.put("responseCode", billingResult.getResponseCode());
-    callbackArgs.put("purchasesList", fromPurchasesList(purchases));
-    channel.invokeMethod(InAppPurchasePlugin.MethodNames.ON_PURCHASES_UPDATED, callbackArgs);
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java b/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java
deleted file mode 100644
index 37e30cb..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package io.flutter.plugins.inapppurchase;
-
-import androidx.annotation.Nullable;
-import com.android.billingclient.api.BillingResult;
-import com.android.billingclient.api.Purchase;
-import com.android.billingclient.api.Purchase.PurchasesResult;
-import com.android.billingclient.api.PurchaseHistoryRecord;
-import com.android.billingclient.api.SkuDetails;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-
-/** Handles serialization of {@link com.android.billingclient.api.BillingClient} related objects. */
-/*package*/ class Translator {
-  static HashMap<String, Object> fromSkuDetail(SkuDetails detail) {
-    HashMap<String, Object> info = new HashMap<>();
-    info.put("title", detail.getTitle());
-    info.put("description", detail.getDescription());
-    info.put("freeTrialPeriod", detail.getFreeTrialPeriod());
-    info.put("introductoryPrice", detail.getIntroductoryPrice());
-    info.put("introductoryPriceAmountMicros", detail.getIntroductoryPriceAmountMicros());
-    info.put("introductoryPriceCycles", detail.getIntroductoryPriceCycles());
-    info.put("introductoryPricePeriod", detail.getIntroductoryPricePeriod());
-    info.put("price", detail.getPrice());
-    info.put("priceAmountMicros", detail.getPriceAmountMicros());
-    info.put("priceCurrencyCode", detail.getPriceCurrencyCode());
-    info.put("sku", detail.getSku());
-    info.put("type", detail.getType());
-    info.put("subscriptionPeriod", detail.getSubscriptionPeriod());
-    info.put("originalPrice", detail.getOriginalPrice());
-    info.put("originalPriceAmountMicros", detail.getOriginalPriceAmountMicros());
-    return info;
-  }
-
-  static List<HashMap<String, Object>> fromSkuDetailsList(
-      @Nullable List<SkuDetails> skuDetailsList) {
-    if (skuDetailsList == null) {
-      return Collections.emptyList();
-    }
-
-    ArrayList<HashMap<String, Object>> output = new ArrayList<>();
-    for (SkuDetails detail : skuDetailsList) {
-      output.add(fromSkuDetail(detail));
-    }
-    return output;
-  }
-
-  static HashMap<String, Object> fromPurchase(Purchase purchase) {
-    HashMap<String, Object> info = new HashMap<>();
-    info.put("orderId", purchase.getOrderId());
-    info.put("packageName", purchase.getPackageName());
-    info.put("purchaseTime", purchase.getPurchaseTime());
-    info.put("purchaseToken", purchase.getPurchaseToken());
-    info.put("signature", purchase.getSignature());
-    info.put("sku", purchase.getSku());
-    info.put("isAutoRenewing", purchase.isAutoRenewing());
-    info.put("originalJson", purchase.getOriginalJson());
-    info.put("developerPayload", purchase.getDeveloperPayload());
-    info.put("isAcknowledged", purchase.isAcknowledged());
-    info.put("purchaseState", purchase.getPurchaseState());
-    return info;
-  }
-
-  static HashMap<String, Object> fromPurchaseHistoryRecord(
-      PurchaseHistoryRecord purchaseHistoryRecord) {
-    HashMap<String, Object> info = new HashMap<>();
-    info.put("purchaseTime", purchaseHistoryRecord.getPurchaseTime());
-    info.put("purchaseToken", purchaseHistoryRecord.getPurchaseToken());
-    info.put("signature", purchaseHistoryRecord.getSignature());
-    info.put("sku", purchaseHistoryRecord.getSku());
-    info.put("developerPayload", purchaseHistoryRecord.getDeveloperPayload());
-    info.put("originalJson", purchaseHistoryRecord.getOriginalJson());
-    return info;
-  }
-
-  static List<HashMap<String, Object>> fromPurchasesList(@Nullable List<Purchase> purchases) {
-    if (purchases == null) {
-      return Collections.emptyList();
-    }
-
-    List<HashMap<String, Object>> serialized = new ArrayList<>();
-    for (Purchase purchase : purchases) {
-      serialized.add(fromPurchase(purchase));
-    }
-    return serialized;
-  }
-
-  static List<HashMap<String, Object>> fromPurchaseHistoryRecordList(
-      @Nullable List<PurchaseHistoryRecord> purchaseHistoryRecords) {
-    if (purchaseHistoryRecords == null) {
-      return Collections.emptyList();
-    }
-
-    List<HashMap<String, Object>> serialized = new ArrayList<>();
-    for (PurchaseHistoryRecord purchaseHistoryRecord : purchaseHistoryRecords) {
-      serialized.add(fromPurchaseHistoryRecord(purchaseHistoryRecord));
-    }
-    return serialized;
-  }
-
-  static HashMap<String, Object> fromPurchasesResult(PurchasesResult purchasesResult) {
-    HashMap<String, Object> info = new HashMap<>();
-    info.put("responseCode", purchasesResult.getResponseCode());
-    info.put("billingResult", fromBillingResult(purchasesResult.getBillingResult()));
-    info.put("purchasesList", fromPurchasesList(purchasesResult.getPurchasesList()));
-    return info;
-  }
-
-  static HashMap<String, Object> fromBillingResult(BillingResult billingResult) {
-    HashMap<String, Object> info = new HashMap<>();
-    info.put("responseCode", billingResult.getResponseCode());
-    info.put("debugMessage", billingResult.getDebugMessage());
-    return info;
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/text/TextUtils.java b/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/text/TextUtils.java
deleted file mode 100644
index d997ae1..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/text/TextUtils.java
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package android.text;
-
-public class TextUtils {
-  public static boolean isEmpty(CharSequence str) {
-    return str == null || str.length() == 0;
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/util/Log.java b/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/util/Log.java
deleted file mode 100644
index 310b9ad..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/test/java/android/util/Log.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package android.util;
-
-public class Log {
-  public static int d(String tag, String msg) {
-    System.out.println("DEBUG: " + tag + ": " + msg);
-    return 0;
-  }
-
-  public static int i(String tag, String msg) {
-    System.out.println("INFO: " + tag + ": " + msg);
-    return 0;
-  }
-
-  public static int w(String tag, String msg) {
-    System.out.println("WARN: " + tag + ": " + msg);
-    return 0;
-  }
-
-  public static int e(String tag, String msg) {
-    System.out.println("ERROR: " + tag + ": " + msg);
-    return 0;
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java b/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java
deleted file mode 100644
index bcee542..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/InAppPurchasePluginTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package io.flutter.plugins.inapppurchase;
-
-import static org.mockito.Mockito.when;
-
-import android.app.Activity;
-import android.app.Application;
-import android.content.Context;
-import io.flutter.plugin.common.BinaryMessenger;
-import io.flutter.plugin.common.PluginRegistry;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-public class InAppPurchasePluginTest {
-  @Mock Activity activity;
-  @Mock Context context;
-  @Mock PluginRegistry.Registrar mockRegistrar; // For v1 embedding
-  @Mock BinaryMessenger mockMessenger;
-  @Mock Application mockApplication;
-
-  @Before
-  public void setUp() {
-    MockitoAnnotations.initMocks(this);
-    when(mockRegistrar.activity()).thenReturn(activity);
-    when(mockRegistrar.messenger()).thenReturn(mockMessenger);
-    when(mockRegistrar.context()).thenReturn(context);
-  }
-
-  @Test
-  public void registerWith_doNotCrashWhenRegisterContextIsActivity_V1Embedding() {
-    when(mockRegistrar.context()).thenReturn(activity);
-    when(activity.getApplicationContext()).thenReturn(mockApplication);
-    InAppPurchasePlugin.registerWith(mockRegistrar);
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java b/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java
deleted file mode 100644
index 4d7a022..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java
+++ /dev/null
@@ -1,812 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package io.flutter.plugins.inapppurchase;
-
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.ACKNOWLEDGE_PURCHASE;
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.CONSUME_PURCHASE_ASYNC;
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.END_CONNECTION;
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.IS_READY;
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.LAUNCH_BILLING_FLOW;
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.ON_DISCONNECT;
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.ON_PURCHASES_UPDATED;
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_PURCHASES;
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_PURCHASE_HISTORY_ASYNC;
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_SKU_DETAILS;
-import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.START_CONNECTION;
-import static io.flutter.plugins.inapppurchase.Translator.fromBillingResult;
-import static io.flutter.plugins.inapppurchase.Translator.fromPurchaseHistoryRecordList;
-import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesList;
-import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesResult;
-import static io.flutter.plugins.inapppurchase.Translator.fromSkuDetailsList;
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonList;
-import static java.util.Collections.unmodifiableList;
-import static java.util.stream.Collectors.toList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.contains;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.refEq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Activity;
-import android.content.Context;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import com.android.billingclient.api.AcknowledgePurchaseParams;
-import com.android.billingclient.api.AcknowledgePurchaseResponseListener;
-import com.android.billingclient.api.BillingClient;
-import com.android.billingclient.api.BillingClient.SkuType;
-import com.android.billingclient.api.BillingClientStateListener;
-import com.android.billingclient.api.BillingFlowParams;
-import com.android.billingclient.api.BillingResult;
-import com.android.billingclient.api.ConsumeParams;
-import com.android.billingclient.api.ConsumeResponseListener;
-import com.android.billingclient.api.Purchase;
-import com.android.billingclient.api.Purchase.PurchasesResult;
-import com.android.billingclient.api.PurchaseHistoryRecord;
-import com.android.billingclient.api.PurchaseHistoryResponseListener;
-import com.android.billingclient.api.SkuDetails;
-import com.android.billingclient.api.SkuDetailsParams;
-import com.android.billingclient.api.SkuDetailsResponseListener;
-import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
-import io.flutter.plugin.common.MethodCall;
-import io.flutter.plugin.common.MethodChannel;
-import io.flutter.plugin.common.MethodChannel.Result;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.json.JSONException;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-
-public class MethodCallHandlerTest {
-  private MethodCallHandlerImpl methodChannelHandler;
-  private BillingClientFactory factory;
-  @Mock BillingClient mockBillingClient;
-  @Mock MethodChannel mockMethodChannel;
-  @Spy Result result;
-  @Mock Activity activity;
-  @Mock Context context;
-  @Mock ActivityPluginBinding mockActivityPluginBinding;
-
-  @Before
-  public void setUp() {
-    MockitoAnnotations.openMocks(this);
-    factory =
-        (@NonNull Context context,
-            @NonNull MethodChannel channel,
-            boolean enablePendingPurchases) -> mockBillingClient;
-    methodChannelHandler = new MethodCallHandlerImpl(activity, context, mockMethodChannel, factory);
-    when(mockActivityPluginBinding.getActivity()).thenReturn(activity);
-  }
-
-  @Test
-  public void invalidMethod() {
-    MethodCall call = new MethodCall("invalid", null);
-    methodChannelHandler.onMethodCall(call, result);
-    verify(result, times(1)).notImplemented();
-  }
-
-  @Test
-  public void isReady_true() {
-    mockStartConnection();
-    MethodCall call = new MethodCall(IS_READY, null);
-    when(mockBillingClient.isReady()).thenReturn(true);
-    methodChannelHandler.onMethodCall(call, result);
-    verify(result).success(true);
-  }
-
-  @Test
-  public void isReady_false() {
-    mockStartConnection();
-    MethodCall call = new MethodCall(IS_READY, null);
-    when(mockBillingClient.isReady()).thenReturn(false);
-    methodChannelHandler.onMethodCall(call, result);
-    verify(result).success(false);
-  }
-
-  @Test
-  public void isReady_clientDisconnected() {
-    MethodCall disconnectCall = new MethodCall(END_CONNECTION, null);
-    methodChannelHandler.onMethodCall(disconnectCall, mock(Result.class));
-    MethodCall isReadyCall = new MethodCall(IS_READY, null);
-
-    methodChannelHandler.onMethodCall(isReadyCall, result);
-
-    verify(result).error(contains("UNAVAILABLE"), contains("BillingClient"), any());
-    verify(result, never()).success(any());
-  }
-
-  @Test
-  public void startConnection() {
-    ArgumentCaptor<BillingClientStateListener> captor = mockStartConnection();
-    verify(result, never()).success(any());
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    captor.getValue().onBillingSetupFinished(billingResult);
-
-    verify(result, times(1)).success(fromBillingResult(billingResult));
-  }
-
-  @Test
-  public void startConnection_multipleCalls() {
-    Map<String, Object> arguments = new HashMap<>();
-    arguments.put("handle", 1);
-    arguments.put("enablePendingPurchases", true);
-    MethodCall call = new MethodCall(START_CONNECTION, arguments);
-    ArgumentCaptor<BillingClientStateListener> captor =
-        ArgumentCaptor.forClass(BillingClientStateListener.class);
-    doNothing().when(mockBillingClient).startConnection(captor.capture());
-
-    methodChannelHandler.onMethodCall(call, result);
-    verify(result, never()).success(any());
-    BillingResult billingResult1 =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    BillingResult billingResult2 =
-        BillingResult.newBuilder()
-            .setResponseCode(200)
-            .setDebugMessage("dummy debug message")
-            .build();
-    BillingResult billingResult3 =
-        BillingResult.newBuilder()
-            .setResponseCode(300)
-            .setDebugMessage("dummy debug message")
-            .build();
-
-    captor.getValue().onBillingSetupFinished(billingResult1);
-    captor.getValue().onBillingSetupFinished(billingResult2);
-    captor.getValue().onBillingSetupFinished(billingResult3);
-
-    verify(result, times(1)).success(fromBillingResult(billingResult1));
-    verify(result, times(1)).success(any());
-  }
-
-  @Test
-  public void endConnection() {
-    // Set up a connected BillingClient instance
-    final int disconnectCallbackHandle = 22;
-    Map<String, Object> arguments = new HashMap<>();
-    arguments.put("handle", disconnectCallbackHandle);
-    arguments.put("enablePendingPurchases", true);
-    MethodCall connectCall = new MethodCall(START_CONNECTION, arguments);
-    ArgumentCaptor<BillingClientStateListener> captor =
-        ArgumentCaptor.forClass(BillingClientStateListener.class);
-    doNothing().when(mockBillingClient).startConnection(captor.capture());
-    methodChannelHandler.onMethodCall(connectCall, mock(Result.class));
-    final BillingClientStateListener stateListener = captor.getValue();
-
-    // Disconnect the connected client
-    MethodCall disconnectCall = new MethodCall(END_CONNECTION, null);
-    methodChannelHandler.onMethodCall(disconnectCall, result);
-
-    // Verify that the client is disconnected and that the OnDisconnect callback has
-    // been triggered
-    verify(result, times(1)).success(any());
-    verify(mockBillingClient, times(1)).endConnection();
-    stateListener.onBillingServiceDisconnected();
-    Map<String, Integer> expectedInvocation = new HashMap<>();
-    expectedInvocation.put("handle", disconnectCallbackHandle);
-    verify(mockMethodChannel, times(1)).invokeMethod(ON_DISCONNECT, expectedInvocation);
-  }
-
-  @Test
-  public void querySkuDetailsAsync() {
-    // Connect a billing client and set up the SKU query listeners
-    establishConnectedBillingClient(/* arguments= */ null, /* result= */ null);
-    String skuType = BillingClient.SkuType.INAPP;
-    List<String> skusList = asList("id1", "id2");
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("skuType", skuType);
-    arguments.put("skusList", skusList);
-    MethodCall queryCall = new MethodCall(QUERY_SKU_DETAILS, arguments);
-
-    // Query for SKU details
-    methodChannelHandler.onMethodCall(queryCall, result);
-
-    // Assert the arguments were forwarded correctly to BillingClient
-    ArgumentCaptor<SkuDetailsParams> paramCaptor = ArgumentCaptor.forClass(SkuDetailsParams.class);
-    ArgumentCaptor<SkuDetailsResponseListener> listenerCaptor =
-        ArgumentCaptor.forClass(SkuDetailsResponseListener.class);
-    verify(mockBillingClient).querySkuDetailsAsync(paramCaptor.capture(), listenerCaptor.capture());
-    assertEquals(paramCaptor.getValue().getSkuType(), skuType);
-    assertEquals(paramCaptor.getValue().getSkusList(), skusList);
-
-    // Assert that we handed result BillingClient's response
-    int responseCode = 200;
-    List<SkuDetails> skuDetailsResponse = asList(buildSkuDetails("foo"));
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    listenerCaptor.getValue().onSkuDetailsResponse(billingResult, skuDetailsResponse);
-    ArgumentCaptor<HashMap<String, Object>> resultCaptor = ArgumentCaptor.forClass(HashMap.class);
-    verify(result).success(resultCaptor.capture());
-    HashMap<String, Object> resultData = resultCaptor.getValue();
-    assertEquals(resultData.get("billingResult"), fromBillingResult(billingResult));
-    assertEquals(resultData.get("skuDetailsList"), fromSkuDetailsList(skuDetailsResponse));
-  }
-
-  @Test
-  public void querySkuDetailsAsync_clientDisconnected() {
-    // Disconnect the Billing client and prepare a querySkuDetails call
-    MethodCall disconnectCall = new MethodCall(END_CONNECTION, null);
-    methodChannelHandler.onMethodCall(disconnectCall, mock(Result.class));
-    String skuType = BillingClient.SkuType.INAPP;
-    List<String> skusList = asList("id1", "id2");
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("skuType", skuType);
-    arguments.put("skusList", skusList);
-    MethodCall queryCall = new MethodCall(QUERY_SKU_DETAILS, arguments);
-
-    // Query for SKU details
-    methodChannelHandler.onMethodCall(queryCall, result);
-
-    // Assert that we sent an error back.
-    verify(result).error(contains("UNAVAILABLE"), contains("BillingClient"), any());
-    verify(result, never()).success(any());
-  }
-
-  // Test launchBillingFlow not crash if `accountId` is `null`
-  // Ideally, we should check if the `accountId` is null in the parameter; however,
-  // since PBL 3.0, the `accountId` variable is not public.
-  @Test
-  public void launchBillingFlow_null_AccountId_do_not_crash() {
-    // Fetch the sku details first and then prepare the launch billing flow call
-    String skuId = "foo";
-    queryForSkus(singletonList(skuId));
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("sku", skuId);
-    arguments.put("accountId", null);
-    arguments.put("obfuscatedProfileId", null);
-    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
-
-    // Launch the billing flow
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult);
-    methodChannelHandler.onMethodCall(launchCall, result);
-
-    // Verify we pass the arguments to the billing flow
-    ArgumentCaptor<BillingFlowParams> billingFlowParamsCaptor =
-        ArgumentCaptor.forClass(BillingFlowParams.class);
-    verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture());
-    BillingFlowParams params = billingFlowParamsCaptor.getValue();
-    assertEquals(params.getSku(), skuId);
-
-    // Verify we pass the response code to result
-    verify(result, never()).error(any(), any(), any());
-    verify(result, times(1)).success(fromBillingResult(billingResult));
-  }
-
-  @Test
-  public void launchBillingFlow_ok_null_OldSku() {
-    // Fetch the sku details first and then prepare the launch billing flow call
-    String skuId = "foo";
-    String accountId = "account";
-    queryForSkus(singletonList(skuId));
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("sku", skuId);
-    arguments.put("accountId", accountId);
-    arguments.put("oldSku", null);
-    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
-
-    // Launch the billing flow
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult);
-    methodChannelHandler.onMethodCall(launchCall, result);
-
-    // Verify we pass the arguments to the billing flow
-    ArgumentCaptor<BillingFlowParams> billingFlowParamsCaptor =
-        ArgumentCaptor.forClass(BillingFlowParams.class);
-    verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture());
-    BillingFlowParams params = billingFlowParamsCaptor.getValue();
-    assertEquals(params.getSku(), skuId);
-    assertNull(params.getOldSku());
-    // Verify we pass the response code to result
-    verify(result, never()).error(any(), any(), any());
-    verify(result, times(1)).success(fromBillingResult(billingResult));
-  }
-
-  @Test
-  public void launchBillingFlow_ok_null_Activity() {
-    methodChannelHandler.setActivity(null);
-
-    // Fetch the sku details first and then prepare the launch billing flow call
-    String skuId = "foo";
-    String accountId = "account";
-    queryForSkus(singletonList(skuId));
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("sku", skuId);
-    arguments.put("accountId", accountId);
-    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
-    methodChannelHandler.onMethodCall(launchCall, result);
-
-    // Verify we pass the response code to result
-    verify(result).error(contains("ACTIVITY_UNAVAILABLE"), contains("foreground"), any());
-    verify(result, never()).success(any());
-  }
-
-  @Test
-  public void launchBillingFlow_ok_oldSku() {
-    // Fetch the sku details first and query the method call
-    String skuId = "foo";
-    String accountId = "account";
-    String oldSkuId = "oldFoo";
-    queryForSkus(unmodifiableList(asList(skuId, oldSkuId)));
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("sku", skuId);
-    arguments.put("accountId", accountId);
-    arguments.put("oldSku", oldSkuId);
-    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
-
-    // Launch the billing flow
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult);
-    methodChannelHandler.onMethodCall(launchCall, result);
-
-    // Verify we pass the arguments to the billing flow
-    ArgumentCaptor<BillingFlowParams> billingFlowParamsCaptor =
-        ArgumentCaptor.forClass(BillingFlowParams.class);
-    verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture());
-    BillingFlowParams params = billingFlowParamsCaptor.getValue();
-    assertEquals(params.getSku(), skuId);
-    assertEquals(params.getOldSku(), oldSkuId);
-
-    // Verify we pass the response code to result
-    verify(result, never()).error(any(), any(), any());
-    verify(result, times(1)).success(fromBillingResult(billingResult));
-  }
-
-  @Test
-  public void launchBillingFlow_ok_AccountId() {
-    // Fetch the sku details first and query the method call
-    String skuId = "foo";
-    String accountId = "account";
-    queryForSkus(singletonList(skuId));
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("sku", skuId);
-    arguments.put("accountId", accountId);
-    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
-
-    // Launch the billing flow
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult);
-    methodChannelHandler.onMethodCall(launchCall, result);
-
-    // Verify we pass the arguments to the billing flow
-    ArgumentCaptor<BillingFlowParams> billingFlowParamsCaptor =
-        ArgumentCaptor.forClass(BillingFlowParams.class);
-    verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture());
-    BillingFlowParams params = billingFlowParamsCaptor.getValue();
-    assertEquals(params.getSku(), skuId);
-
-    // Verify we pass the response code to result
-    verify(result, never()).error(any(), any(), any());
-    verify(result, times(1)).success(fromBillingResult(billingResult));
-  }
-
-  @Test
-  public void launchBillingFlow_ok_Proration() {
-    // Fetch the sku details first and query the method call
-    String skuId = "foo";
-    String oldSkuId = "oldFoo";
-    String purchaseToken = "purchaseTokenFoo";
-    String accountId = "account";
-    int prorationMode = BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE;
-    queryForSkus(unmodifiableList(asList(skuId, oldSkuId)));
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("sku", skuId);
-    arguments.put("accountId", accountId);
-    arguments.put("oldSku", oldSkuId);
-    arguments.put("purchaseToken", purchaseToken);
-    arguments.put("prorationMode", prorationMode);
-    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
-
-    // Launch the billing flow
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult);
-    methodChannelHandler.onMethodCall(launchCall, result);
-
-    // Verify we pass the arguments to the billing flow
-    ArgumentCaptor<BillingFlowParams> billingFlowParamsCaptor =
-        ArgumentCaptor.forClass(BillingFlowParams.class);
-    verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture());
-    BillingFlowParams params = billingFlowParamsCaptor.getValue();
-    assertEquals(params.getSku(), skuId);
-    assertEquals(params.getOldSku(), oldSkuId);
-    assertEquals(params.getOldSkuPurchaseToken(), purchaseToken);
-    assertEquals(params.getReplaceSkusProrationMode(), prorationMode);
-
-    // Verify we pass the response code to result
-    verify(result, never()).error(any(), any(), any());
-    verify(result, times(1)).success(fromBillingResult(billingResult));
-  }
-
-  @Test
-  public void launchBillingFlow_ok_Proration_with_null_OldSku() {
-    // Fetch the sku details first and query the method call
-    String skuId = "foo";
-    String accountId = "account";
-    String queryOldSkuId = "oldFoo";
-    String oldSkuId = null;
-    int prorationMode = BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE;
-    queryForSkus(unmodifiableList(asList(skuId, queryOldSkuId)));
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("sku", skuId);
-    arguments.put("accountId", accountId);
-    arguments.put("oldSku", oldSkuId);
-    arguments.put("prorationMode", prorationMode);
-    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
-
-    // Launch the billing flow
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult);
-    methodChannelHandler.onMethodCall(launchCall, result);
-
-    // Assert that we sent an error back.
-    verify(result)
-        .error(
-            contains("IN_APP_PURCHASE_REQUIRE_OLD_SKU"),
-            contains("launchBillingFlow failed because oldSku is null"),
-            any());
-    verify(result, never()).success(any());
-  }
-
-  @Test
-  public void launchBillingFlow_clientDisconnected() {
-    // Prepare the launch call after disconnecting the client
-    MethodCall disconnectCall = new MethodCall(END_CONNECTION, null);
-    methodChannelHandler.onMethodCall(disconnectCall, mock(Result.class));
-    String skuId = "foo";
-    String accountId = "account";
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("sku", skuId);
-    arguments.put("accountId", accountId);
-    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
-
-    methodChannelHandler.onMethodCall(launchCall, result);
-
-    // Assert that we sent an error back.
-    verify(result).error(contains("UNAVAILABLE"), contains("BillingClient"), any());
-    verify(result, never()).success(any());
-  }
-
-  @Test
-  public void launchBillingFlow_skuNotFound() {
-    // Try to launch the billing flow for a random sku ID
-    establishConnectedBillingClient(null, null);
-    String skuId = "foo";
-    String accountId = "account";
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("sku", skuId);
-    arguments.put("accountId", accountId);
-    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
-
-    methodChannelHandler.onMethodCall(launchCall, result);
-
-    // Assert that we sent an error back.
-    verify(result).error(contains("NOT_FOUND"), contains(skuId), any());
-    verify(result, never()).success(any());
-  }
-
-  @Test
-  public void launchBillingFlow_oldSkuNotFound() {
-    // Try to launch the billing flow for a random sku ID
-    establishConnectedBillingClient(null, null);
-    String skuId = "foo";
-    String accountId = "account";
-    String oldSkuId = "oldSku";
-    queryForSkus(singletonList(skuId));
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("sku", skuId);
-    arguments.put("accountId", accountId);
-    arguments.put("oldSku", oldSkuId);
-    MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments);
-
-    methodChannelHandler.onMethodCall(launchCall, result);
-
-    // Assert that we sent an error back.
-    verify(result).error(contains("IN_APP_PURCHASE_INVALID_OLD_SKU"), contains(oldSkuId), any());
-    verify(result, never()).success(any());
-  }
-
-  @Test
-  public void queryPurchases() {
-    establishConnectedBillingClient(null, null);
-    PurchasesResult purchasesResult = mock(PurchasesResult.class);
-    Purchase purchase = buildPurchase("foo");
-    when(purchasesResult.getPurchasesList()).thenReturn(asList(purchase));
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    when(purchasesResult.getBillingResult()).thenReturn(billingResult);
-    when(mockBillingClient.queryPurchases(SkuType.INAPP)).thenReturn(purchasesResult);
-
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("skuType", SkuType.INAPP);
-    methodChannelHandler.onMethodCall(new MethodCall(QUERY_PURCHASES, arguments), result);
-
-    // Verify we pass the response to result
-    ArgumentCaptor<HashMap<String, Object>> resultCaptor = ArgumentCaptor.forClass(HashMap.class);
-    verify(result, never()).error(any(), any(), any());
-    verify(result, times(1)).success(resultCaptor.capture());
-    assertEquals(fromPurchasesResult(purchasesResult), resultCaptor.getValue());
-  }
-
-  @Test
-  public void queryPurchases_clientDisconnected() {
-    // Prepare the launch call after disconnecting the client
-    methodChannelHandler.onMethodCall(new MethodCall(END_CONNECTION, null), mock(Result.class));
-
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("skuType", SkuType.INAPP);
-    methodChannelHandler.onMethodCall(new MethodCall(QUERY_PURCHASES, arguments), result);
-
-    // Assert that we sent an error back.
-    verify(result).error(contains("UNAVAILABLE"), contains("BillingClient"), any());
-    verify(result, never()).success(any());
-  }
-
-  @Test
-  public void queryPurchaseHistoryAsync() {
-    // Set up an established billing client and all our mocked responses
-    establishConnectedBillingClient(null, null);
-    ArgumentCaptor<HashMap<String, Object>> resultCaptor = ArgumentCaptor.forClass(HashMap.class);
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    List<PurchaseHistoryRecord> purchasesList = asList(buildPurchaseHistoryRecord("foo"));
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("skuType", SkuType.INAPP);
-    ArgumentCaptor<PurchaseHistoryResponseListener> listenerCaptor =
-        ArgumentCaptor.forClass(PurchaseHistoryResponseListener.class);
-
-    methodChannelHandler.onMethodCall(
-        new MethodCall(QUERY_PURCHASE_HISTORY_ASYNC, arguments), result);
-
-    // Verify we pass the data to result
-    verify(mockBillingClient)
-        .queryPurchaseHistoryAsync(eq(SkuType.INAPP), listenerCaptor.capture());
-    listenerCaptor.getValue().onPurchaseHistoryResponse(billingResult, purchasesList);
-    verify(result).success(resultCaptor.capture());
-    HashMap<String, Object> resultData = resultCaptor.getValue();
-    assertEquals(fromBillingResult(billingResult), resultData.get("billingResult"));
-    assertEquals(
-        fromPurchaseHistoryRecordList(purchasesList), resultData.get("purchaseHistoryRecordList"));
-  }
-
-  @Test
-  public void queryPurchaseHistoryAsync_clientDisconnected() {
-    // Prepare the launch call after disconnecting the client
-    methodChannelHandler.onMethodCall(new MethodCall(END_CONNECTION, null), mock(Result.class));
-
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("skuType", SkuType.INAPP);
-    methodChannelHandler.onMethodCall(
-        new MethodCall(QUERY_PURCHASE_HISTORY_ASYNC, arguments), result);
-
-    // Assert that we sent an error back.
-    verify(result).error(contains("UNAVAILABLE"), contains("BillingClient"), any());
-    verify(result, never()).success(any());
-  }
-
-  @Test
-  public void onPurchasesUpdatedListener() {
-    PluginPurchaseListener listener = new PluginPurchaseListener(mockMethodChannel);
-
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    List<Purchase> purchasesList = asList(buildPurchase("foo"));
-    ArgumentCaptor<HashMap<String, Object>> resultCaptor = ArgumentCaptor.forClass(HashMap.class);
-    doNothing()
-        .when(mockMethodChannel)
-        .invokeMethod(eq(ON_PURCHASES_UPDATED), resultCaptor.capture());
-    listener.onPurchasesUpdated(billingResult, purchasesList);
-
-    HashMap<String, Object> resultData = resultCaptor.getValue();
-    assertEquals(fromBillingResult(billingResult), resultData.get("billingResult"));
-    assertEquals(fromPurchasesList(purchasesList), resultData.get("purchasesList"));
-  }
-
-  @Test
-  public void consumeAsync() {
-    establishConnectedBillingClient(null, null);
-    ArgumentCaptor<BillingResult> resultCaptor = ArgumentCaptor.forClass(BillingResult.class);
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("purchaseToken", "mockToken");
-    arguments.put("developerPayload", "mockPayload");
-    ArgumentCaptor<ConsumeResponseListener> listenerCaptor =
-        ArgumentCaptor.forClass(ConsumeResponseListener.class);
-
-    methodChannelHandler.onMethodCall(new MethodCall(CONSUME_PURCHASE_ASYNC, arguments), result);
-
-    ConsumeParams params = ConsumeParams.newBuilder().setPurchaseToken("mockToken").build();
-
-    // Verify we pass the data to result
-    verify(mockBillingClient).consumeAsync(refEq(params), listenerCaptor.capture());
-
-    listenerCaptor.getValue().onConsumeResponse(billingResult, "mockToken");
-    verify(result).success(resultCaptor.capture());
-
-    // Verify we pass the response code to result
-    verify(result, never()).error(any(), any(), any());
-    verify(result, times(1)).success(fromBillingResult(billingResult));
-  }
-
-  @Test
-  public void acknowledgePurchase() {
-    establishConnectedBillingClient(null, null);
-    ArgumentCaptor<BillingResult> resultCaptor = ArgumentCaptor.forClass(BillingResult.class);
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    HashMap<String, Object> arguments = new HashMap<>();
-    arguments.put("purchaseToken", "mockToken");
-    arguments.put("developerPayload", "mockPayload");
-    ArgumentCaptor<AcknowledgePurchaseResponseListener> listenerCaptor =
-        ArgumentCaptor.forClass(AcknowledgePurchaseResponseListener.class);
-
-    methodChannelHandler.onMethodCall(new MethodCall(ACKNOWLEDGE_PURCHASE, arguments), result);
-
-    AcknowledgePurchaseParams params =
-        AcknowledgePurchaseParams.newBuilder().setPurchaseToken("mockToken").build();
-
-    // Verify we pass the data to result
-    verify(mockBillingClient).acknowledgePurchase(refEq(params), listenerCaptor.capture());
-
-    listenerCaptor.getValue().onAcknowledgePurchaseResponse(billingResult);
-    verify(result).success(resultCaptor.capture());
-
-    // Verify we pass the response code to result
-    verify(result, never()).error(any(), any(), any());
-    verify(result, times(1)).success(fromBillingResult(billingResult));
-  }
-
-  @Test
-  public void endConnection_if_activity_dettached() {
-    InAppPurchasePlugin plugin = new InAppPurchasePlugin();
-    plugin.setMethodCallHandler(methodChannelHandler);
-    mockStartConnection();
-    plugin.onDetachedFromActivity();
-    verify(mockBillingClient).endConnection();
-  }
-
-  private ArgumentCaptor<BillingClientStateListener> mockStartConnection() {
-    Map<String, Object> arguments = new HashMap<>();
-    arguments.put("handle", 1);
-    arguments.put("enablePendingPurchases", true);
-    MethodCall call = new MethodCall(START_CONNECTION, arguments);
-    ArgumentCaptor<BillingClientStateListener> captor =
-        ArgumentCaptor.forClass(BillingClientStateListener.class);
-    doNothing().when(mockBillingClient).startConnection(captor.capture());
-
-    methodChannelHandler.onMethodCall(call, result);
-    return captor;
-  }
-
-  private void establishConnectedBillingClient(
-      @Nullable Map<String, Object> arguments, @Nullable Result result) {
-    if (arguments == null) {
-      arguments = new HashMap<>();
-      arguments.put("handle", 1);
-      arguments.put("enablePendingPurchases", true);
-    }
-    if (result == null) {
-      result = mock(Result.class);
-    }
-
-    MethodCall connectCall = new MethodCall(START_CONNECTION, arguments);
-    methodChannelHandler.onMethodCall(connectCall, result);
-  }
-
-  private void queryForSkus(List<String> skusList) {
-    // Set up the query method call
-    establishConnectedBillingClient(/* arguments= */ null, /* result= */ null);
-    HashMap<String, Object> arguments = new HashMap<>();
-    String skuType = SkuType.INAPP;
-    arguments.put("skuType", skuType);
-    arguments.put("skusList", skusList);
-    MethodCall queryCall = new MethodCall(QUERY_SKU_DETAILS, arguments);
-
-    // Call the method.
-    methodChannelHandler.onMethodCall(queryCall, mock(Result.class));
-
-    // Respond to the call with a matching set of Sku details.
-    ArgumentCaptor<SkuDetailsResponseListener> listenerCaptor =
-        ArgumentCaptor.forClass(SkuDetailsResponseListener.class);
-    verify(mockBillingClient).querySkuDetailsAsync(any(), listenerCaptor.capture());
-    List<SkuDetails> skuDetailsResponse =
-        skusList.stream().map(this::buildSkuDetails).collect(toList());
-
-    BillingResult billingResult =
-        BillingResult.newBuilder()
-            .setResponseCode(100)
-            .setDebugMessage("dummy debug message")
-            .build();
-    listenerCaptor.getValue().onSkuDetailsResponse(billingResult, skuDetailsResponse);
-  }
-
-  private SkuDetails buildSkuDetails(String id) {
-    String json =
-        String.format(
-            "{\"packageName\": \"dummyPackageName\",\"productId\":\"%s\",\"type\":\"inapp\",\"price\":\"$0.99\",\"price_amount_micros\":990000,\"price_currency_code\":\"USD\",\"title\":\"Example title\",\"description\":\"Example description.\",\"original_price\":\"$0.99\",\"original_price_micros\":990000}",
-            id);
-    SkuDetails details = null;
-    try {
-      details = new SkuDetails(json);
-    } catch (JSONException e) {
-      fail("buildSkuDetails failed with JSONException " + e.toString());
-    }
-    return details;
-  }
-
-  private Purchase buildPurchase(String orderId) {
-    Purchase purchase = mock(Purchase.class);
-    when(purchase.getOrderId()).thenReturn(orderId);
-    return purchase;
-  }
-
-  private PurchaseHistoryRecord buildPurchaseHistoryRecord(String purchaseToken) {
-    PurchaseHistoryRecord purchase = mock(PurchaseHistoryRecord.class);
-    when(purchase.getPurchaseToken()).thenReturn(purchaseToken);
-    return purchase;
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java
deleted file mode 100644
index 47147e7..0000000
--- a/packages/in_app_purchase/in_app_purchase/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package io.flutter.plugins.inapppurchase;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import com.android.billingclient.api.BillingClient;
-import com.android.billingclient.api.BillingResult;
-import com.android.billingclient.api.Purchase;
-import com.android.billingclient.api.Purchase.PurchasesResult;
-import com.android.billingclient.api.PurchaseHistoryRecord;
-import com.android.billingclient.api.SkuDetails;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.json.JSONException;
-import org.junit.Test;
-
-public class TranslatorTest {
-  private static final String SKU_DETAIL_EXAMPLE_JSON =
-      "{\"productId\":\"example\",\"type\":\"inapp\",\"price\":\"$0.99\",\"price_amount_micros\":990000,\"price_currency_code\":\"USD\",\"title\":\"Example title\",\"description\":\"Example description.\",\"original_price\":\"$0.99\",\"original_price_micros\":990000}";
-  private static final String PURCHASE_EXAMPLE_JSON =
-      "{\"orderId\":\"foo\",\"packageName\":\"bar\",\"productId\":\"consumable\",\"purchaseTime\":11111111,\"purchaseState\":0,\"purchaseToken\":\"baz\",\"developerPayload\":\"dummy payload\",\"isAcknowledged\":\"true\"}";
-
-  @Test
-  public void fromSkuDetail() throws JSONException {
-    final SkuDetails expected = new SkuDetails(SKU_DETAIL_EXAMPLE_JSON);
-
-    Map<String, Object> serialized = Translator.fromSkuDetail(expected);
-
-    assertSerialized(expected, serialized);
-  }
-
-  @Test
-  public void fromSkuDetailsList() throws JSONException {
-    final String SKU_DETAIL_EXAMPLE_2_JSON =
-        "{\"productId\":\"example2\",\"type\":\"inapp\",\"price\":\"$0.99\",\"price_amount_micros\":990000,\"price_currency_code\":\"USD\",\"title\":\"Example title\",\"description\":\"Example description.\",\"original_price\":\"$0.99\",\"original_price_micros\":990000}";
-    final List<SkuDetails> expected =
-        Arrays.asList(
-            new SkuDetails(SKU_DETAIL_EXAMPLE_JSON), new SkuDetails(SKU_DETAIL_EXAMPLE_2_JSON));
-
-    final List<HashMap<String, Object>> serialized = Translator.fromSkuDetailsList(expected);
-
-    assertEquals(expected.size(), serialized.size());
-    assertSerialized(expected.get(0), serialized.get(0));
-    assertSerialized(expected.get(1), serialized.get(1));
-  }
-
-  @Test
-  public void fromSkuDetailsList_null() {
-    assertEquals(Collections.emptyList(), Translator.fromSkuDetailsList(null));
-  }
-
-  @Test
-  public void fromPurchase() throws JSONException {
-    final Purchase expected = new Purchase(PURCHASE_EXAMPLE_JSON, "signature");
-    assertSerialized(expected, Translator.fromPurchase(expected));
-  }
-
-  @Test
-  public void fromPurchaseHistoryRecord() throws JSONException {
-    final PurchaseHistoryRecord expected =
-        new PurchaseHistoryRecord(PURCHASE_EXAMPLE_JSON, "signature");
-    assertSerialized(expected, Translator.fromPurchaseHistoryRecord(expected));
-  }
-
-  @Test
-  public void fromPurchasesHistoryRecordList() throws JSONException {
-    final String purchase2Json =
-        "{\"orderId\":\"foo2\",\"packageName\":\"bar\",\"productId\":\"consumable\",\"purchaseTime\":11111111,\"purchaseState\":0,\"purchaseToken\":\"baz\",\"developerPayload\":\"dummy payload\",\"isAcknowledged\":\"true\"}";
-    final String signature = "signature";
-    final List<PurchaseHistoryRecord> expected =
-        Arrays.asList(
-            new PurchaseHistoryRecord(PURCHASE_EXAMPLE_JSON, signature),
-            new PurchaseHistoryRecord(purchase2Json, signature));
-
-    final List<HashMap<String, Object>> serialized =
-        Translator.fromPurchaseHistoryRecordList(expected);
-
-    assertEquals(expected.size(), serialized.size());
-    assertSerialized(expected.get(0), serialized.get(0));
-    assertSerialized(expected.get(1), serialized.get(1));
-  }
-
-  @Test
-  public void fromPurchasesHistoryRecordList_null() {
-    assertEquals(Collections.emptyList(), Translator.fromPurchaseHistoryRecordList(null));
-  }
-
-  @Test
-  public void fromPurchasesList() throws JSONException {
-    final String purchase2Json =
-        "{\"orderId\":\"foo2\",\"packageName\":\"bar\",\"productId\":\"consumable\",\"purchaseTime\":11111111,\"purchaseState\":0,\"purchaseToken\":\"baz\",\"developerPayload\":\"dummy payload\",\"isAcknowledged\":\"true\"}";
-    final String signature = "signature";
-    final List<Purchase> expected =
-        Arrays.asList(
-            new Purchase(PURCHASE_EXAMPLE_JSON, signature), new Purchase(purchase2Json, signature));
-
-    final List<HashMap<String, Object>> serialized = Translator.fromPurchasesList(expected);
-
-    assertEquals(expected.size(), serialized.size());
-    assertSerialized(expected.get(0), serialized.get(0));
-    assertSerialized(expected.get(1), serialized.get(1));
-  }
-
-  @Test
-  public void fromPurchasesList_null() {
-    assertEquals(Collections.emptyList(), Translator.fromPurchasesList(null));
-  }
-
-  @Test
-  public void fromPurchasesResult() throws JSONException {
-    PurchasesResult result = mock(PurchasesResult.class);
-    final String purchase2Json =
-        "{\"orderId\":\"foo2\",\"packageName\":\"bar\",\"productId\":\"consumable\",\"purchaseTime\":11111111,\"purchaseState\":0,\"purchaseToken\":\"baz\",\"developerPayload\":\"dummy payload\",\"isAcknowledged\":\"true\"}";
-    final String signature = "signature";
-    final List<Purchase> expectedPurchases =
-        Arrays.asList(
-            new Purchase(PURCHASE_EXAMPLE_JSON, signature), new Purchase(purchase2Json, signature));
-    when(result.getPurchasesList()).thenReturn(expectedPurchases);
-    when(result.getResponseCode()).thenReturn(BillingClient.BillingResponseCode.OK);
-    BillingResult newBillingResult =
-        BillingResult.newBuilder()
-            .setDebugMessage("dummy debug message")
-            .setResponseCode(BillingClient.BillingResponseCode.OK)
-            .build();
-    when(result.getBillingResult()).thenReturn(newBillingResult);
-    final HashMap<String, Object> serialized = Translator.fromPurchasesResult(result);
-
-    assertEquals(BillingClient.BillingResponseCode.OK, serialized.get("responseCode"));
-    List<Map<String, Object>> serializedPurchases =
-        (List<Map<String, Object>>) serialized.get("purchasesList");
-    assertEquals(expectedPurchases.size(), serializedPurchases.size());
-    assertSerialized(expectedPurchases.get(0), serializedPurchases.get(0));
-    assertSerialized(expectedPurchases.get(1), serializedPurchases.get(1));
-
-    Map<String, Object> billingResultMap = (Map<String, Object>) serialized.get("billingResult");
-    assertEquals(billingResultMap.get("responseCode"), newBillingResult.getResponseCode());
-    assertEquals(billingResultMap.get("debugMessage"), newBillingResult.getDebugMessage());
-  }
-
-  @Test
-  public void fromBillingResult() throws JSONException {
-    BillingResult newBillingResult =
-        BillingResult.newBuilder()
-            .setDebugMessage("dummy debug message")
-            .setResponseCode(BillingClient.BillingResponseCode.OK)
-            .build();
-    Map<String, Object> billingResultMap = Translator.fromBillingResult(newBillingResult);
-
-    assertEquals(billingResultMap.get("responseCode"), newBillingResult.getResponseCode());
-    assertEquals(billingResultMap.get("debugMessage"), newBillingResult.getDebugMessage());
-  }
-
-  @Test
-  public void fromBillingResult_debugMessageNull() throws JSONException {
-    BillingResult newBillingResult =
-        BillingResult.newBuilder().setResponseCode(BillingClient.BillingResponseCode.OK).build();
-    Map<String, Object> billingResultMap = Translator.fromBillingResult(newBillingResult);
-
-    assertEquals(billingResultMap.get("responseCode"), newBillingResult.getResponseCode());
-    assertEquals(billingResultMap.get("debugMessage"), newBillingResult.getDebugMessage());
-  }
-
-  private void assertSerialized(SkuDetails expected, Map<String, Object> serialized) {
-    assertEquals(expected.getDescription(), serialized.get("description"));
-    assertEquals(expected.getFreeTrialPeriod(), serialized.get("freeTrialPeriod"));
-    assertEquals(expected.getIntroductoryPrice(), serialized.get("introductoryPrice"));
-    assertEquals(
-        expected.getIntroductoryPriceAmountMicros(),
-        serialized.get("introductoryPriceAmountMicros"));
-    assertEquals(expected.getIntroductoryPriceCycles(), serialized.get("introductoryPriceCycles"));
-    assertEquals(expected.getIntroductoryPricePeriod(), serialized.get("introductoryPricePeriod"));
-    assertEquals(expected.getPrice(), serialized.get("price"));
-    assertEquals(expected.getPriceAmountMicros(), serialized.get("priceAmountMicros"));
-    assertEquals(expected.getPriceCurrencyCode(), serialized.get("priceCurrencyCode"));
-    assertEquals(expected.getSku(), serialized.get("sku"));
-    assertEquals(expected.getSubscriptionPeriod(), serialized.get("subscriptionPeriod"));
-    assertEquals(expected.getTitle(), serialized.get("title"));
-    assertEquals(expected.getType(), serialized.get("type"));
-    assertEquals(expected.getOriginalPrice(), serialized.get("originalPrice"));
-    assertEquals(
-        expected.getOriginalPriceAmountMicros(), serialized.get("originalPriceAmountMicros"));
-  }
-
-  private void assertSerialized(Purchase expected, Map<String, Object> serialized) {
-    assertEquals(expected.getOrderId(), serialized.get("orderId"));
-    assertEquals(expected.getPackageName(), serialized.get("packageName"));
-    assertEquals(expected.getPurchaseTime(), serialized.get("purchaseTime"));
-    assertEquals(expected.getPurchaseToken(), serialized.get("purchaseToken"));
-    assertEquals(expected.getSignature(), serialized.get("signature"));
-    assertEquals(expected.getOriginalJson(), serialized.get("originalJson"));
-    assertEquals(expected.getSku(), serialized.get("sku"));
-    assertEquals(expected.getDeveloperPayload(), serialized.get("developerPayload"));
-    assertEquals(expected.isAcknowledged(), serialized.get("isAcknowledged"));
-    assertEquals(expected.getPurchaseState(), serialized.get("purchaseState"));
-  }
-
-  private void assertSerialized(PurchaseHistoryRecord expected, Map<String, Object> serialized) {
-    assertEquals(expected.getPurchaseTime(), serialized.get("purchaseTime"));
-    assertEquals(expected.getPurchaseToken(), serialized.get("purchaseToken"));
-    assertEquals(expected.getSignature(), serialized.get("signature"));
-    assertEquals(expected.getOriginalJson(), serialized.get("originalJson"));
-    assertEquals(expected.getSku(), serialized.get("sku"));
-    assertEquals(expected.getDeveloperPayload(), serialized.get("developerPayload"));
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/example/integration_test/in_app_purchase_test.dart b/packages/in_app_purchase/in_app_purchase/example/integration_test/in_app_purchase_test.dart
index ca1eea6..4a87077 100644
--- a/packages/in_app_purchase/in_app_purchase/example/integration_test/in_app_purchase_test.dart
+++ b/packages/in_app_purchase/in_app_purchase/example/integration_test/in_app_purchase_test.dart
@@ -10,9 +10,8 @@
 void main() {
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
 
-  testWidgets('Can create InAppPurchaseConnection instance',
-      (WidgetTester tester) async {
-    final InAppPurchaseConnection connection = InAppPurchaseConnection.instance;
-    expect(connection, isNotNull);
+  testWidgets('Can create InAppPurchase instance', (WidgetTester tester) async {
+    final InAppPurchase iapInstance = InAppPurchase.instance;
+    expect(iapInstance, isNotNull);
   });
 }
diff --git a/packages/in_app_purchase/in_app_purchase/example/ios/Podfile b/packages/in_app_purchase/in_app_purchase/example/ios/Podfile
index 7079e94..310b9b4 100644
--- a/packages/in_app_purchase/in_app_purchase/example/ios/Podfile
+++ b/packages/in_app_purchase/in_app_purchase/example/ios/Podfile
@@ -30,12 +30,6 @@
 target 'Runner' do
   flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
 
-  target 'in_app_purchase_pluginTests' do
-    inherit! :search_paths
-
-    # Matches in_app_purchase test_spec dependency.
-    pod 'OCMock','3.5'
-  end
 end
 
 post_install do |installer|
diff --git a/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj b/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj
index 3821ea2..0155d79 100644
--- a/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/project.pbxproj
@@ -9,10 +9,6 @@
 /* Begin PBXBuildFile section */
 		1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
 		3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
-		523686A0BE5A2D2269D4F386 /* libPods-in_app_purchase_pluginTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E20838C66ABCD8667B0BB95D /* libPods-in_app_purchase_pluginTests.a */; };
-		688DE35121F2A5A100EA2684 /* TranslatorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 688DE35021F2A5A100EA2684 /* TranslatorTest.m */; };
-		6896B34621E9363700D37AEF /* ProductRequestHandlerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6896B34521E9363700D37AEF /* ProductRequestHandlerTest.m */; };
-		6896B34C21EEB4B800D37AEF /* Stubs.m in Sources */ = {isa = PBXBuildFile; fileRef = 6896B34B21EEB4B800D37AEF /* Stubs.m */; };
 		861D0D93B0757D95C8A69620 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B2AB6BE1D4E2232AB5D4A002 /* libPods-Runner.a */; };
 		978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
 		97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
@@ -20,20 +16,8 @@
 		97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
 		97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
 		A5279298219369C600FF69E6 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A5279297219369C600FF69E6 /* StoreKit.framework */; };
-		A59001A721E69658004A3E5E /* InAppPurchasePluginTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A59001A621E69658004A3E5E /* InAppPurchasePluginTest.m */; };
-		F78AF3142342BC89008449C7 /* PaymentQueueTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F78AF3132342BC89008449C7 /* PaymentQueueTest.m */; };
 /* End PBXBuildFile section */
 
-/* Begin PBXContainerItemProxy section */
-		A59001A921E69658004A3E5E /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = 97C146E61CF9000F007C117D /* Project object */;
-			proxyType = 1;
-			remoteGlobalIDString = 97C146ED1CF9000F007C117D;
-			remoteInfo = Runner;
-		};
-/* End PBXContainerItemProxy section */
-
 /* Begin PBXCopyFilesBuildPhase section */
 		9705A1C41CF9048500538489 /* Embed Frameworks */ = {
 			isa = PBXCopyFilesBuildPhase;
@@ -51,10 +35,6 @@
 		1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
 		1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
 		3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
-		688DE35021F2A5A100EA2684 /* TranslatorTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TranslatorTest.m; path = ../../../ios/Tests/TranslatorTest.m; sourceTree = "<group>"; };
-		6896B34521E9363700D37AEF /* ProductRequestHandlerTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ProductRequestHandlerTest.m; path = ../../../ios/Tests/ProductRequestHandlerTest.m; sourceTree = "<group>"; };
-		6896B34A21EEB4B800D37AEF /* Stubs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Stubs.h; path = ../../../ios/Tests/Stubs.h; sourceTree = "<group>"; };
-		6896B34B21EEB4B800D37AEF /* Stubs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Stubs.m; path = ../../../ios/Tests/Stubs.m; sourceTree = "<group>"; };
 		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
 		7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
 		7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -67,9 +47,6 @@
 		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
 		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		A5279297219369C600FF69E6 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
-		A59001A421E69658004A3E5E /* in_app_purchase_pluginTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = in_app_purchase_pluginTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-		A59001A621E69658004A3E5E /* InAppPurchasePluginTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = InAppPurchasePluginTest.m; path = ../../../ios/Tests/InAppPurchasePluginTest.m; sourceTree = "<group>"; };
-		A59001A821E69658004A3E5E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		ACAF3B1D3B61187149C0FF81 /* Pods-in_app_purchase_pluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-in_app_purchase_pluginTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-in_app_purchase_pluginTests/Pods-in_app_purchase_pluginTests.release.xcconfig"; sourceTree = "<group>"; };
 		B2AB6BE1D4E2232AB5D4A002 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 		BE95F46E12942F78BF67E55B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
@@ -77,7 +54,6 @@
 		DE7EEEE26E27ACC04BA9951D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
 		E20838C66ABCD8667B0BB95D /* libPods-in_app_purchase_pluginTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-in_app_purchase_pluginTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 		F6E5D5F926131C4800C68BED /* Configuration.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = Configuration.storekit; sourceTree = "<group>"; };
-		F78AF3132342BC89008449C7 /* PaymentQueueTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PaymentQueueTest.m; path = ../../../ios/Tests/PaymentQueueTest.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -90,14 +66,6 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
-		A59001A121E69658004A3E5E /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				523686A0BE5A2D2269D4F386 /* libPods-in_app_purchase_pluginTests.a in Frameworks */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
@@ -128,7 +96,6 @@
 			children = (
 				9740EEB11CF90186004384FC /* Flutter */,
 				97C146F01CF9000F007C117D /* Runner */,
-				A59001A521E69658004A3E5E /* in_app_purchase_pluginTests */,
 				97C146EF1CF9000F007C117D /* Products */,
 				2D4BBB2E0E7B18550E80D50C /* Pods */,
 				E4DB99639FAD8ADED6B572FC /* Frameworks */,
@@ -139,7 +106,6 @@
 			isa = PBXGroup;
 			children = (
 				97C146EE1CF9000F007C117D /* Runner.app */,
-				A59001A421E69658004A3E5E /* in_app_purchase_pluginTests.xctest */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -169,20 +135,6 @@
 			name = "Supporting Files";
 			sourceTree = "<group>";
 		};
-		A59001A521E69658004A3E5E /* in_app_purchase_pluginTests */ = {
-			isa = PBXGroup;
-			children = (
-				A59001A621E69658004A3E5E /* InAppPurchasePluginTest.m */,
-				6896B34521E9363700D37AEF /* ProductRequestHandlerTest.m */,
-				F78AF3132342BC89008449C7 /* PaymentQueueTest.m */,
-				A59001A821E69658004A3E5E /* Info.plist */,
-				6896B34A21EEB4B800D37AEF /* Stubs.h */,
-				6896B34B21EEB4B800D37AEF /* Stubs.m */,
-				688DE35021F2A5A100EA2684 /* TranslatorTest.m */,
-			);
-			path = in_app_purchase_pluginTests;
-			sourceTree = "<group>";
-		};
 		E4DB99639FAD8ADED6B572FC /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
@@ -217,25 +169,6 @@
 			productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
 			productType = "com.apple.product-type.application";
 		};
-		A59001A321E69658004A3E5E /* in_app_purchase_pluginTests */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = A59001AD21E69658004A3E5E /* Build configuration list for PBXNativeTarget "in_app_purchase_pluginTests" */;
-			buildPhases = (
-				4EA84B170943DF9C4A2CF33C /* [CP] Check Pods Manifest.lock */,
-				A59001A021E69658004A3E5E /* Sources */,
-				A59001A121E69658004A3E5E /* Frameworks */,
-				A59001A221E69658004A3E5E /* Resources */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-				A59001AA21E69658004A3E5E /* PBXTargetDependency */,
-			);
-			name = in_app_purchase_pluginTests;
-			productName = in_app_purchase_pluginTests;
-			productReference = A59001A421E69658004A3E5E /* in_app_purchase_pluginTests.xctest */;
-			productType = "com.apple.product-type.bundle.unit-test";
-		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
@@ -254,11 +187,6 @@
 							};
 						};
 					};
-					A59001A321E69658004A3E5E = {
-						CreatedOnToolsVersion = 10.0;
-						ProvisioningStyle = Automatic;
-						TestTargetID = 97C146ED1CF9000F007C117D;
-					};
 				};
 			};
 			buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
@@ -275,7 +203,6 @@
 			projectRoot = "";
 			targets = (
 				97C146ED1CF9000F007C117D /* Runner */,
-				A59001A321E69658004A3E5E /* in_app_purchase_pluginTests */,
 			);
 		};
 /* End PBXProject section */
@@ -292,13 +219,6 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
-		A59001A221E69658004A3E5E /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
@@ -316,28 +236,6 @@
 			shellPath = /bin/sh;
 			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
 		};
-		4EA84B170943DF9C4A2CF33C /* [CP] Check Pods Manifest.lock */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputFileListPaths = (
-			);
-			inputPaths = (
-				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
-				"${PODS_ROOT}/Manifest.lock",
-			);
-			name = "[CP] Check Pods Manifest.lock";
-			outputFileListPaths = (
-			);
-			outputPaths = (
-				"$(DERIVED_FILE_DIR)/Pods-in_app_purchase_pluginTests-checkManifestLockResult.txt",
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
-			showEnvVarsInLog = 0;
-		};
 		5DF63B80D489A62B306EA07A /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
@@ -383,28 +281,8 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
-		A59001A021E69658004A3E5E /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				F78AF3142342BC89008449C7 /* PaymentQueueTest.m in Sources */,
-				6896B34621E9363700D37AEF /* ProductRequestHandlerTest.m in Sources */,
-				688DE35121F2A5A100EA2684 /* TranslatorTest.m in Sources */,
-				A59001A721E69658004A3E5E /* InAppPurchasePluginTest.m in Sources */,
-				6896B34C21EEB4B800D37AEF /* Stubs.m in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
 /* End PBXSourcesBuildPhase section */
 
-/* Begin PBXTargetDependency section */
-		A59001AA21E69658004A3E5E /* PBXTargetDependency */ = {
-			isa = PBXTargetDependency;
-			target = 97C146ED1CF9000F007C117D /* Runner */;
-			targetProxy = A59001A921E69658004A3E5E /* PBXContainerItemProxy */;
-		};
-/* End PBXTargetDependency section */
-
 /* Begin PBXVariantGroup section */
 		97C146FA1CF9000F007C117D /* Main.storyboard */ = {
 			isa = PBXVariantGroup;
@@ -537,6 +415,7 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CURRENT_PROJECT_VERSION = 1;
+				DEVELOPMENT_TEAM = "";
 				ENABLE_BITCODE = NO;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
@@ -548,7 +427,7 @@
 					"$(inherited)",
 					"$(PROJECT_DIR)/Flutter",
 				);
-				PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.inAppPurchaseExample;
+				PRODUCT_BUNDLE_IDENTIFIER = com.baseflow.example.iap;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				VERSIONING_SYSTEM = "apple-generic";
 			};
@@ -560,6 +439,7 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CURRENT_PROJECT_VERSION = 1;
+				DEVELOPMENT_TEAM = "";
 				ENABLE_BITCODE = NO;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
@@ -571,55 +451,12 @@
 					"$(inherited)",
 					"$(PROJECT_DIR)/Flutter",
 				);
-				PRODUCT_BUNDLE_IDENTIFIER = io.flutter.plugins.inAppPurchaseExample;
+				PRODUCT_BUNDLE_IDENTIFIER = com.baseflow.example.iap;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				VERSIONING_SYSTEM = "apple-generic";
 			};
 			name = Release;
 		};
-		A59001AB21E69658004A3E5E /* Debug */ = {
-			isa = XCBuildConfiguration;
-			baseConfigurationReference = CC2B3FFB29B2574DEDD718A6 /* Pods-in_app_purchase_pluginTests.debug.xcconfig */;
-			buildSettings = {
-				BUNDLE_LOADER = "$(TEST_HOST)";
-				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-				CLANG_ENABLE_OBJC_WEAK = YES;
-				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-				CODE_SIGN_STYLE = Automatic;
-				INFOPLIST_FILE = in_app_purchase_pluginTests/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
-				MTL_FAST_MATH = YES;
-				PRODUCT_BUNDLE_IDENTIFIER = "sample.changme.in-app-purchase-pluginTests";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner";
-			};
-			name = Debug;
-		};
-		A59001AC21E69658004A3E5E /* Release */ = {
-			isa = XCBuildConfiguration;
-			baseConfigurationReference = ACAF3B1D3B61187149C0FF81 /* Pods-in_app_purchase_pluginTests.release.xcconfig */;
-			buildSettings = {
-				BUNDLE_LOADER = "$(TEST_HOST)";
-				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-				CLANG_ENABLE_OBJC_WEAK = YES;
-				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
-				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-				CODE_SIGN_STYLE = Automatic;
-				INFOPLIST_FILE = in_app_purchase_pluginTests/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-				MTL_FAST_MATH = YES;
-				PRODUCT_BUNDLE_IDENTIFIER = "sample.changme.in-app-purchase-pluginTests";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner";
-			};
-			name = Release;
-		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
@@ -641,15 +478,6 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		A59001AD21E69658004A3E5E /* Build configuration list for PBXNativeTarget "in_app_purchase_pluginTests" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				A59001AB21E69658004A3E5E /* Debug */,
-				A59001AC21E69658004A3E5E /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
 /* End XCConfigurationList section */
 	};
 	rootObject = 97C146E61CF9000F007C117D /* Project object */;
diff --git a/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index e1fad2d..3bb3697 100644
--- a/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/packages/in_app_purchase/in_app_purchase/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -37,16 +37,6 @@
          </BuildableReference>
       </MacroExpansion>
       <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "A59001A321E69658004A3E5E"
-               BuildableName = "in_app_purchase_pluginTests.xctest"
-               BlueprintName = "in_app_purchase_pluginTests"
-               ReferencedContainer = "container:Runner.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
       </Testables>
    </TestAction>
    <LaunchAction
diff --git a/packages/in_app_purchase/in_app_purchase/example/ios/in_app_purchase_pluginTests/Info.plist b/packages/in_app_purchase/in_app_purchase/example/ios/in_app_purchase_pluginTests/Info.plist
deleted file mode 100644
index 6c40a6c..0000000
--- a/packages/in_app_purchase/in_app_purchase/example/ios/in_app_purchase_pluginTests/Info.plist
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>$(DEVELOPMENT_LANGUAGE)</string>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIdentifier</key>
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundlePackageType</key>
-	<string>BNDL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-</dict>
-</plist>
diff --git a/packages/in_app_purchase/in_app_purchase/example/lib/main.dart b/packages/in_app_purchase/in_app_purchase/example/lib/main.dart
index 58cca91..17beade 100644
--- a/packages/in_app_purchase/in_app_purchase/example/lib/main.dart
+++ b/packages/in_app_purchase/in_app_purchase/example/lib/main.dart
@@ -4,15 +4,23 @@
 
 import 'dart:async';
 import 'dart:io';
+import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:in_app_purchase/in_app_purchase.dart';
+import 'package:in_app_purchase_android/billing_client_wrappers.dart';
+import 'package:in_app_purchase_android/in_app_purchase_android.dart';
 import 'consumable_store.dart';
 
 void main() {
-  // For play billing library 2.0 on Android, it is mandatory to call
-  // [enablePendingPurchases](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.Builder.html#enablependingpurchases)
-  // as part of initializing the app.
-  InAppPurchaseConnection.enablePendingPurchases();
+  WidgetsFlutterBinding.ensureInitialized();
+
+  if (defaultTargetPlatform == TargetPlatform.android) {
+    // For play billing library 2.0 on Android, it is mandatory to call
+    // [enablePendingPurchases](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.Builder.html#enablependingpurchases)
+    // as part of initializing the app.
+    InAppPurchaseAndroidPlatformAddition.enablePendingPurchases();
+  }
+
   runApp(_MyApp());
 }
 
@@ -35,7 +43,7 @@
 }
 
 class _MyAppState extends State<_MyApp> {
-  final InAppPurchaseConnection _connection = InAppPurchaseConnection.instance;
+  final InAppPurchase _inAppPurchase = InAppPurchase.instance;
   late StreamSubscription<List<PurchaseDetails>> _subscription;
   List<String> _notFoundIds = [];
   List<ProductDetails> _products = [];
@@ -49,7 +57,7 @@
   @override
   void initState() {
     final Stream<List<PurchaseDetails>> purchaseUpdated =
-        InAppPurchaseConnection.instance.purchaseUpdatedStream;
+        _inAppPurchase.purchaseStream;
     _subscription = purchaseUpdated.listen((purchaseDetailsList) {
       _listenToPurchaseUpdated(purchaseDetailsList);
     }, onDone: () {
@@ -62,7 +70,7 @@
   }
 
   Future<void> initStoreInfo() async {
-    final bool isAvailable = await _connection.isAvailable();
+    final bool isAvailable = await _inAppPurchase.isAvailable();
     if (!isAvailable) {
       setState(() {
         _isAvailable = isAvailable;
@@ -77,7 +85,7 @@
     }
 
     ProductDetailsResponse productDetailResponse =
-        await _connection.queryProductDetails(_kProductIds.toSet());
+        await _inAppPurchase.queryProductDetails(_kProductIds.toSet());
     if (productDetailResponse.error != null) {
       setState(() {
         _queryProductError = productDetailResponse.error!.message;
@@ -106,22 +114,12 @@
       return;
     }
 
-    final QueryPurchaseDetailsResponse purchaseResponse =
-        await _connection.queryPastPurchases();
-    if (purchaseResponse.error != null) {
-      // handle query past purchase error..
-    }
-    final List<PurchaseDetails> verifiedPurchases = [];
-    for (PurchaseDetails purchase in purchaseResponse.pastPurchases) {
-      if (await _verifyPurchase(purchase)) {
-        verifiedPurchases.add(purchase);
-      }
-    }
+    await _inAppPurchase.restorePurchases();
+
     List<String> consumables = await ConsumableStore.load();
     setState(() {
       _isAvailable = isAvailable;
       _products = productDetailResponse.productDetails;
-      _purchases = verifiedPurchases;
       _notFoundIds = productDetailResponse.notFoundIDs;
       _consumables = consumables;
       _purchasePending = false;
@@ -233,7 +231,7 @@
     Map<String, PurchaseDetails> purchases =
         Map.fromEntries(_purchases.map((PurchaseDetails purchase) {
       if (purchase.pendingCompletePurchase) {
-        InAppPurchaseConnection.instance.completePurchase(purchase);
+        _inAppPurchase.completePurchase(purchase);
       }
       return MapEntry<String, PurchaseDetails>(purchase.productID, purchase);
     }));
@@ -256,28 +254,39 @@
                       primary: Colors.white,
                     ),
                     onPressed: () {
-                      // NOTE: If you are making a subscription purchase/upgrade/downgrade, we recommend you to
-                      // verify the latest status of you your subscription by using server side receipt validation
-                      // and update the UI accordingly. The subscription purchase status shown
-                      // inside the app may not be accurate.
-                      final oldSubscription =
-                          _getOldSubscription(productDetails, purchases);
-                      PurchaseParam purchaseParam = PurchaseParam(
+                      late PurchaseParam purchaseParam;
+
+                      if (Platform.isAndroid) {
+                        // NOTE: If you are making a subscription purchase/upgrade/downgrade, we recommend you to
+                        // verify the latest status of you your subscription by using server side receipt validation
+                        // and update the UI accordingly. The subscription purchase status shown
+                        // inside the app may not be accurate.
+                        final oldSubscription =
+                            _getOldSubscription(productDetails, purchases);
+
+                        purchaseParam = GooglePlayPurchaseParam(
+                            productDetails: productDetails,
+                            applicationUserName: null,
+                            changeSubscriptionParam: (oldSubscription != null)
+                                ? ChangeSubscriptionParam(
+                                    oldPurchaseDetails: oldSubscription,
+                                    prorationMode: ProrationMode
+                                        .immediateWithTimeProration,
+                                  )
+                                : null);
+                      } else {
+                        purchaseParam = PurchaseParam(
                           productDetails: productDetails,
                           applicationUserName: null,
-                          changeSubscriptionParam: Platform.isAndroid &&
-                                  oldSubscription != null
-                              ? ChangeSubscriptionParam(
-                                  oldPurchaseDetails: oldSubscription,
-                                  prorationMode:
-                                      ProrationMode.immediateWithTimeProration)
-                              : null);
+                        );
+                      }
+
                       if (productDetails.id == _kConsumableId) {
-                        _connection.buyConsumable(
+                        _inAppPurchase.buyConsumable(
                             purchaseParam: purchaseParam,
                             autoConsume: _kAutoConsume || Platform.isIOS);
                       } else {
-                        _connection.buyNonConsumable(
+                        _inAppPurchase.buyNonConsumable(
                             purchaseParam: purchaseParam);
                       }
                     },
@@ -393,19 +402,20 @@
         }
         if (Platform.isAndroid) {
           if (!_kAutoConsume && purchaseDetails.productID == _kConsumableId) {
-            await InAppPurchaseConnection.instance
-                .consumePurchase(purchaseDetails);
+            final InAppPurchaseAndroidPlatformAddition androidAddition =
+                _inAppPurchase.getPlatformAddition<
+                    InAppPurchaseAndroidPlatformAddition>();
+            await androidAddition.consumePurchase(purchaseDetails);
           }
         }
         if (purchaseDetails.pendingCompletePurchase) {
-          await InAppPurchaseConnection.instance
-              .completePurchase(purchaseDetails);
+          await _inAppPurchase.completePurchase(purchaseDetails);
         }
       }
     });
   }
 
-  PurchaseDetails? _getOldSubscription(
+  GooglePlayPurchaseDetails? _getOldSubscription(
       ProductDetails productDetails, Map<String, PurchaseDetails> purchases) {
     // This is just to demonstrate a subscription upgrade or downgrade.
     // This method assumes that you have only 2 subscriptions under a group, 'subscription_silver' & 'subscription_gold'.
@@ -414,13 +424,15 @@
     // Please remember to replace the logic of finding the old subscription Id as per your app.
     // The old subscription is only required on Android since Apple handles this internally
     // by using the subscription group feature in iTunesConnect.
-    PurchaseDetails? oldSubscription;
+    GooglePlayPurchaseDetails? oldSubscription;
     if (productDetails.id == _kSilverSubscriptionId &&
         purchases[_kGoldSubscriptionId] != null) {
-      oldSubscription = purchases[_kGoldSubscriptionId];
+      oldSubscription =
+          purchases[_kGoldSubscriptionId] as GooglePlayPurchaseDetails;
     } else if (productDetails.id == _kGoldSubscriptionId &&
         purchases[_kSilverSubscriptionId] != null) {
-      oldSubscription = purchases[_kSilverSubscriptionId];
+      oldSubscription =
+          purchases[_kSilverSubscriptionId] as GooglePlayPurchaseDetails;
     }
     return oldSubscription;
   }
diff --git a/packages/in_app_purchase/in_app_purchase/example/pubspec.yaml b/packages/in_app_purchase/in_app_purchase/example/pubspec.yaml
index 1acddc1..da9cf63 100644
--- a/packages/in_app_purchase/in_app_purchase/example/pubspec.yaml
+++ b/packages/in_app_purchase/in_app_purchase/example/pubspec.yaml
@@ -7,9 +7,6 @@
     sdk: flutter
   shared_preferences: ^2.0.0-nullsafety.1
 
-dev_dependencies:
-  flutter_driver:
-    sdk: flutter
   in_app_purchase:
     # When depending on this package from a real application you should use:
     #   in_app_purchase: ^x.y.z
@@ -17,6 +14,11 @@
     # The example app is bundled with the plugin so we use a path dependency on
     # the parent directory to use the current plugin's version.
     path: ../
+
+dev_dependencies:
+  flutter_driver:
+    sdk: flutter
+
   integration_test:
     sdk: flutter
   pedantic: ^1.10.0
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Assets/.gitkeep b/packages/in_app_purchase/in_app_purchase/ios/Assets/.gitkeep
deleted file mode 100644
index e69de29..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Assets/.gitkeep
+++ /dev/null
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAObjectTranslator.h b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAObjectTranslator.h
deleted file mode 100644
index 2d0187e..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAObjectTranslator.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Foundation/Foundation.h>
-#import <StoreKit/StoreKit.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface FIAObjectTranslator : NSObject
-
-+ (NSDictionary *)getMapFromSKProduct:(SKProduct *)product;
-
-+ (NSDictionary *)getMapFromSKProductSubscriptionPeriod:(SKProductSubscriptionPeriod *)period
-    API_AVAILABLE(ios(11.2));
-
-+ (NSDictionary *)getMapFromSKProductDiscount:(SKProductDiscount *)discount
-    API_AVAILABLE(ios(11.2));
-
-+ (NSDictionary *)getMapFromSKProductsResponse:(SKProductsResponse *)productResponse;
-
-+ (NSDictionary *)getMapFromSKPayment:(SKPayment *)payment;
-
-+ (NSDictionary *)getMapFromNSLocale:(NSLocale *)locale;
-
-+ (SKMutablePayment *)getSKMutablePaymentFromMap:(NSDictionary *)map;
-
-+ (NSDictionary *)getMapFromSKPaymentTransaction:(SKPaymentTransaction *)transaction;
-
-+ (NSDictionary *)getMapFromNSError:(NSError *)error;
-
-@end
-;
-
-NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAObjectTranslator.m b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAObjectTranslator.m
deleted file mode 100644
index 5d6e0a2..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAObjectTranslator.m
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "FIAObjectTranslator.h"
-
-#pragma mark - SKProduct Coders
-
-@implementation FIAObjectTranslator
-
-+ (NSDictionary *)getMapFromSKProduct:(SKProduct *)product {
-  if (!product) {
-    return nil;
-  }
-  NSMutableDictionary *map = [[NSMutableDictionary alloc] initWithDictionary:@{
-    @"localizedDescription" : product.localizedDescription ?: [NSNull null],
-    @"localizedTitle" : product.localizedTitle ?: [NSNull null],
-    @"productIdentifier" : product.productIdentifier ?: [NSNull null],
-    @"price" : product.price.description ?: [NSNull null]
-
-  }];
-  // TODO(cyanglaz): NSLocale is a complex object, want to see the actual need of getting this
-  // expanded to a map. Matching android to only get the currencySymbol for now.
-  // https://github.com/flutter/flutter/issues/26610
-  [map setObject:[FIAObjectTranslator getMapFromNSLocale:product.priceLocale] ?: [NSNull null]
-          forKey:@"priceLocale"];
-  if (@available(iOS 11.2, *)) {
-    [map setObject:[FIAObjectTranslator
-                       getMapFromSKProductSubscriptionPeriod:product.subscriptionPeriod]
-                       ?: [NSNull null]
-            forKey:@"subscriptionPeriod"];
-  }
-  if (@available(iOS 11.2, *)) {
-    [map setObject:[FIAObjectTranslator getMapFromSKProductDiscount:product.introductoryPrice]
-                       ?: [NSNull null]
-            forKey:@"introductoryPrice"];
-  }
-  if (@available(iOS 12.0, *)) {
-    [map setObject:product.subscriptionGroupIdentifier ?: [NSNull null]
-            forKey:@"subscriptionGroupIdentifier"];
-  }
-  return map;
-}
-
-+ (NSDictionary *)getMapFromSKProductSubscriptionPeriod:(SKProductSubscriptionPeriod *)period {
-  if (!period) {
-    return nil;
-  }
-  return @{@"numberOfUnits" : @(period.numberOfUnits), @"unit" : @(period.unit)};
-}
-
-+ (NSDictionary *)getMapFromSKProductDiscount:(SKProductDiscount *)discount {
-  if (!discount) {
-    return nil;
-  }
-  NSMutableDictionary *map = [[NSMutableDictionary alloc] initWithDictionary:@{
-    @"price" : discount.price.description ?: [NSNull null],
-    @"numberOfPeriods" : @(discount.numberOfPeriods),
-    @"subscriptionPeriod" :
-            [FIAObjectTranslator getMapFromSKProductSubscriptionPeriod:discount.subscriptionPeriod]
-        ?: [NSNull null],
-    @"paymentMode" : @(discount.paymentMode)
-  }];
-
-  // TODO(cyanglaz): NSLocale is a complex object, want to see the actual need of getting this
-  // expanded to a map. Matching android to only get the currencySymbol for now.
-  // https://github.com/flutter/flutter/issues/26610
-  [map setObject:[FIAObjectTranslator getMapFromNSLocale:discount.priceLocale] ?: [NSNull null]
-          forKey:@"priceLocale"];
-  return map;
-}
-
-+ (NSDictionary *)getMapFromSKProductsResponse:(SKProductsResponse *)productResponse {
-  if (!productResponse) {
-    return nil;
-  }
-  NSMutableArray *productsMapArray = [NSMutableArray new];
-  for (SKProduct *product in productResponse.products) {
-    [productsMapArray addObject:[FIAObjectTranslator getMapFromSKProduct:product]];
-  }
-  return @{
-    @"products" : productsMapArray,
-    @"invalidProductIdentifiers" : productResponse.invalidProductIdentifiers ?: @[]
-  };
-}
-
-+ (NSDictionary *)getMapFromSKPayment:(SKPayment *)payment {
-  if (!payment) {
-    return nil;
-  }
-  NSMutableDictionary *map = [[NSMutableDictionary alloc] initWithDictionary:@{
-    @"productIdentifier" : payment.productIdentifier ?: [NSNull null],
-    @"requestData" : payment.requestData ? [[NSString alloc] initWithData:payment.requestData
-                                                                 encoding:NSUTF8StringEncoding]
-                                         : [NSNull null],
-    @"quantity" : @(payment.quantity),
-    @"applicationUsername" : payment.applicationUsername ?: [NSNull null]
-  }];
-  if (@available(iOS 8.3, *)) {
-    [map setObject:@(payment.simulatesAskToBuyInSandbox) forKey:@"simulatesAskToBuyInSandbox"];
-  }
-  return map;
-}
-
-+ (NSDictionary *)getMapFromNSLocale:(NSLocale *)locale {
-  if (!locale) {
-    return nil;
-  }
-  NSMutableDictionary *map = [[NSMutableDictionary alloc] init];
-  [map setObject:[locale objectForKey:NSLocaleCurrencySymbol] ?: [NSNull null]
-          forKey:@"currencySymbol"];
-  [map setObject:[locale objectForKey:NSLocaleCurrencyCode] ?: [NSNull null]
-          forKey:@"currencyCode"];
-  return map;
-}
-
-+ (SKMutablePayment *)getSKMutablePaymentFromMap:(NSDictionary *)map {
-  if (!map) {
-    return nil;
-  }
-  SKMutablePayment *payment = [[SKMutablePayment alloc] init];
-  payment.productIdentifier = map[@"productIdentifier"];
-  NSString *utf8String = map[@"requestData"];
-  payment.requestData = [utf8String dataUsingEncoding:NSUTF8StringEncoding];
-  payment.quantity = [map[@"quantity"] integerValue];
-  payment.applicationUsername = map[@"applicationUsername"];
-  if (@available(iOS 8.3, *)) {
-    payment.simulatesAskToBuyInSandbox = [map[@"simulatesAskToBuyInSandbox"] boolValue];
-  }
-  return payment;
-}
-
-+ (NSDictionary *)getMapFromSKPaymentTransaction:(SKPaymentTransaction *)transaction {
-  if (!transaction) {
-    return nil;
-  }
-  NSMutableDictionary *map = [[NSMutableDictionary alloc] initWithDictionary:@{
-    @"error" : [FIAObjectTranslator getMapFromNSError:transaction.error] ?: [NSNull null],
-    @"payment" : transaction.payment ? [FIAObjectTranslator getMapFromSKPayment:transaction.payment]
-                                     : [NSNull null],
-    @"originalTransaction" : transaction.originalTransaction
-        ? [FIAObjectTranslator getMapFromSKPaymentTransaction:transaction.originalTransaction]
-        : [NSNull null],
-    @"transactionTimeStamp" : transaction.transactionDate
-        ? @(transaction.transactionDate.timeIntervalSince1970)
-        : [NSNull null],
-    @"transactionIdentifier" : transaction.transactionIdentifier ?: [NSNull null],
-    @"transactionState" : @(transaction.transactionState)
-  }];
-
-  return map;
-}
-
-+ (NSDictionary *)getMapFromNSError:(NSError *)error {
-  if (!error) {
-    return nil;
-  }
-  NSMutableDictionary *userInfo = [NSMutableDictionary new];
-  for (NSErrorUserInfoKey key in error.userInfo) {
-    id value = error.userInfo[key];
-    if ([value isKindOfClass:[NSError class]]) {
-      userInfo[key] = [FIAObjectTranslator getMapFromNSError:value];
-    } else if ([value isKindOfClass:[NSURL class]]) {
-      userInfo[key] = [value absoluteString];
-    } else {
-      userInfo[key] = value;
-    }
-  }
-  return @{@"code" : @(error.code), @"domain" : error.domain ?: @"", @"userInfo" : userInfo};
-}
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPReceiptManager.h b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPReceiptManager.h
deleted file mode 100644
index 94020ff..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPReceiptManager.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@class FlutterError;
-
-@interface FIAPReceiptManager : NSObject
-
-- (nullable NSString *)retrieveReceiptWithError:(FlutterError *_Nullable *_Nullable)error;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPReceiptManager.m b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPReceiptManager.m
deleted file mode 100644
index 5263640..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPReceiptManager.m
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "FIAPReceiptManager.h"
-#import <Flutter/Flutter.h>
-
-@implementation FIAPReceiptManager
-
-- (NSString *)retrieveReceiptWithError:(FlutterError **)error {
-  NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
-  NSData *receipt = [self getReceiptData:receiptURL];
-  if (!receipt) {
-    *error = [FlutterError errorWithCode:@"storekit_no_receipt"
-                                 message:@"Cannot find receipt for the current main bundle."
-                                 details:nil];
-    return nil;
-  }
-  return [receipt base64EncodedStringWithOptions:kNilOptions];
-}
-
-- (NSData *)getReceiptData:(NSURL *)url {
-  return [NSData dataWithContentsOfURL:url];
-}
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPRequestHandler.h b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPRequestHandler.h
deleted file mode 100644
index cbf21d6..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPRequestHandler.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Foundation/Foundation.h>
-#import <StoreKit/StoreKit.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-typedef void (^ProductRequestCompletion)(SKProductsResponse *_Nullable response,
-                                         NSError *_Nullable errror);
-
-@interface FIAPRequestHandler : NSObject
-
-- (instancetype)initWithRequest:(SKRequest *)request;
-- (void)startProductRequestWithCompletionHandler:(ProductRequestCompletion)completion;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPRequestHandler.m b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPRequestHandler.m
deleted file mode 100644
index 8767265..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPRequestHandler.m
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "FIAPRequestHandler.h"
-#import <StoreKit/StoreKit.h>
-
-#pragma mark - Main Handler
-
-@interface FIAPRequestHandler () <SKProductsRequestDelegate>
-
-@property(copy, nonatomic) ProductRequestCompletion completion;
-@property(strong, nonatomic) SKRequest *request;
-
-@end
-
-@implementation FIAPRequestHandler
-
-- (instancetype)initWithRequest:(SKRequest *)request {
-  self = [super init];
-  if (self) {
-    self.request = request;
-    request.delegate = self;
-  }
-  return self;
-}
-
-- (void)startProductRequestWithCompletionHandler:(ProductRequestCompletion)completion {
-  self.completion = completion;
-  [self.request start];
-}
-
-- (void)productsRequest:(SKProductsRequest *)request
-     didReceiveResponse:(SKProductsResponse *)response {
-  if (self.completion) {
-    self.completion(response, nil);
-    // set the completion to nil here so self.completion won't be triggered again in
-    // requestDidFinish for SKProductRequest.
-    self.completion = nil;
-  }
-}
-
-- (void)requestDidFinish:(SKRequest *)request {
-  if (self.completion) {
-    self.completion(nil, nil);
-  }
-}
-
-- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
-  if (self.completion) {
-    self.completion(nil, error);
-  }
-}
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h
deleted file mode 100644
index fddeb07..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Foundation/Foundation.h>
-#import <StoreKit/StoreKit.h>
-
-@class SKPaymentTransaction;
-
-NS_ASSUME_NONNULL_BEGIN
-
-typedef void (^TransactionsUpdated)(NSArray<SKPaymentTransaction *> *transactions);
-typedef void (^TransactionsRemoved)(NSArray<SKPaymentTransaction *> *transactions);
-typedef void (^RestoreTransactionFailed)(NSError *error);
-typedef void (^RestoreCompletedTransactionsFinished)(void);
-typedef BOOL (^ShouldAddStorePayment)(SKPayment *payment, SKProduct *product);
-typedef void (^UpdatedDownloads)(NSArray<SKDownload *> *downloads);
-
-@interface FIAPaymentQueueHandler : NSObject <SKPaymentTransactionObserver>
-
-- (instancetype)initWithQueue:(nonnull SKPaymentQueue *)queue
-                     transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated
-                      transactionRemoved:(nullable TransactionsRemoved)transactionsRemoved
-                restoreTransactionFailed:(nullable RestoreTransactionFailed)restoreTransactionFailed
-    restoreCompletedTransactionsFinished:
-        (nullable RestoreCompletedTransactionsFinished)restoreCompletedTransactionsFinished
-                   shouldAddStorePayment:(nullable ShouldAddStorePayment)shouldAddStorePayment
-                        updatedDownloads:(nullable UpdatedDownloads)updatedDownloads;
-// Can throw exceptions if the transaction type is purchasing, should always used in a @try block.
-- (void)finishTransaction:(nonnull SKPaymentTransaction *)transaction;
-- (void)restoreTransactions:(nullable NSString *)applicationName;
-- (void)presentCodeRedemptionSheet;
-- (NSArray<SKPaymentTransaction *> *)getUnfinishedTransactions;
-
-// This method needs to be called before any other methods.
-- (void)startObservingPaymentQueue;
-
-// Appends a payment to the SKPaymentQueue.
-//
-// @param payment Payment object to be added to the payment queue.
-// @return whether "addPayment" was successful.
-- (BOOL)addPayment:(SKPayment *)payment;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m b/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m
deleted file mode 100644
index eb3348e..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "FIAPaymentQueueHandler.h"
-
-@interface FIAPaymentQueueHandler ()
-
-@property(strong, nonatomic) SKPaymentQueue *queue;
-@property(nullable, copy, nonatomic) TransactionsUpdated transactionsUpdated;
-@property(nullable, copy, nonatomic) TransactionsRemoved transactionsRemoved;
-@property(nullable, copy, nonatomic) RestoreTransactionFailed restoreTransactionFailed;
-@property(nullable, copy, nonatomic)
-    RestoreCompletedTransactionsFinished paymentQueueRestoreCompletedTransactionsFinished;
-@property(nullable, copy, nonatomic) ShouldAddStorePayment shouldAddStorePayment;
-@property(nullable, copy, nonatomic) UpdatedDownloads updatedDownloads;
-
-@end
-
-@implementation FIAPaymentQueueHandler
-
-- (instancetype)initWithQueue:(nonnull SKPaymentQueue *)queue
-                     transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated
-                      transactionRemoved:(nullable TransactionsRemoved)transactionsRemoved
-                restoreTransactionFailed:(nullable RestoreTransactionFailed)restoreTransactionFailed
-    restoreCompletedTransactionsFinished:
-        (nullable RestoreCompletedTransactionsFinished)restoreCompletedTransactionsFinished
-                   shouldAddStorePayment:(nullable ShouldAddStorePayment)shouldAddStorePayment
-                        updatedDownloads:(nullable UpdatedDownloads)updatedDownloads {
-  self = [super init];
-  if (self) {
-    _queue = queue;
-    _transactionsUpdated = transactionsUpdated;
-    _transactionsRemoved = transactionsRemoved;
-    _restoreTransactionFailed = restoreTransactionFailed;
-    _paymentQueueRestoreCompletedTransactionsFinished = restoreCompletedTransactionsFinished;
-    _shouldAddStorePayment = shouldAddStorePayment;
-    _updatedDownloads = updatedDownloads;
-  }
-  return self;
-}
-
-- (void)startObservingPaymentQueue {
-  [_queue addTransactionObserver:self];
-}
-
-- (BOOL)addPayment:(SKPayment *)payment {
-  for (SKPaymentTransaction *transaction in self.queue.transactions) {
-    if ([transaction.payment.productIdentifier isEqualToString:payment.productIdentifier]) {
-      return NO;
-    }
-  }
-  [self.queue addPayment:payment];
-  return YES;
-}
-
-- (void)finishTransaction:(SKPaymentTransaction *)transaction {
-  [self.queue finishTransaction:transaction];
-}
-
-- (void)restoreTransactions:(nullable NSString *)applicationName {
-  if (applicationName) {
-    [self.queue restoreCompletedTransactionsWithApplicationUsername:applicationName];
-  } else {
-    [self.queue restoreCompletedTransactions];
-  }
-}
-
-- (void)presentCodeRedemptionSheet {
-  if (@available(iOS 14, *)) {
-    [self.queue presentCodeRedemptionSheet];
-  } else {
-    NSLog(@"presentCodeRedemptionSheet is only available on iOS 14 or newer");
-  }
-}
-
-#pragma mark - observing
-
-// Sent when the transaction array has changed (additions or state changes).  Client should check
-// state of transactions and finish as appropriate.
-- (void)paymentQueue:(SKPaymentQueue *)queue
-    updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
-  // notify dart through callbacks.
-  self.transactionsUpdated(transactions);
-}
-
-// Sent when transactions are removed from the queue (via finishTransaction:).
-- (void)paymentQueue:(SKPaymentQueue *)queue
-    removedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
-  self.transactionsRemoved(transactions);
-}
-
-// Sent when an error is encountered while adding transactions from the user's purchase history back
-// to the queue.
-- (void)paymentQueue:(SKPaymentQueue *)queue
-    restoreCompletedTransactionsFailedWithError:(NSError *)error {
-  self.restoreTransactionFailed(error);
-}
-
-// Sent when all transactions from the user's purchase history have successfully been added back to
-// the queue.
-- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
-  self.paymentQueueRestoreCompletedTransactionsFinished();
-}
-
-// Sent when the download state has changed.
-- (void)paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray<SKDownload *> *)downloads {
-  self.updatedDownloads(downloads);
-}
-
-// Sent when a user initiates an IAP buy from the App Store
-- (BOOL)paymentQueue:(SKPaymentQueue *)queue
-    shouldAddStorePayment:(SKPayment *)payment
-               forProduct:(SKProduct *)product {
-  return (self.shouldAddStorePayment(payment, product));
-}
-
-- (NSArray<SKPaymentTransaction *> *)getUnfinishedTransactions {
-  return self.queue.transactions;
-}
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Classes/InAppPurchasePlugin.h b/packages/in_app_purchase/in_app_purchase/ios/Classes/InAppPurchasePlugin.h
deleted file mode 100644
index 8cb42f3..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Classes/InAppPurchasePlugin.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Flutter/Flutter.h>
-@class FIAPaymentQueueHandler;
-@class FIAPReceiptManager;
-
-@interface InAppPurchasePlugin : NSObject <FlutterPlugin>
-
-@property(strong, nonatomic) FIAPaymentQueueHandler *paymentQueueHandler;
-
-- (instancetype)initWithReceiptManager:(FIAPReceiptManager *)receiptManager
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)init NS_UNAVAILABLE;
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Classes/InAppPurchasePlugin.m b/packages/in_app_purchase/in_app_purchase/ios/Classes/InAppPurchasePlugin.m
deleted file mode 100644
index 650cd81..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Classes/InAppPurchasePlugin.m
+++ /dev/null
@@ -1,360 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "InAppPurchasePlugin.h"
-#import <StoreKit/StoreKit.h>
-#import "FIAObjectTranslator.h"
-#import "FIAPReceiptManager.h"
-#import "FIAPRequestHandler.h"
-#import "FIAPaymentQueueHandler.h"
-
-@interface InAppPurchasePlugin ()
-
-// Holding strong references to FIAPRequestHandlers. Remove the handlers from the set after
-// the request is finished.
-@property(strong, nonatomic, readonly) NSMutableSet *requestHandlers;
-
-// After querying the product, the available products will be saved in the map to be used
-// for purchase.
-@property(strong, nonatomic, readonly) NSMutableDictionary *productsCache;
-
-// Call back channel to dart used for when a listener function is triggered.
-@property(strong, nonatomic, readonly) FlutterMethodChannel *callbackChannel;
-@property(strong, nonatomic, readonly) NSObject<FlutterTextureRegistry> *registry;
-@property(strong, nonatomic, readonly) NSObject<FlutterBinaryMessenger> *messenger;
-@property(strong, nonatomic, readonly) NSObject<FlutterPluginRegistrar> *registrar;
-
-@property(strong, nonatomic, readonly) FIAPReceiptManager *receiptManager;
-
-@end
-
-@implementation InAppPurchasePlugin
-
-+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
-  FlutterMethodChannel *channel =
-      [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/in_app_purchase"
-                                  binaryMessenger:[registrar messenger]];
-  InAppPurchasePlugin *instance = [[InAppPurchasePlugin alloc] initWithRegistrar:registrar];
-  [registrar addMethodCallDelegate:instance channel:channel];
-}
-
-- (instancetype)initWithReceiptManager:(FIAPReceiptManager *)receiptManager {
-  self = [super init];
-  _receiptManager = receiptManager;
-  _requestHandlers = [NSMutableSet new];
-  _productsCache = [NSMutableDictionary new];
-  return self;
-}
-
-- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
-  self = [self initWithReceiptManager:[FIAPReceiptManager new]];
-  _registrar = registrar;
-  _registry = [registrar textures];
-  _messenger = [registrar messenger];
-
-  __weak typeof(self) weakSelf = self;
-  _paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:[SKPaymentQueue defaultQueue]
-      transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
-        [weakSelf handleTransactionsUpdated:transactions];
-      }
-      transactionRemoved:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
-        [weakSelf handleTransactionsRemoved:transactions];
-      }
-      restoreTransactionFailed:^(NSError *_Nonnull error) {
-        [weakSelf handleTransactionRestoreFailed:error];
-      }
-      restoreCompletedTransactionsFinished:^{
-        [weakSelf restoreCompletedTransactionsFinished];
-      }
-      shouldAddStorePayment:^BOOL(SKPayment *payment, SKProduct *product) {
-        return [weakSelf shouldAddStorePayment:payment product:product];
-      }
-      updatedDownloads:^void(NSArray<SKDownload *> *_Nonnull downloads) {
-        [weakSelf updatedDownloads:downloads];
-      }];
-  [_paymentQueueHandler startObservingPaymentQueue];
-  _callbackChannel =
-      [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/in_app_purchase"
-                                  binaryMessenger:[registrar messenger]];
-  return self;
-}
-
-- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
-  if ([@"-[SKPaymentQueue canMakePayments:]" isEqualToString:call.method]) {
-    [self canMakePayments:result];
-  } else if ([@"-[SKPaymentQueue transactions]" isEqualToString:call.method]) {
-    [self getPendingTransactions:result];
-  } else if ([@"-[InAppPurchasePlugin startProductRequest:result:]" isEqualToString:call.method]) {
-    [self handleProductRequestMethodCall:call result:result];
-  } else if ([@"-[InAppPurchasePlugin addPayment:result:]" isEqualToString:call.method]) {
-    [self addPayment:call result:result];
-  } else if ([@"-[InAppPurchasePlugin finishTransaction:result:]" isEqualToString:call.method]) {
-    [self finishTransaction:call result:result];
-  } else if ([@"-[InAppPurchasePlugin restoreTransactions:result:]" isEqualToString:call.method]) {
-    [self restoreTransactions:call result:result];
-  } else if ([@"-[InAppPurchasePlugin presentCodeRedemptionSheet:result:]"
-                 isEqualToString:call.method]) {
-    [self presentCodeRedemptionSheet:call result:result];
-  } else if ([@"-[InAppPurchasePlugin retrieveReceiptData:result:]" isEqualToString:call.method]) {
-    [self retrieveReceiptData:call result:result];
-  } else if ([@"-[InAppPurchasePlugin refreshReceipt:result:]" isEqualToString:call.method]) {
-    [self refreshReceipt:call result:result];
-  } else {
-    result(FlutterMethodNotImplemented);
-  }
-}
-
-- (void)canMakePayments:(FlutterResult)result {
-  result([NSNumber numberWithBool:[SKPaymentQueue canMakePayments]]);
-}
-
-- (void)getPendingTransactions:(FlutterResult)result {
-  NSArray<SKPaymentTransaction *> *transactions =
-      [self.paymentQueueHandler getUnfinishedTransactions];
-  NSMutableArray *transactionMaps = [[NSMutableArray alloc] init];
-  for (SKPaymentTransaction *transaction in transactions) {
-    [transactionMaps addObject:[FIAObjectTranslator getMapFromSKPaymentTransaction:transaction]];
-  }
-  result(transactionMaps);
-}
-
-- (void)handleProductRequestMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
-  if (![call.arguments isKindOfClass:[NSArray class]]) {
-    result([FlutterError errorWithCode:@"storekit_invalid_argument"
-                               message:@"Argument type of startRequest is not array"
-                               details:call.arguments]);
-    return;
-  }
-  NSArray *productIdentifiers = (NSArray *)call.arguments;
-  SKProductsRequest *request =
-      [self getProductRequestWithIdentifiers:[NSSet setWithArray:productIdentifiers]];
-  FIAPRequestHandler *handler = [[FIAPRequestHandler alloc] initWithRequest:request];
-  [self.requestHandlers addObject:handler];
-  __weak typeof(self) weakSelf = self;
-  [handler startProductRequestWithCompletionHandler:^(SKProductsResponse *_Nullable response,
-                                                      NSError *_Nullable error) {
-    if (error) {
-      result([FlutterError errorWithCode:@"storekit_getproductrequest_platform_error"
-                                 message:error.localizedDescription
-                                 details:error.description]);
-      return;
-    }
-    if (!response) {
-      result([FlutterError errorWithCode:@"storekit_platform_no_response"
-                                 message:@"Failed to get SKProductResponse in startRequest "
-                                         @"call. Error occured on iOS platform"
-                                 details:call.arguments]);
-      return;
-    }
-    for (SKProduct *product in response.products) {
-      [self.productsCache setObject:product forKey:product.productIdentifier];
-    }
-    result([FIAObjectTranslator getMapFromSKProductsResponse:response]);
-    [weakSelf.requestHandlers removeObject:handler];
-  }];
-}
-
-- (void)addPayment:(FlutterMethodCall *)call result:(FlutterResult)result {
-  if (![call.arguments isKindOfClass:[NSDictionary class]]) {
-    result([FlutterError errorWithCode:@"storekit_invalid_argument"
-                               message:@"Argument type of addPayment is not a Dictionary"
-                               details:call.arguments]);
-    return;
-  }
-  NSDictionary *paymentMap = (NSDictionary *)call.arguments;
-  NSString *productID = [paymentMap objectForKey:@"productIdentifier"];
-  // When a product is already fetched, we create a payment object with
-  // the product to process the payment.
-  SKProduct *product = [self getProduct:productID];
-  if (!product) {
-    result([FlutterError
-        errorWithCode:@"storekit_invalid_payment_object"
-              message:
-                  @"You have requested a payment for an invalid product. Either the "
-                  @"`productIdentifier` of the payment is not valid or the product has not been "
-                  @"fetched before adding the payment to the payment queue."
-              details:call.arguments]);
-    return;
-  }
-  SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
-  payment.applicationUsername = [paymentMap objectForKey:@"applicationUsername"];
-  NSNumber *quantity = [paymentMap objectForKey:@"quantity"];
-  payment.quantity = (quantity != nil) ? quantity.integerValue : 1;
-  if (@available(iOS 8.3, *)) {
-    NSNumber *simulatesAskToBuyInSandbox = [paymentMap objectForKey:@"simulatesAskToBuyInSandbox"];
-    payment.simulatesAskToBuyInSandbox = (id)simulatesAskToBuyInSandbox == (id)[NSNull null]
-                                             ? NO
-                                             : [simulatesAskToBuyInSandbox boolValue];
-  }
-
-  if (![self.paymentQueueHandler addPayment:payment]) {
-    result([FlutterError
-        errorWithCode:@"storekit_duplicate_product_object"
-              message:@"There is a pending transaction for the same product identifier. Please "
-                      @"either wait for it to be finished or finish it manually using "
-                      @"`completePurchase` to avoid edge cases."
-
-              details:call.arguments]);
-    return;
-  }
-  result(nil);
-}
-
-- (void)finishTransaction:(FlutterMethodCall *)call result:(FlutterResult)result {
-  if (![call.arguments isKindOfClass:[NSDictionary class]]) {
-    result([FlutterError errorWithCode:@"storekit_invalid_argument"
-                               message:@"Argument type of finishTransaction is not a Dictionary"
-                               details:call.arguments]);
-    return;
-  }
-  NSDictionary *paymentMap = (NSDictionary *)call.arguments;
-  NSString *transactionIdentifier = [paymentMap objectForKey:@"transactionIdentifier"];
-  NSString *productIdentifier = [paymentMap objectForKey:@"productIdentifier"];
-
-  NSArray<SKPaymentTransaction *> *pendingTransactions =
-      [self.paymentQueueHandler getUnfinishedTransactions];
-
-  for (SKPaymentTransaction *transaction in pendingTransactions) {
-    // If the user cancels the purchase dialog we won't have a transactionIdentifier.
-    // So if it is null AND a transaction in the pendingTransactions list has
-    // also a null transactionIdentifier we check for equal product identifiers.
-    if ([transaction.transactionIdentifier isEqualToString:transactionIdentifier] ||
-        ([transactionIdentifier isEqual:[NSNull null]] &&
-         transaction.transactionIdentifier == nil &&
-         [transaction.payment.productIdentifier isEqualToString:productIdentifier])) {
-      @try {
-        [self.paymentQueueHandler finishTransaction:transaction];
-      } @catch (NSException *e) {
-        result([FlutterError errorWithCode:@"storekit_finish_transaction_exception"
-                                   message:e.name
-                                   details:e.description]);
-        return;
-      }
-    }
-  }
-
-  result(nil);
-}
-
-- (void)restoreTransactions:(FlutterMethodCall *)call result:(FlutterResult)result {
-  if (call.arguments && ![call.arguments isKindOfClass:[NSString class]]) {
-    result([FlutterError
-        errorWithCode:@"storekit_invalid_argument"
-              message:@"Argument is not nil and the type of finishTransaction is not a string."
-              details:call.arguments]);
-    return;
-  }
-  [self.paymentQueueHandler restoreTransactions:call.arguments];
-  result(nil);
-}
-
-- (void)presentCodeRedemptionSheet:(FlutterMethodCall *)call result:(FlutterResult)result {
-  [self.paymentQueueHandler presentCodeRedemptionSheet];
-  result(nil);
-}
-
-- (void)retrieveReceiptData:(FlutterMethodCall *)call result:(FlutterResult)result {
-  FlutterError *error = nil;
-  NSString *receiptData = [self.receiptManager retrieveReceiptWithError:&error];
-  if (error) {
-    result(error);
-    return;
-  }
-  result(receiptData);
-}
-
-- (void)refreshReceipt:(FlutterMethodCall *)call result:(FlutterResult)result {
-  NSDictionary *arguments = call.arguments;
-  SKReceiptRefreshRequest *request;
-  if (arguments) {
-    if (![arguments isKindOfClass:[NSDictionary class]]) {
-      result([FlutterError errorWithCode:@"storekit_invalid_argument"
-                                 message:@"Argument type of startRequest is not array"
-                                 details:call.arguments]);
-      return;
-    }
-    NSMutableDictionary *properties = [NSMutableDictionary new];
-    properties[SKReceiptPropertyIsExpired] = arguments[@"isExpired"];
-    properties[SKReceiptPropertyIsRevoked] = arguments[@"isRevoked"];
-    properties[SKReceiptPropertyIsVolumePurchase] = arguments[@"isVolumePurchase"];
-    request = [self getRefreshReceiptRequest:properties];
-  } else {
-    request = [self getRefreshReceiptRequest:nil];
-  }
-  FIAPRequestHandler *handler = [[FIAPRequestHandler alloc] initWithRequest:request];
-  [self.requestHandlers addObject:handler];
-  __weak typeof(self) weakSelf = self;
-  [handler startProductRequestWithCompletionHandler:^(SKProductsResponse *_Nullable response,
-                                                      NSError *_Nullable error) {
-    if (error) {
-      result([FlutterError errorWithCode:@"storekit_refreshreceiptrequest_platform_error"
-                                 message:error.localizedDescription
-                                 details:error.description]);
-      return;
-    }
-    result(nil);
-    [weakSelf.requestHandlers removeObject:handler];
-  }];
-}
-
-#pragma mark - delegates:
-
-- (void)handleTransactionsUpdated:(NSArray<SKPaymentTransaction *> *)transactions {
-  NSMutableArray *maps = [NSMutableArray new];
-  for (SKPaymentTransaction *transaction in transactions) {
-    [maps addObject:[FIAObjectTranslator getMapFromSKPaymentTransaction:transaction]];
-  }
-  [self.callbackChannel invokeMethod:@"updatedTransactions" arguments:maps];
-}
-
-- (void)handleTransactionsRemoved:(NSArray<SKPaymentTransaction *> *)transactions {
-  NSMutableArray *maps = [NSMutableArray new];
-  for (SKPaymentTransaction *transaction in transactions) {
-    [maps addObject:[FIAObjectTranslator getMapFromSKPaymentTransaction:transaction]];
-  }
-  [self.callbackChannel invokeMethod:@"removedTransactions" arguments:maps];
-}
-
-- (void)handleTransactionRestoreFailed:(NSError *)error {
-  [self.callbackChannel invokeMethod:@"restoreCompletedTransactionsFailed"
-                           arguments:[FIAObjectTranslator getMapFromNSError:error]];
-}
-
-- (void)restoreCompletedTransactionsFinished {
-  [self.callbackChannel invokeMethod:@"paymentQueueRestoreCompletedTransactionsFinished"
-                           arguments:nil];
-}
-
-- (void)updatedDownloads:(NSArray<SKDownload *> *)downloads {
-  NSLog(@"Received an updatedDownloads callback, but downloads are not supported.");
-}
-
-- (BOOL)shouldAddStorePayment:(SKPayment *)payment product:(SKProduct *)product {
-  // We always return NO here. And we send the message to dart to process the payment; and we will
-  // have a interception method that deciding if the payment should be processed (implemented by the
-  // programmer).
-  [self.productsCache setObject:product forKey:product.productIdentifier];
-  [self.callbackChannel invokeMethod:@"shouldAddStorePayment"
-                           arguments:@{
-                             @"payment" : [FIAObjectTranslator getMapFromSKPayment:payment],
-                             @"product" : [FIAObjectTranslator getMapFromSKProduct:product]
-                           }];
-  return NO;
-}
-
-#pragma mark - dependency injection (for unit testing)
-
-- (SKProductsRequest *)getProductRequestWithIdentifiers:(NSSet *)identifiers {
-  return [[SKProductsRequest alloc] initWithProductIdentifiers:identifiers];
-}
-
-- (SKProduct *)getProduct:(NSString *)productID {
-  return [self.productsCache objectForKey:productID];
-}
-
-- (SKReceiptRefreshRequest *)getRefreshReceiptRequest:(NSDictionary *)properties {
-  return [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:properties];
-}
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m b/packages/in_app_purchase/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m
deleted file mode 100644
index cb00cbc..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <OCMock/OCMock.h>
-#import <XCTest/XCTest.h>
-#import "FIAPaymentQueueHandler.h"
-#import "Stubs.h"
-
-@import in_app_purchase;
-
-@interface InAppPurchasePluginTest : XCTestCase
-
-@property(strong, nonatomic) InAppPurchasePlugin* plugin;
-
-@end
-
-@implementation InAppPurchasePluginTest
-
-- (void)setUp {
-  self.plugin =
-      [[InAppPurchasePluginStub alloc] initWithReceiptManager:[FIAPReceiptManagerStub new]];
-}
-
-- (void)tearDown {
-}
-
-- (void)testInvalidMethodCall {
-  XCTestExpectation* expectation =
-      [self expectationWithDescription:@"expect result to be not implemented"];
-  FlutterMethodCall* call = [FlutterMethodCall methodCallWithMethodName:@"invalid" arguments:NULL];
-  __block id result;
-  [self.plugin handleMethodCall:call
-                         result:^(id r) {
-                           [expectation fulfill];
-                           result = r;
-                         }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertEqual(result, FlutterMethodNotImplemented);
-}
-
-- (void)testCanMakePayments {
-  XCTestExpectation* expectation = [self expectationWithDescription:@"expect result to be YES"];
-  FlutterMethodCall* call =
-      [FlutterMethodCall methodCallWithMethodName:@"-[SKPaymentQueue canMakePayments:]"
-                                        arguments:NULL];
-  __block id result;
-  [self.plugin handleMethodCall:call
-                         result:^(id r) {
-                           [expectation fulfill];
-                           result = r;
-                         }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertEqual(result, [NSNumber numberWithBool:YES]);
-}
-
-- (void)testGetProductResponse {
-  XCTestExpectation* expectation =
-      [self expectationWithDescription:@"expect response contains 1 item"];
-  FlutterMethodCall* call = [FlutterMethodCall
-      methodCallWithMethodName:@"-[InAppPurchasePlugin startProductRequest:result:]"
-                     arguments:@[ @"123" ]];
-  __block id result;
-  [self.plugin handleMethodCall:call
-                         result:^(id r) {
-                           [expectation fulfill];
-                           result = r;
-                         }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssert([result isKindOfClass:[NSDictionary class]]);
-  NSArray* resultArray = [result objectForKey:@"products"];
-  XCTAssertEqual(resultArray.count, 1);
-  XCTAssertTrue([resultArray.firstObject[@"productIdentifier"] isEqualToString:@"123"]);
-}
-
-- (void)testAddPaymentFailure {
-  XCTestExpectation* expectation =
-      [self expectationWithDescription:@"result should return failed state"];
-  FlutterMethodCall* call =
-      [FlutterMethodCall methodCallWithMethodName:@"-[InAppPurchasePlugin addPayment:result:]"
-                                        arguments:@{
-                                          @"productIdentifier" : @"123",
-                                          @"quantity" : @(1),
-                                          @"simulatesAskToBuyInSandbox" : @YES,
-                                        }];
-  SKPaymentQueueStub* queue = [SKPaymentQueueStub new];
-  queue.testState = SKPaymentTransactionStateFailed;
-  __block SKPaymentTransaction* transactionForUpdateBlock;
-  self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
-      transactionsUpdated:^(NSArray<SKPaymentTransaction*>* _Nonnull transactions) {
-        SKPaymentTransaction* transaction = transactions[0];
-        if (transaction.transactionState == SKPaymentTransactionStateFailed) {
-          transactionForUpdateBlock = transaction;
-          [expectation fulfill];
-        }
-      }
-      transactionRemoved:nil
-      restoreTransactionFailed:nil
-      restoreCompletedTransactionsFinished:nil
-      shouldAddStorePayment:^BOOL(SKPayment* _Nonnull payment, SKProduct* _Nonnull product) {
-        return YES;
-      }
-      updatedDownloads:nil];
-  [queue addTransactionObserver:self.plugin.paymentQueueHandler];
-
-  [self.plugin handleMethodCall:call
-                         result:^(id r){
-                         }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertEqual(transactionForUpdateBlock.transactionState, SKPaymentTransactionStateFailed);
-}
-
-- (void)testAddPaymentSuccessWithMockQueue {
-  XCTestExpectation* expectation =
-      [self expectationWithDescription:@"result should return success state"];
-  FlutterMethodCall* call =
-      [FlutterMethodCall methodCallWithMethodName:@"-[InAppPurchasePlugin addPayment:result:]"
-                                        arguments:@{
-                                          @"productIdentifier" : @"123",
-                                          @"quantity" : @(1),
-                                          @"simulatesAskToBuyInSandbox" : @YES,
-                                        }];
-  SKPaymentQueueStub* queue = [SKPaymentQueueStub new];
-  queue.testState = SKPaymentTransactionStatePurchased;
-  __block SKPaymentTransaction* transactionForUpdateBlock;
-  self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
-      transactionsUpdated:^(NSArray<SKPaymentTransaction*>* _Nonnull transactions) {
-        SKPaymentTransaction* transaction = transactions[0];
-        if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
-          transactionForUpdateBlock = transaction;
-          [expectation fulfill];
-        }
-      }
-      transactionRemoved:nil
-      restoreTransactionFailed:nil
-      restoreCompletedTransactionsFinished:nil
-      shouldAddStorePayment:^BOOL(SKPayment* _Nonnull payment, SKProduct* _Nonnull product) {
-        return YES;
-      }
-      updatedDownloads:nil];
-  [queue addTransactionObserver:self.plugin.paymentQueueHandler];
-  [self.plugin handleMethodCall:call
-                         result:^(id r){
-                         }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertEqual(transactionForUpdateBlock.transactionState, SKPaymentTransactionStatePurchased);
-}
-
-- (void)testAddPaymentWithNullSandboxArgument {
-  XCTestExpectation* expectation =
-      [self expectationWithDescription:@"result should return success state"];
-  XCTestExpectation* simulatesAskToBuyInSandboxExpectation =
-      [self expectationWithDescription:@"payment isn't simulatesAskToBuyInSandbox"];
-  FlutterMethodCall* call =
-      [FlutterMethodCall methodCallWithMethodName:@"-[InAppPurchasePlugin addPayment:result:]"
-                                        arguments:@{
-                                          @"productIdentifier" : @"123",
-                                          @"quantity" : @(1),
-                                          @"simulatesAskToBuyInSandbox" : [NSNull null],
-                                        }];
-  SKPaymentQueueStub* queue = [SKPaymentQueueStub new];
-  queue.testState = SKPaymentTransactionStatePurchased;
-  __block SKPaymentTransaction* transactionForUpdateBlock;
-  self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
-      transactionsUpdated:^(NSArray<SKPaymentTransaction*>* _Nonnull transactions) {
-        SKPaymentTransaction* transaction = transactions[0];
-        if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
-          transactionForUpdateBlock = transaction;
-          [expectation fulfill];
-        }
-        if (@available(iOS 8.3, *)) {
-          if (!transaction.payment.simulatesAskToBuyInSandbox) {
-            [simulatesAskToBuyInSandboxExpectation fulfill];
-          }
-        } else {
-          [simulatesAskToBuyInSandboxExpectation fulfill];
-        }
-      }
-      transactionRemoved:nil
-      restoreTransactionFailed:nil
-      restoreCompletedTransactionsFinished:nil
-      shouldAddStorePayment:^BOOL(SKPayment* _Nonnull payment, SKProduct* _Nonnull product) {
-        return YES;
-      }
-      updatedDownloads:nil];
-  [queue addTransactionObserver:self.plugin.paymentQueueHandler];
-  [self.plugin handleMethodCall:call
-                         result:^(id r){
-                         }];
-  [self waitForExpectations:@[ expectation, simulatesAskToBuyInSandboxExpectation ] timeout:5];
-  XCTAssertEqual(transactionForUpdateBlock.transactionState, SKPaymentTransactionStatePurchased);
-}
-
-- (void)testRestoreTransactions {
-  XCTestExpectation* expectation =
-      [self expectationWithDescription:@"result successfully restore transactions"];
-  FlutterMethodCall* call = [FlutterMethodCall
-      methodCallWithMethodName:@"-[InAppPurchasePlugin restoreTransactions:result:]"
-                     arguments:nil];
-  SKPaymentQueueStub* queue = [SKPaymentQueueStub new];
-  queue.testState = SKPaymentTransactionStatePurchased;
-  __block BOOL callbackInvoked = NO;
-  self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
-      transactionsUpdated:^(NSArray<SKPaymentTransaction*>* _Nonnull transactions) {
-      }
-      transactionRemoved:nil
-      restoreTransactionFailed:nil
-      restoreCompletedTransactionsFinished:^() {
-        callbackInvoked = YES;
-        [expectation fulfill];
-      }
-      shouldAddStorePayment:nil
-      updatedDownloads:nil];
-  [queue addTransactionObserver:self.plugin.paymentQueueHandler];
-  [self.plugin handleMethodCall:call
-                         result:^(id r){
-                         }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertTrue(callbackInvoked);
-}
-
-- (void)testRetrieveReceiptData {
-  XCTestExpectation* expectation = [self expectationWithDescription:@"receipt data retrieved"];
-  FlutterMethodCall* call = [FlutterMethodCall
-      methodCallWithMethodName:@"-[InAppPurchasePlugin retrieveReceiptData:result:]"
-                     arguments:nil];
-  __block NSDictionary* result;
-  [self.plugin handleMethodCall:call
-                         result:^(id r) {
-                           result = r;
-                           [expectation fulfill];
-                         }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  NSLog(@"%@", result);
-  XCTAssertNotNil(result);
-}
-
-- (void)testRefreshReceiptRequest {
-  XCTestExpectation* expectation = [self expectationWithDescription:@"expect success"];
-  FlutterMethodCall* call =
-      [FlutterMethodCall methodCallWithMethodName:@"-[InAppPurchasePlugin refreshReceipt:result:]"
-                                        arguments:nil];
-  __block BOOL result = NO;
-  [self.plugin handleMethodCall:call
-                         result:^(id r) {
-                           result = YES;
-                           [expectation fulfill];
-                         }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertTrue(result);
-}
-
-- (void)testPresentCodeRedemptionSheet {
-  XCTestExpectation* expectation =
-      [self expectationWithDescription:@"expect successfully present Code Redemption Sheet"];
-  FlutterMethodCall* call = [FlutterMethodCall
-      methodCallWithMethodName:@"-[InAppPurchasePlugin presentCodeRedemptionSheet:result:]"
-                     arguments:nil];
-  __block BOOL callbackInvoked = NO;
-  [self.plugin handleMethodCall:call
-                         result:^(id r) {
-                           callbackInvoked = YES;
-                           [expectation fulfill];
-                         }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertTrue(callbackInvoked);
-}
-
-- (void)testGetPendingTransactions {
-  XCTestExpectation* expectation = [self expectationWithDescription:@"expect success"];
-  FlutterMethodCall* call =
-      [FlutterMethodCall methodCallWithMethodName:@"-[SKPaymentQueue transactions]" arguments:nil];
-  SKPaymentQueue* mockQueue = OCMClassMock(SKPaymentQueue.class);
-  NSDictionary* transactionMap = @{
-    @"transactionIdentifier" : [NSNull null],
-    @"transactionState" : @(SKPaymentTransactionStatePurchasing),
-    @"payment" : [NSNull null],
-    @"error" : [FIAObjectTranslator getMapFromNSError:[NSError errorWithDomain:@"test_stub"
-                                                                          code:123
-                                                                      userInfo:@{}]],
-    @"transactionTimeStamp" : @([NSDate date].timeIntervalSince1970),
-    @"originalTransaction" : [NSNull null],
-  };
-  OCMStub(mockQueue.transactions).andReturn(@[ [[SKPaymentTransactionStub alloc]
-      initWithMap:transactionMap] ]);
-
-  __block NSArray* resultArray;
-  self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:mockQueue
-                                                              transactionsUpdated:nil
-                                                               transactionRemoved:nil
-                                                         restoreTransactionFailed:nil
-                                             restoreCompletedTransactionsFinished:nil
-                                                            shouldAddStorePayment:nil
-                                                                 updatedDownloads:nil];
-  [self.plugin handleMethodCall:call
-                         result:^(id r) {
-                           resultArray = r;
-                           [expectation fulfill];
-                         }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertEqualObjects(resultArray, @[ transactionMap ]);
-}
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Tests/PaymentQueueTest.m b/packages/in_app_purchase/in_app_purchase/ios/Tests/PaymentQueueTest.m
deleted file mode 100644
index c335fa3..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Tests/PaymentQueueTest.m
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <XCTest/XCTest.h>
-#import "Stubs.h"
-
-@import in_app_purchase;
-
-@interface PaymentQueueTest : XCTestCase
-
-@property(strong, nonatomic) NSDictionary *periodMap;
-@property(strong, nonatomic) NSDictionary *discountMap;
-@property(strong, nonatomic) NSDictionary *productMap;
-@property(strong, nonatomic) NSDictionary *productResponseMap;
-
-@end
-
-@implementation PaymentQueueTest
-
-- (void)setUp {
-  self.periodMap = @{@"numberOfUnits" : @(0), @"unit" : @(0)};
-  self.discountMap = @{
-    @"price" : @1.0,
-    @"currencyCode" : @"USD",
-    @"numberOfPeriods" : @1,
-    @"subscriptionPeriod" : self.periodMap,
-    @"paymentMode" : @1
-  };
-  self.productMap = @{
-    @"price" : @1.0,
-    @"currencyCode" : @"USD",
-    @"productIdentifier" : @"123",
-    @"localizedTitle" : @"title",
-    @"localizedDescription" : @"des",
-    @"subscriptionPeriod" : self.periodMap,
-    @"introductoryPrice" : self.discountMap,
-    @"subscriptionGroupIdentifier" : @"com.group"
-  };
-  self.productResponseMap =
-      @{@"products" : @[ self.productMap ], @"invalidProductIdentifiers" : [NSNull null]};
-}
-
-- (void)testTransactionPurchased {
-  XCTestExpectation *expectation =
-      [self expectationWithDescription:@"expect to get purchased transcation."];
-  SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
-  queue.testState = SKPaymentTransactionStatePurchased;
-  __block SKPaymentTransactionStub *tran;
-  FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
-      transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
-        SKPaymentTransaction *transaction = transactions[0];
-        tran = (SKPaymentTransactionStub *)transaction;
-        [expectation fulfill];
-      }
-      transactionRemoved:nil
-      restoreTransactionFailed:nil
-      restoreCompletedTransactionsFinished:nil
-      shouldAddStorePayment:^BOOL(SKPayment *_Nonnull payment, SKProduct *_Nonnull product) {
-        return YES;
-      }
-      updatedDownloads:nil];
-  [queue addTransactionObserver:handler];
-  SKPayment *payment =
-      [SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
-  [handler addPayment:payment];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertEqual(tran.transactionState, SKPaymentTransactionStatePurchased);
-  XCTAssertEqual(tran.transactionIdentifier, @"fakeID");
-}
-
-- (void)testTransactionFailed {
-  XCTestExpectation *expectation =
-      [self expectationWithDescription:@"expect to get failed transcation."];
-  SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
-  queue.testState = SKPaymentTransactionStateFailed;
-  __block SKPaymentTransactionStub *tran;
-  FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
-      transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
-        SKPaymentTransaction *transaction = transactions[0];
-        tran = (SKPaymentTransactionStub *)transaction;
-        [expectation fulfill];
-      }
-      transactionRemoved:nil
-      restoreTransactionFailed:nil
-      restoreCompletedTransactionsFinished:nil
-      shouldAddStorePayment:^BOOL(SKPayment *_Nonnull payment, SKProduct *_Nonnull product) {
-        return YES;
-      }
-      updatedDownloads:nil];
-  [queue addTransactionObserver:handler];
-  SKPayment *payment =
-      [SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
-  [handler addPayment:payment];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertEqual(tran.transactionState, SKPaymentTransactionStateFailed);
-  XCTAssertEqual(tran.transactionIdentifier, nil);
-}
-
-- (void)testTransactionRestored {
-  XCTestExpectation *expectation =
-      [self expectationWithDescription:@"expect to get restored transcation."];
-  SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
-  queue.testState = SKPaymentTransactionStateRestored;
-  __block SKPaymentTransactionStub *tran;
-  FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
-      transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
-        SKPaymentTransaction *transaction = transactions[0];
-        tran = (SKPaymentTransactionStub *)transaction;
-        [expectation fulfill];
-      }
-      transactionRemoved:nil
-      restoreTransactionFailed:nil
-      restoreCompletedTransactionsFinished:nil
-      shouldAddStorePayment:^BOOL(SKPayment *_Nonnull payment, SKProduct *_Nonnull product) {
-        return YES;
-      }
-      updatedDownloads:nil];
-  [queue addTransactionObserver:handler];
-  SKPayment *payment =
-      [SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
-  [handler addPayment:payment];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertEqual(tran.transactionState, SKPaymentTransactionStateRestored);
-  XCTAssertEqual(tran.transactionIdentifier, @"fakeID");
-}
-
-- (void)testTransactionPurchasing {
-  XCTestExpectation *expectation =
-      [self expectationWithDescription:@"expect to get purchasing transcation."];
-  SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
-  queue.testState = SKPaymentTransactionStatePurchasing;
-  __block SKPaymentTransactionStub *tran;
-  FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
-      transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
-        SKPaymentTransaction *transaction = transactions[0];
-        tran = (SKPaymentTransactionStub *)transaction;
-        [expectation fulfill];
-      }
-      transactionRemoved:nil
-      restoreTransactionFailed:nil
-      restoreCompletedTransactionsFinished:nil
-      shouldAddStorePayment:^BOOL(SKPayment *_Nonnull payment, SKProduct *_Nonnull product) {
-        return YES;
-      }
-      updatedDownloads:nil];
-  [queue addTransactionObserver:handler];
-  SKPayment *payment =
-      [SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
-  [handler addPayment:payment];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertEqual(tran.transactionState, SKPaymentTransactionStatePurchasing);
-  XCTAssertEqual(tran.transactionIdentifier, nil);
-}
-
-- (void)testTransactionDeferred {
-  XCTestExpectation *expectation =
-      [self expectationWithDescription:@"expect to get deffered transcation."];
-  SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
-  queue.testState = SKPaymentTransactionStateDeferred;
-  __block SKPaymentTransactionStub *tran;
-  FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
-      transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
-        SKPaymentTransaction *transaction = transactions[0];
-        tran = (SKPaymentTransactionStub *)transaction;
-        [expectation fulfill];
-      }
-      transactionRemoved:nil
-      restoreTransactionFailed:nil
-      restoreCompletedTransactionsFinished:nil
-      shouldAddStorePayment:^BOOL(SKPayment *_Nonnull payment, SKProduct *_Nonnull product) {
-        return YES;
-      }
-      updatedDownloads:nil];
-  [queue addTransactionObserver:handler];
-  SKPayment *payment =
-      [SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
-  [handler addPayment:payment];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertEqual(tran.transactionState, SKPaymentTransactionStateDeferred);
-  XCTAssertEqual(tran.transactionIdentifier, nil);
-}
-
-- (void)testFinishTransaction {
-  XCTestExpectation *expectation =
-      [self expectationWithDescription:@"handler.transactions should be empty."];
-  SKPaymentQueueStub *queue = [[SKPaymentQueueStub alloc] init];
-  queue.testState = SKPaymentTransactionStateDeferred;
-  __block FIAPaymentQueueHandler *handler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue
-      transactionsUpdated:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
-        XCTAssertEqual(transactions.count, 1);
-        SKPaymentTransaction *transaction = transactions[0];
-        [handler finishTransaction:transaction];
-      }
-      transactionRemoved:^(NSArray<SKPaymentTransaction *> *_Nonnull transactions) {
-        XCTAssertEqual(transactions.count, 1);
-        [expectation fulfill];
-      }
-      restoreTransactionFailed:nil
-      restoreCompletedTransactionsFinished:nil
-      shouldAddStorePayment:^BOOL(SKPayment *_Nonnull payment, SKProduct *_Nonnull product) {
-        return YES;
-      }
-      updatedDownloads:nil];
-  [queue addTransactionObserver:handler];
-  SKPayment *payment =
-      [SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]];
-  [handler addPayment:payment];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-}
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m b/packages/in_app_purchase/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m
deleted file mode 100644
index 19f5848..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Tests/ProductRequestHandlerTest.m
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <XCTest/XCTest.h>
-#import "Stubs.h"
-
-@import in_app_purchase;
-
-#pragma tests start here
-
-@interface RequestHandlerTest : XCTestCase
-
-@end
-
-@implementation RequestHandlerTest
-
-- (void)testRequestHandlerWithProductRequestSuccess {
-  SKProductRequestStub *request =
-      [[SKProductRequestStub alloc] initWithProductIdentifiers:[NSSet setWithArray:@[ @"123" ]]];
-  FIAPRequestHandler *handler = [[FIAPRequestHandler alloc] initWithRequest:request];
-  XCTestExpectation *expectation =
-      [self expectationWithDescription:@"expect to get response with 1 product"];
-  __block SKProductsResponse *response;
-  [handler
-      startProductRequestWithCompletionHandler:^(SKProductsResponse *_Nullable r, NSError *error) {
-        response = r;
-        [expectation fulfill];
-      }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertNotNil(response);
-  XCTAssertEqual(response.products.count, 1);
-  SKProduct *product = response.products.firstObject;
-  XCTAssertTrue([product.productIdentifier isEqualToString:@"123"]);
-}
-
-- (void)testRequestHandlerWithProductRequestFailure {
-  SKProductRequestStub *request = [[SKProductRequestStub alloc]
-      initWithFailureError:[NSError errorWithDomain:@"test" code:123 userInfo:@{}]];
-  FIAPRequestHandler *handler = [[FIAPRequestHandler alloc] initWithRequest:request];
-  XCTestExpectation *expectation =
-      [self expectationWithDescription:@"expect to get response with 1 product"];
-  __block NSError *error;
-  __block SKProductsResponse *response;
-  [handler startProductRequestWithCompletionHandler:^(SKProductsResponse *_Nullable r, NSError *e) {
-    error = e;
-    response = r;
-    [expectation fulfill];
-  }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertNotNil(error);
-  XCTAssertEqual(error.domain, @"test");
-  XCTAssertNil(response);
-}
-
-- (void)testRequestHandlerWithRefreshReceiptSuccess {
-  SKReceiptRefreshRequestStub *request =
-      [[SKReceiptRefreshRequestStub alloc] initWithReceiptProperties:nil];
-  FIAPRequestHandler *handler = [[FIAPRequestHandler alloc] initWithRequest:request];
-  XCTestExpectation *expectation = [self expectationWithDescription:@"expect no error"];
-  __block NSError *e;
-  [handler
-      startProductRequestWithCompletionHandler:^(SKProductsResponse *_Nullable r, NSError *error) {
-        e = error;
-        [expectation fulfill];
-      }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertNil(e);
-}
-
-- (void)testRequestHandlerWithRefreshReceiptFailure {
-  SKReceiptRefreshRequestStub *request = [[SKReceiptRefreshRequestStub alloc]
-      initWithFailureError:[NSError errorWithDomain:@"test" code:123 userInfo:@{}]];
-  FIAPRequestHandler *handler = [[FIAPRequestHandler alloc] initWithRequest:request];
-  XCTestExpectation *expectation = [self expectationWithDescription:@"expect error"];
-  __block NSError *error;
-  __block SKProductsResponse *response;
-  [handler startProductRequestWithCompletionHandler:^(SKProductsResponse *_Nullable r, NSError *e) {
-    error = e;
-    response = r;
-    [expectation fulfill];
-  }];
-  [self waitForExpectations:@[ expectation ] timeout:5];
-  XCTAssertNotNil(error);
-  XCTAssertEqual(error.domain, @"test");
-  XCTAssertNil(response);
-}
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Tests/Stubs.h b/packages/in_app_purchase/in_app_purchase/ios/Tests/Stubs.h
deleted file mode 100644
index e07cc3f..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Tests/Stubs.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Foundation/Foundation.h>
-#import <StoreKit/StoreKit.h>
-
-@import in_app_purchase;
-
-NS_ASSUME_NONNULL_BEGIN
-API_AVAILABLE(ios(11.2), macos(10.13.2))
-@interface SKProductSubscriptionPeriodStub : SKProductSubscriptionPeriod
-- (instancetype)initWithMap:(NSDictionary *)map;
-@end
-
-API_AVAILABLE(ios(11.2), macos(10.13.2))
-@interface SKProductDiscountStub : SKProductDiscount
-- (instancetype)initWithMap:(NSDictionary *)map;
-@end
-
-@interface SKProductStub : SKProduct
-- (instancetype)initWithMap:(NSDictionary *)map;
-@end
-
-@interface SKProductRequestStub : SKProductsRequest
-- (instancetype)initWithProductIdentifiers:(NSSet<NSString *> *)productIdentifiers;
-- (instancetype)initWithFailureError:(NSError *)error;
-@end
-
-@interface SKProductsResponseStub : SKProductsResponse
-- (instancetype)initWithMap:(NSDictionary *)map;
-@end
-
-@interface InAppPurchasePluginStub : InAppPurchasePlugin
-@end
-
-@interface SKPaymentQueueStub : SKPaymentQueue
-@property(assign, nonatomic) SKPaymentTransactionState testState;
-@end
-
-@interface SKPaymentTransactionStub : SKPaymentTransaction
-- (instancetype)initWithMap:(NSDictionary *)map;
-- (instancetype)initWithState:(SKPaymentTransactionState)state;
-- (instancetype)initWithState:(SKPaymentTransactionState)state payment:(SKPayment *)payment;
-@end
-
-@interface SKMutablePaymentStub : SKMutablePayment
-- (instancetype)initWithMap:(NSDictionary *)map;
-@end
-
-@interface NSErrorStub : NSError
-- (instancetype)initWithMap:(NSDictionary *)map;
-@end
-
-@interface FIAPReceiptManagerStub : FIAPReceiptManager
-@end
-
-@interface SKReceiptRefreshRequestStub : SKReceiptRefreshRequest
-- (instancetype)initWithFailureError:(NSError *)error;
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Tests/Stubs.m b/packages/in_app_purchase/in_app_purchase/ios/Tests/Stubs.m
deleted file mode 100644
index 66610a8..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Tests/Stubs.m
+++ /dev/null
@@ -1,290 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "Stubs.h"
-
-@implementation SKProductSubscriptionPeriodStub
-
-- (instancetype)initWithMap:(NSDictionary *)map {
-  self = [super init];
-  if (self) {
-    [self setValue:map[@"numberOfUnits"] ?: @(0) forKey:@"numberOfUnits"];
-    [self setValue:map[@"unit"] ?: @(0) forKey:@"unit"];
-  }
-  return self;
-}
-
-@end
-
-@implementation SKProductDiscountStub
-
-- (instancetype)initWithMap:(NSDictionary *)map {
-  self = [super init];
-  if (self) {
-    [self setValue:[[NSDecimalNumber alloc] initWithString:map[@"price"]] ?: [NSNull null]
-            forKey:@"price"];
-    NSLocale *locale = NSLocale.systemLocale;
-    [self setValue:locale ?: [NSNull null] forKey:@"priceLocale"];
-    [self setValue:map[@"numberOfPeriods"] ?: @(0) forKey:@"numberOfPeriods"];
-    SKProductSubscriptionPeriodStub *subscriptionPeriodSub =
-        [[SKProductSubscriptionPeriodStub alloc] initWithMap:map[@"subscriptionPeriod"]];
-    [self setValue:subscriptionPeriodSub forKey:@"subscriptionPeriod"];
-    [self setValue:map[@"paymentMode"] ?: @(0) forKey:@"paymentMode"];
-  }
-  return self;
-}
-
-@end
-
-@implementation SKProductStub
-
-- (instancetype)initWithMap:(NSDictionary *)map {
-  self = [super init];
-  if (self) {
-    [self setValue:map[@"productIdentifier"] ?: [NSNull null] forKey:@"productIdentifier"];
-    [self setValue:map[@"localizedDescription"] ?: [NSNull null] forKey:@"localizedDescription"];
-    [self setValue:map[@"localizedTitle"] ?: [NSNull null] forKey:@"localizedTitle"];
-    [self setValue:map[@"downloadable"] ?: @NO forKey:@"downloadable"];
-    [self setValue:[[NSDecimalNumber alloc] initWithString:map[@"price"]] ?: [NSNull null]
-            forKey:@"price"];
-    NSLocale *locale = NSLocale.systemLocale;
-    [self setValue:locale ?: [NSNull null] forKey:@"priceLocale"];
-    [self setValue:map[@"downloadContentLengths"] ?: @(0) forKey:@"downloadContentLengths"];
-    if (@available(iOS 11.2, *)) {
-      SKProductSubscriptionPeriodStub *period =
-          [[SKProductSubscriptionPeriodStub alloc] initWithMap:map[@"subscriptionPeriod"]];
-      [self setValue:period ?: [NSNull null] forKey:@"subscriptionPeriod"];
-      SKProductDiscountStub *discount =
-          [[SKProductDiscountStub alloc] initWithMap:map[@"introductoryPrice"]];
-      [self setValue:discount ?: [NSNull null] forKey:@"introductoryPrice"];
-      [self setValue:map[@"subscriptionGroupIdentifier"] ?: [NSNull null]
-              forKey:@"subscriptionGroupIdentifier"];
-    }
-  }
-  return self;
-}
-
-- (instancetype)initWithProductID:(NSString *)productIdentifier {
-  self = [super init];
-  if (self) {
-    [self setValue:productIdentifier forKey:@"productIdentifier"];
-  }
-  return self;
-}
-
-@end
-
-@interface SKProductRequestStub ()
-
-@property(strong, nonatomic) NSSet *identifers;
-@property(strong, nonatomic) NSError *error;
-
-@end
-
-@implementation SKProductRequestStub
-
-- (instancetype)initWithProductIdentifiers:(NSSet<NSString *> *)productIdentifiers {
-  self = [super initWithProductIdentifiers:productIdentifiers];
-  self.identifers = productIdentifiers;
-  return self;
-}
-
-- (instancetype)initWithFailureError:(NSError *)error {
-  self = [super init];
-  self.error = error;
-  return self;
-}
-
-- (void)start {
-  NSMutableArray *productArray = [NSMutableArray new];
-  for (NSString *identifier in self.identifers) {
-    [productArray addObject:@{@"productIdentifier" : identifier}];
-  }
-  SKProductsResponseStub *response =
-      [[SKProductsResponseStub alloc] initWithMap:@{@"products" : productArray}];
-  if (self.error) {
-    [self.delegate request:self didFailWithError:self.error];
-  } else {
-    [self.delegate productsRequest:self didReceiveResponse:response];
-  }
-}
-
-@end
-
-@implementation SKProductsResponseStub
-
-- (instancetype)initWithMap:(NSDictionary *)map {
-  self = [super init];
-  if (self) {
-    NSMutableArray *products = [NSMutableArray new];
-    for (NSDictionary *productMap in map[@"products"]) {
-      SKProductStub *product = [[SKProductStub alloc] initWithMap:productMap];
-      [products addObject:product];
-    }
-    [self setValue:products forKey:@"products"];
-  }
-  return self;
-}
-
-@end
-
-@interface InAppPurchasePluginStub ()
-
-@end
-
-@implementation InAppPurchasePluginStub
-
-- (SKProductRequestStub *)getProductRequestWithIdentifiers:(NSSet *)identifiers {
-  return [[SKProductRequestStub alloc] initWithProductIdentifiers:identifiers];
-}
-
-- (SKProduct *)getProduct:(NSString *)productID {
-  return [[SKProductStub alloc] initWithProductID:productID];
-}
-
-- (SKReceiptRefreshRequestStub *)getRefreshReceiptRequest:(NSDictionary *)properties {
-  return [[SKReceiptRefreshRequestStub alloc] initWithReceiptProperties:properties];
-}
-
-@end
-
-@interface SKPaymentQueueStub ()
-
-@property(strong, nonatomic) id<SKPaymentTransactionObserver> observer;
-
-@end
-
-@implementation SKPaymentQueueStub
-
-- (void)addTransactionObserver:(id<SKPaymentTransactionObserver>)observer {
-  self.observer = observer;
-}
-
-- (void)addPayment:(SKPayment *)payment {
-  SKPaymentTransactionStub *transaction =
-      [[SKPaymentTransactionStub alloc] initWithState:self.testState payment:payment];
-  [self.observer paymentQueue:self updatedTransactions:@[ transaction ]];
-}
-
-- (void)restoreCompletedTransactions {
-  if ([self.observer
-          respondsToSelector:@selector(paymentQueueRestoreCompletedTransactionsFinished:)]) {
-    [self.observer paymentQueueRestoreCompletedTransactionsFinished:self];
-  }
-}
-
-- (void)finishTransaction:(SKPaymentTransaction *)transaction {
-  if ([self.observer respondsToSelector:@selector(paymentQueue:removedTransactions:)]) {
-    [self.observer paymentQueue:self removedTransactions:@[ transaction ]];
-  }
-}
-
-@end
-
-@implementation SKPaymentTransactionStub {
-  SKPayment *_payment;
-}
-
-- (instancetype)initWithID:(NSString *)identifier {
-  self = [super init];
-  if (self) {
-    [self setValue:identifier forKey:@"transactionIdentifier"];
-  }
-  return self;
-}
-
-- (instancetype)initWithMap:(NSDictionary *)map {
-  self = [super init];
-  if (self) {
-    [self setValue:map[@"transactionIdentifier"] forKey:@"transactionIdentifier"];
-    [self setValue:map[@"transactionState"] forKey:@"transactionState"];
-    if (![map[@"originalTransaction"] isKindOfClass:[NSNull class]] &&
-        map[@"originalTransaction"]) {
-      [self setValue:[[SKPaymentTransactionStub alloc] initWithMap:map[@"originalTransaction"]]
-              forKey:@"originalTransaction"];
-    }
-    [self setValue:map[@"error"] ? [[NSErrorStub alloc] initWithMap:map[@"error"]] : [NSNull null]
-            forKey:@"error"];
-    [self setValue:[NSDate dateWithTimeIntervalSince1970:[map[@"transactionTimeStamp"] doubleValue]]
-            forKey:@"transactionDate"];
-  }
-  return self;
-}
-
-- (instancetype)initWithState:(SKPaymentTransactionState)state {
-  self = [super init];
-  if (self) {
-    // Only purchased and restored transactions have transactionIdentifier:
-    // https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc
-    if (state == SKPaymentTransactionStatePurchased || state == SKPaymentTransactionStateRestored) {
-      [self setValue:@"fakeID" forKey:@"transactionIdentifier"];
-    }
-    [self setValue:@(state) forKey:@"transactionState"];
-  }
-  return self;
-}
-
-- (instancetype)initWithState:(SKPaymentTransactionState)state payment:(SKPayment *)payment {
-  self = [super init];
-  if (self) {
-    // Only purchased and restored transactions have transactionIdentifier:
-    // https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc
-    if (state == SKPaymentTransactionStatePurchased || state == SKPaymentTransactionStateRestored) {
-      [self setValue:@"fakeID" forKey:@"transactionIdentifier"];
-    }
-    [self setValue:@(state) forKey:@"transactionState"];
-    _payment = payment;
-  }
-  return self;
-}
-
-- (SKPayment *)payment {
-  return _payment;
-}
-
-@end
-
-@implementation NSErrorStub
-
-- (instancetype)initWithMap:(NSDictionary *)map {
-  return [self initWithDomain:[map objectForKey:@"domain"]
-                         code:[[map objectForKey:@"code"] integerValue]
-                     userInfo:[map objectForKey:@"userInfo"]];
-}
-
-@end
-
-@implementation FIAPReceiptManagerStub : FIAPReceiptManager
-
-- (NSData *)getReceiptData:(NSURL *)url {
-  NSString *originalString = [NSString stringWithFormat:@"test"];
-  return [[NSData alloc] initWithBase64EncodedString:originalString options:kNilOptions];
-}
-
-@end
-
-@implementation SKReceiptRefreshRequestStub {
-  NSError *_error;
-}
-
-- (instancetype)initWithReceiptProperties:(NSDictionary<NSString *, id> *)properties {
-  self = [super initWithReceiptProperties:properties];
-  return self;
-}
-
-- (instancetype)initWithFailureError:(NSError *)error {
-  self = [super init];
-  _error = error;
-  return self;
-}
-
-- (void)start {
-  if (_error) {
-    [self.delegate request:self didFailWithError:_error];
-  } else {
-    [self.delegate requestDidFinish:self];
-  }
-}
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/Tests/TranslatorTest.m b/packages/in_app_purchase/in_app_purchase/ios/Tests/TranslatorTest.m
deleted file mode 100644
index 550d1fc..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/Tests/TranslatorTest.m
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <XCTest/XCTest.h>
-#import "Stubs.h"
-
-@import in_app_purchase;
-
-@interface TranslatorTest : XCTestCase
-
-@property(strong, nonatomic) NSDictionary *periodMap;
-@property(strong, nonatomic) NSDictionary *discountMap;
-@property(strong, nonatomic) NSMutableDictionary *productMap;
-@property(strong, nonatomic) NSDictionary *productResponseMap;
-@property(strong, nonatomic) NSDictionary *paymentMap;
-@property(strong, nonatomic) NSDictionary *transactionMap;
-@property(strong, nonatomic) NSDictionary *errorMap;
-@property(strong, nonatomic) NSDictionary *localeMap;
-
-@end
-
-@implementation TranslatorTest
-
-- (void)setUp {
-  self.periodMap = @{@"numberOfUnits" : @(0), @"unit" : @(0)};
-  self.discountMap = @{
-    @"price" : @"1",
-    @"priceLocale" : [FIAObjectTranslator getMapFromNSLocale:NSLocale.systemLocale],
-    @"numberOfPeriods" : @1,
-    @"subscriptionPeriod" : self.periodMap,
-    @"paymentMode" : @1
-  };
-
-  self.productMap = [[NSMutableDictionary alloc] initWithDictionary:@{
-    @"price" : @"1",
-    @"priceLocale" : [FIAObjectTranslator getMapFromNSLocale:NSLocale.systemLocale],
-    @"productIdentifier" : @"123",
-    @"localizedTitle" : @"title",
-    @"localizedDescription" : @"des",
-  }];
-  if (@available(iOS 11.2, *)) {
-    self.productMap[@"subscriptionPeriod"] = self.periodMap;
-    self.productMap[@"introductoryPrice"] = self.discountMap;
-  }
-
-  if (@available(iOS 12.0, *)) {
-    self.productMap[@"subscriptionGroupIdentifier"] = @"com.group";
-  }
-
-  self.productResponseMap =
-      @{@"products" : @[ self.productMap ], @"invalidProductIdentifiers" : @[]};
-  self.paymentMap = @{
-    @"productIdentifier" : @"123",
-    @"requestData" : @"abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
-    @"quantity" : @(2),
-    @"applicationUsername" : @"app user name",
-    @"simulatesAskToBuyInSandbox" : @(NO)
-  };
-  NSDictionary *originalTransactionMap = @{
-    @"transactionIdentifier" : @"567",
-    @"transactionState" : @(SKPaymentTransactionStatePurchasing),
-    @"payment" : [NSNull null],
-    @"error" : [FIAObjectTranslator getMapFromNSError:[NSError errorWithDomain:@"test_stub"
-                                                                          code:123
-                                                                      userInfo:@{}]],
-    @"transactionTimeStamp" : @([NSDate date].timeIntervalSince1970),
-    @"originalTransaction" : [NSNull null],
-  };
-  self.transactionMap = @{
-    @"transactionIdentifier" : @"567",
-    @"transactionState" : @(SKPaymentTransactionStatePurchasing),
-    @"payment" : [NSNull null],
-    @"error" : [FIAObjectTranslator getMapFromNSError:[NSError errorWithDomain:@"test_stub"
-                                                                          code:123
-                                                                      userInfo:@{}]],
-    @"transactionTimeStamp" : @([NSDate date].timeIntervalSince1970),
-    @"originalTransaction" : originalTransactionMap,
-  };
-  self.errorMap = @{
-    @"code" : @(123),
-    @"domain" : @"test_domain",
-    @"userInfo" : @{
-      @"key" : @"value",
-    }
-  };
-}
-
-- (void)testSKProductSubscriptionPeriodStubToMap {
-  if (@available(iOS 11.2, *)) {
-    SKProductSubscriptionPeriodStub *period =
-        [[SKProductSubscriptionPeriodStub alloc] initWithMap:self.periodMap];
-    NSDictionary *map = [FIAObjectTranslator getMapFromSKProductSubscriptionPeriod:period];
-    XCTAssertEqualObjects(map, self.periodMap);
-  }
-}
-
-- (void)testSKProductDiscountStubToMap {
-  if (@available(iOS 11.2, *)) {
-    SKProductDiscountStub *discount = [[SKProductDiscountStub alloc] initWithMap:self.discountMap];
-    NSDictionary *map = [FIAObjectTranslator getMapFromSKProductDiscount:discount];
-    XCTAssertEqualObjects(map, self.discountMap);
-  }
-}
-
-- (void)testProductToMap {
-  SKProductStub *product = [[SKProductStub alloc] initWithMap:self.productMap];
-  NSDictionary *map = [FIAObjectTranslator getMapFromSKProduct:product];
-  XCTAssertEqualObjects(map, self.productMap);
-}
-
-- (void)testProductResponseToMap {
-  SKProductsResponseStub *response =
-      [[SKProductsResponseStub alloc] initWithMap:self.productResponseMap];
-  NSDictionary *map = [FIAObjectTranslator getMapFromSKProductsResponse:response];
-  XCTAssertEqualObjects(map, self.productResponseMap);
-}
-
-- (void)testPaymentToMap {
-  SKMutablePayment *payment = [FIAObjectTranslator getSKMutablePaymentFromMap:self.paymentMap];
-  NSDictionary *map = [FIAObjectTranslator getMapFromSKPayment:payment];
-  XCTAssertEqualObjects(map, self.paymentMap);
-}
-
-- (void)testPaymentTransactionToMap {
-  // payment is not KVC, cannot test payment field.
-  SKPaymentTransactionStub *paymentTransaction =
-      [[SKPaymentTransactionStub alloc] initWithMap:self.transactionMap];
-  NSDictionary *map = [FIAObjectTranslator getMapFromSKPaymentTransaction:paymentTransaction];
-  XCTAssertEqualObjects(map, self.transactionMap);
-}
-
-- (void)testError {
-  NSErrorStub *error = [[NSErrorStub alloc] initWithMap:self.errorMap];
-  NSDictionary *map = [FIAObjectTranslator getMapFromNSError:error];
-  XCTAssertEqualObjects(map, self.errorMap);
-}
-
-- (void)testLocaleToMap {
-  if (@available(iOS 10.0, *)) {
-    NSLocale *system = NSLocale.systemLocale;
-    NSDictionary *map = [FIAObjectTranslator getMapFromNSLocale:system];
-    XCTAssertEqualObjects(map[@"currencySymbol"], system.currencySymbol);
-  }
-}
-
-@end
diff --git a/packages/in_app_purchase/in_app_purchase/ios/in_app_purchase.podspec b/packages/in_app_purchase/in_app_purchase/ios/in_app_purchase.podspec
deleted file mode 100644
index 8da9d78..0000000
--- a/packages/in_app_purchase/in_app_purchase/ios/in_app_purchase.podspec
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
-#
-Pod::Spec.new do |s|
-  s.name             = 'in_app_purchase'
-  s.version          = '0.0.1'
-  s.summary          = 'Flutter In App Purchase'
-  s.description      = <<-DESC
-A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store.
-Downloaded by pub (not CocoaPods).
-                       DESC
-  s.homepage         = 'https://github.com/flutter/plugins'
-  s.license          = { :type => 'BSD', :file => '../LICENSE' }
-  s.author           = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
-  s.source           = { :http => 'https://github.com/flutter/plugins/tree/master/packages/in_app_purchase' }
-  s.documentation_url = 'https://pub.dev/packages/in_app_purchase'
-  s.source_files = 'Classes/**/*'
-  s.public_header_files = 'Classes/**/*.h'
-  s.dependency 'Flutter'
-  s.platform = :ios, '8.0'
-  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => 'armv7 arm64 x86_64' }
-
-  s.test_spec 'Tests' do |test_spec|
-    test_spec.source_files = 'Tests/**/*'
-    test_spec.dependency 'OCMock','3.5'
-  end
-end
diff --git a/packages/in_app_purchase/in_app_purchase/lib/billing_client_wrappers.dart b/packages/in_app_purchase/in_app_purchase/lib/billing_client_wrappers.dart
deleted file mode 100644
index 1dac19f..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/billing_client_wrappers.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-export 'src/billing_client_wrappers/billing_client_wrapper.dart';
-export 'src/billing_client_wrappers/purchase_wrapper.dart';
-export 'src/billing_client_wrappers/sku_details_wrapper.dart';
diff --git a/packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart b/packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart
index 928f860..f8547e4 100644
--- a/packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart
+++ b/packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart
@@ -2,6 +2,210 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-export 'src/in_app_purchase/in_app_purchase_connection.dart';
-export 'src/in_app_purchase/product_details.dart';
-export 'src/in_app_purchase/purchase_details.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
+import 'package:in_app_purchase_android/in_app_purchase_android.dart';
+import 'package:in_app_purchase_ios/in_app_purchase_ios.dart';
+
+export 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart'
+    show
+        IAPError,
+        InAppPurchaseException,
+        ProductDetails,
+        ProductDetailsResponse,
+        PurchaseDetails,
+        PurchaseParam,
+        PurchaseVerificationData,
+        PurchaseStatus;
+
+/// Basic API for making in app purchases across multiple platforms.
+class InAppPurchase implements InAppPurchasePlatformAdditionProvider {
+  InAppPurchase._();
+
+  static InAppPurchase? _instance;
+
+  /// The instance of the [InAppPurchase] to use.
+  static InAppPurchase get instance => _getOrCreateInstance();
+
+  static InAppPurchase _getOrCreateInstance() {
+    if (_instance != null) {
+      return _instance!;
+    }
+
+    if (defaultTargetPlatform == TargetPlatform.android) {
+      InAppPurchaseAndroidPlatform.registerPlatform();
+    } else if (defaultTargetPlatform == TargetPlatform.iOS) {
+      InAppPurchaseIosPlatform.registerPlatform();
+    }
+
+    _instance = InAppPurchase._();
+    return _instance!;
+  }
+
+  @override
+  T getPlatformAddition<T extends InAppPurchasePlatformAddition?>() {
+    return InAppPurchasePlatformAddition.instance as T;
+  }
+
+  /// Listen to this broadcast stream to get real time update for purchases.
+  ///
+  /// This stream will never close as long as the app is active.
+  ///
+  /// Purchase updates can happen in several situations:
+  /// * When a purchase is triggered by user in the app.
+  /// * When a purchase is triggered by user from the platform-specific store front.
+  /// * When a purchase is restored on the device by the user in the app.
+  /// * If a purchase is not completed ([completePurchase] is not called on the
+  ///   purchase object) from the last app session. Purchase updates will happen
+  ///   when a new app session starts instead.
+  ///
+  /// IMPORTANT! You must subscribe to this stream as soon as your app launches,
+  /// preferably before returning your main App Widget in main(). Otherwise you
+  /// will miss purchase updated made before this stream is subscribed to.
+  ///
+  /// We also recommend listening to the stream with one subscription at a given
+  /// time. If you choose to have multiple subscription at the same time, you
+  /// should be careful at the fact that each subscription will receive all the
+  /// events after they start to listen.
+  Stream<List<PurchaseDetails>> get purchaseStream =>
+      InAppPurchasePlatform.instance.purchaseStream;
+
+  /// Returns `true` if the payment platform is ready and available.
+  Future<bool> isAvailable() => InAppPurchasePlatform.instance.isAvailable();
+
+  /// Query product details for the given set of IDs.
+  ///
+  /// Identifiers in the underlying payment platform, for example, [App Store
+  /// Connect](https://appstoreconnect.apple.com/) for iOS and [Google Play
+  /// Console](https://play.google.com/) for Android.
+  Future<ProductDetailsResponse> queryProductDetails(Set<String> identifiers) =>
+      InAppPurchasePlatform.instance.queryProductDetails(identifiers);
+
+  /// Buy a non consumable product or subscription.
+  ///
+  /// Non consumable items can only be bought once. For example, a purchase that
+  /// unlocks a special content in your app. Subscriptions are also non
+  /// consumable products.
+  ///
+  /// You always need to restore all the non consumable products for user when
+  /// they switch their phones.
+  ///
+  /// This method does not return the result of the purchase. Instead, after
+  /// triggering this method, purchase updates will be sent to
+  /// [purchaseStream]. You should [Stream.listen] to [purchaseStream] to get
+  /// [PurchaseDetails] objects in different [PurchaseDetails.status] and update
+  ///  your UI accordingly. When the [PurchaseDetails.status] is
+  /// [PurchaseStatus.purchased], [PurchaseStatus.restored] or
+  /// [PurchaseStatus.error] you should deliver the content or handle the error,
+  /// then call [completePurchase] to finish the purchasing process.
+  ///
+  /// This method does return whether or not the purchase request was initially
+  /// sent successfully.
+  ///
+  /// Consumable items are defined differently by the different underlying
+  /// payment platforms, and there's no way to query for whether or not the
+  /// [ProductDetail] is a consumable at runtime.
+  ///
+  /// See also:
+  ///
+  ///  * [buyConsumable], for buying a consumable product.
+  ///  * [restorePurchases], for restoring non consumable products.
+  ///
+  /// Calling this method for consumable items will cause unwanted behaviors!
+  Future<bool> buyNonConsumable({required PurchaseParam purchaseParam}) =>
+      InAppPurchasePlatform.instance.buyNonConsumable(
+        purchaseParam: purchaseParam,
+      );
+
+  /// Buy a consumable product.
+  ///
+  /// Consumable items can be "consumed" to mark that they've been used and then
+  /// bought additional times. For example, a health potion.
+  ///
+  /// To restore consumable purchases across devices, you should keep track of
+  /// those purchase on your own server and restore the purchase for your users.
+  /// Consumed products are no longer considered to be "owned" by payment
+  /// platforms and will not be delivered by calling [restorePurchases].
+  ///
+  /// Consumable items are defined differently by the different underlying
+  /// payment platforms, and there's no way to query for whether or not the
+  /// [ProductDetail] is a consumable at runtime.
+  ///
+  /// `autoConsume` is provided as a utility and will instruct the plugin to
+  /// automatically consume the product after a succesful purchase.
+  /// `autoConsume` is `true` by default.
+  ///
+  /// This method does not return the result of the purchase. Instead, after
+  /// triggering this method, purchase updates will be sent to
+  /// [purchaseStream]. You should [Stream.listen] to
+  /// [purchaseStream] to get [PurchaseDetails] objects in different
+  /// [PurchaseDetails.status] and update your UI accordingly. When the
+  /// [PurchaseDetails.status] is [PurchaseStatus.purchased] or
+  /// [PurchaseStatus.error], you should deliver the content or handle the
+  /// error, then call [completePurchase] to finish the purchasing process.
+  ///
+  /// This method does return whether or not the purchase request was initially
+  /// sent succesfully.
+  ///
+  /// See also:
+  ///
+  ///  * [buyNonConsumable], for buying a non consumable product or
+  ///    subscription.
+  ///  * [restorePurchases], for restoring non consumable products.
+  ///
+  /// Calling this method for non consumable items will cause unwanted
+  /// behaviors!
+  Future<bool> buyConsumable({
+    required PurchaseParam purchaseParam,
+    bool autoConsume = true,
+  }) =>
+      InAppPurchasePlatform.instance.buyConsumable(
+        purchaseParam: purchaseParam,
+      );
+
+  /// Mark that purchased content has been delivered to the user.
+  ///
+  /// You are responsible for completing every [PurchaseDetails] whose
+  /// [PurchaseDetails.status] is [PurchaseStatus.purchased] or
+  /// [PurchaseStatus.restored].
+  /// Completing a [PurchaseStatus.pending] purchase will cause an exception.
+  /// For convenience, [PurchaseDetails.pendingCompletePurchase] indicates if a
+  /// purchase is pending for completion.
+  ///
+  /// The method will throw a [PurchaseException] when the purchase could not be
+  /// finished. Depending on the [PurchaseException.errorCode] the developer
+  /// should try to complete the purchase via this method again, or retry the
+  /// [completePurchase] method at a later time. If the
+  /// [PurchaseException.errorCode] indicates you should not retry there might
+  /// be some issue with the app's code or the configuration of the app in the
+  /// respective store. The developer is responsible to fix this issue. The
+  /// [PurchaseException.message] field might provide more information on what
+  /// went wrong.
+  Future<void> completePurchase(PurchaseDetails purchase) =>
+      InAppPurchasePlatform.instance.completePurchase(purchase);
+
+  /// Restore all previous purchases.
+  ///
+  /// The `applicationUserName` should match whatever was sent in the initial
+  /// `PurchaseParam`, if anything. If no `applicationUserName` was specified in the initial
+  /// `PurchaseParam`, use `null`.
+  ///
+  /// Restored purchases are delivered through the [purchaseStream] with a
+  /// status of [PurchaseStatus.restored]. You should listen for these purchases,
+  /// validate their receipts, deliver the content and mark the purchase complete
+  /// by calling the [finishPurchase] method for each purchase.
+  ///
+  /// This does not return consumed products. If you want to restore unused
+  /// consumable products, you need to persist consumable product information
+  /// for your user on your own server.
+  ///
+  /// See also:
+  ///
+  ///  * [refreshPurchaseVerificationData], for reloading failed
+  ///    [PurchaseDetails.verificationData].
+  Future<void> restorePurchases({String? applicationUserName}) =>
+      InAppPurchasePlatform.instance.restorePurchases(
+        applicationUserName: applicationUserName,
+      );
+}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/README.md b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/README.md
deleted file mode 100644
index 54e76b5..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# billing_client_wrappers
-
-This exposes a way Dart endpoints through to [Google Play Billing
-Library](https://developer.android.com/google/play/billing/billing_library_overview).
-Can be used as an alternative to
-[in_app_purchase](../in_app_purchase/README.md).
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart
deleted file mode 100644
index 1f43b3a..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/billing_client_wrapper.dart
+++ /dev/null
@@ -1,448 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-import 'package:flutter/services.dart';
-import 'package:flutter/foundation.dart';
-import 'package:json_annotation/json_annotation.dart';
-import '../../billing_client_wrappers.dart';
-import '../channel.dart';
-import 'purchase_wrapper.dart';
-import 'sku_details_wrapper.dart';
-import 'enum_converters.dart';
-
-/// Method identifier for the OnPurchaseUpdated method channel method.
-@visibleForTesting
-const String kOnPurchasesUpdated =
-    'PurchasesUpdatedListener#onPurchasesUpdated(int, List<Purchase>)';
-const String _kOnBillingServiceDisconnected =
-    'BillingClientStateListener#onBillingServiceDisconnected()';
-
-/// Callback triggered by Play in response to purchase activity.
-///
-/// This callback is triggered in response to all purchase activity while an
-/// instance of `BillingClient` is active. This includes purchases initiated by
-/// the app ([BillingClient.launchBillingFlow]) as well as purchases made in
-/// Play itself while this app is open.
-///
-/// This does not provide any hooks for purchases made in the past. See
-/// [BillingClient.queryPurchases] and [BillingClient.queryPurchaseHistory].
-///
-/// All purchase information should also be verified manually, with your server
-/// if at all possible. See ["Verify a
-/// purchase"](https://developer.android.com/google/play/billing/billing_library_overview#Verify).
-///
-/// Wraps a
-/// [`PurchasesUpdatedListener`](https://developer.android.com/reference/com/android/billingclient/api/PurchasesUpdatedListener.html).
-typedef void PurchasesUpdatedListener(PurchasesResultWrapper purchasesResult);
-
-/// This class can be used directly instead of [InAppPurchaseConnection] to call
-/// Play-specific billing APIs.
-///
-/// Wraps a
-/// [`com.android.billingclient.api.BillingClient`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient)
-/// instance.
-///
-///
-/// In general this API conforms to the Java
-/// `com.android.billingclient.api.BillingClient` API as much as possible, with
-/// some minor changes to account for language differences. Callbacks have been
-/// converted to futures where appropriate.
-class BillingClient {
-  bool _enablePendingPurchases = false;
-
-  /// Creates a billing client.
-  BillingClient(PurchasesUpdatedListener onPurchasesUpdated) {
-    channel.setMethodCallHandler(callHandler);
-    _callbacks[kOnPurchasesUpdated] = [onPurchasesUpdated];
-  }
-
-  // Occasionally methods in the native layer require a Dart callback to be
-  // triggered in response to a Java callback. For example,
-  // [startConnection] registers an [OnBillingServiceDisconnected] callback.
-  // This list of names to callbacks is used to trigger Dart callbacks in
-  // response to those Java callbacks. Dart sends the Java layer a handle to the
-  // matching callback here to remember, and then once its twin is triggered it
-  // sends the handle back over the platform channel. We then access that handle
-  // in this array and call it in Dart code. See also [_callHandler].
-  Map<String, List<Function>> _callbacks = <String, List<Function>>{};
-
-  /// Calls
-  /// [`BillingClient#isReady()`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#isReady())
-  /// to get the ready status of the BillingClient instance.
-  Future<bool> isReady() async {
-    final bool? ready =
-        await channel.invokeMethod<bool>('BillingClient#isReady()');
-    return ready ?? false;
-  }
-
-  /// Enable the [BillingClientWrapper] to handle pending purchases.
-  ///
-  /// Play requires that you call this method when initializing your application.
-  /// It is to acknowledge your application has been updated to support pending purchases.
-  /// See [Support pending transactions](https://developer.android.com/google/play/billing/billing_library_overview#pending)
-  /// for more details.
-  ///
-  /// Failure to call this method before any other method in the [startConnection] will throw an exception.
-  void enablePendingPurchases() {
-    _enablePendingPurchases = true;
-  }
-
-  /// Calls
-  /// [`BillingClient#startConnection(BillingClientStateListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#startconnection)
-  /// to create and connect a `BillingClient` instance.
-  ///
-  /// [onBillingServiceConnected] has been converted from a callback parameter
-  /// to the Future result returned by this function. This returns the
-  /// `BillingClient.BillingResultWrapper` describing the connection result.
-  ///
-  /// This triggers the creation of a new `BillingClient` instance in Java if
-  /// one doesn't already exist.
-  Future<BillingResultWrapper> startConnection(
-      {required OnBillingServiceDisconnected
-          onBillingServiceDisconnected}) async {
-    assert(_enablePendingPurchases,
-        'enablePendingPurchases() must be called before calling startConnection');
-    List<Function> disconnectCallbacks =
-        _callbacks[_kOnBillingServiceDisconnected] ??= [];
-    disconnectCallbacks.add(onBillingServiceDisconnected);
-    return BillingResultWrapper.fromJson((await channel
-            .invokeMapMethod<String, dynamic>(
-                "BillingClient#startConnection(BillingClientStateListener)",
-                <String, dynamic>{
-              'handle': disconnectCallbacks.length - 1,
-              'enablePendingPurchases': _enablePendingPurchases
-            })) ??
-        <String, dynamic>{});
-  }
-
-  /// Calls
-  /// [`BillingClient#endConnection(BillingClientStateListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#endconnect
-  /// to disconnect a `BillingClient` instance.
-  ///
-  /// Will trigger the [OnBillingServiceDisconnected] callback passed to [startConnection].
-  ///
-  /// This triggers the destruction of the `BillingClient` instance in Java.
-  Future<void> endConnection() async {
-    return channel.invokeMethod<void>("BillingClient#endConnection()", null);
-  }
-
-  /// Returns a list of [SkuDetailsWrapper]s that have [SkuDetailsWrapper.sku]
-  /// in `skusList`, and [SkuDetailsWrapper.type] matching `skuType`.
-  ///
-  /// Calls through to [`BillingClient#querySkuDetailsAsync(SkuDetailsParams,
-  /// SkuDetailsResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querySkuDetailsAsync(com.android.billingclient.api.SkuDetailsParams,%20com.android.billingclient.api.SkuDetailsResponseListener))
-  /// Instead of taking a callback parameter, it returns a Future
-  /// [SkuDetailsResponseWrapper]. It also takes the values of
-  /// `SkuDetailsParams` as direct arguments instead of requiring it constructed
-  /// and passed in as a class.
-  Future<SkuDetailsResponseWrapper> querySkuDetails(
-      {required SkuType skuType, required List<String> skusList}) async {
-    final Map<String, dynamic> arguments = <String, dynamic>{
-      'skuType': SkuTypeConverter().toJson(skuType),
-      'skusList': skusList
-    };
-    return SkuDetailsResponseWrapper.fromJson((await channel.invokeMapMethod<
-                String, dynamic>(
-            'BillingClient#querySkuDetailsAsync(SkuDetailsParams, SkuDetailsResponseListener)',
-            arguments)) ??
-        <String, dynamic>{});
-  }
-
-  /// Attempt to launch the Play Billing Flow for a given [skuDetails].
-  ///
-  /// The [skuDetails] needs to have already been fetched in a [querySkuDetails]
-  /// call. The [accountId] is an optional hashed string associated with the user
-  /// that's unique to your app. It's used by Google to detect unusual behavior.
-  /// Do not pass in a cleartext [accountId], and do not use this field to store any Personally Identifiable Information (PII)
-  /// such as emails in cleartext. Attempting to store PII in this field will result in purchases being blocked.
-  /// Google Play recommends that you use either encryption or a one-way hash to generate an obfuscated identifier to send to Google Play.
-  ///
-  /// Specifies an optional [obfuscatedProfileId] that is uniquely associated with the user's profile in your app.
-  /// Some applications allow users to have multiple profiles within a single account. Use this method to send the user's profile identifier to Google.
-  /// Setting this field requests the user's obfuscated account id.
-  ///
-  /// Calling this attemps to show the Google Play purchase UI. The user is free
-  /// to complete the transaction there.
-  ///
-  /// This method returns a [BillingResultWrapper] representing the initial attempt
-  /// to show the Google Play billing flow. Actual purchase updates are
-  /// delivered via the [PurchasesUpdatedListener].
-  ///
-  /// This method calls through to
-  /// [`BillingClient#launchBillingFlow`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#launchbillingflow).
-  /// It constructs a
-  /// [`BillingFlowParams`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams)
-  /// instance by [setting the given skuDetails](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder.html#setskudetails),
-  /// [the given accountId](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setObfuscatedAccountId(java.lang.String))
-  /// and the [obfuscatedProfileId] (https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setobfuscatedprofileid).
-  ///
-  /// When this method is called to purchase a subscription, an optional `oldSku`
-  /// can be passed in. This will tell Google Play that rather than purchasing a new subscription,
-  /// the user needs to upgrade/downgrade the existing subscription.
-  /// The [oldSku](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setoldsku) and [purchaseToken] are the SKU id and purchase token that the user is upgrading or downgrading from.
-  /// [purchaseToken] must not be `null` if [oldSku] is not `null`.
-  /// The [prorationMode](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.Builder#setreplaceskusprorationmode) is the mode of proration during subscription upgrade/downgrade.
-  /// This value will only be effective if the `oldSku` is also set.
-  Future<BillingResultWrapper> launchBillingFlow(
-      {required String sku,
-      String? accountId,
-      String? obfuscatedProfileId,
-      String? oldSku,
-      String? purchaseToken,
-      ProrationMode? prorationMode}) async {
-    assert(sku != null);
-    assert((oldSku == null) == (purchaseToken == null),
-        'oldSku and purchaseToken must both be set, or both be null.');
-    final Map<String, dynamic> arguments = <String, dynamic>{
-      'sku': sku,
-      'accountId': accountId,
-      'obfuscatedProfileId': obfuscatedProfileId,
-      'oldSku': oldSku,
-      'purchaseToken': purchaseToken,
-      'prorationMode': ProrationModeConverter().toJson(prorationMode ??
-          ProrationMode.unknownSubscriptionUpgradeDowngradePolicy)
-    };
-    return BillingResultWrapper.fromJson(
-        (await channel.invokeMapMethod<String, dynamic>(
-                'BillingClient#launchBillingFlow(Activity, BillingFlowParams)',
-                arguments)) ??
-            <String, dynamic>{});
-  }
-
-  /// Fetches recent purchases for the given [SkuType].
-  ///
-  /// Unlike [queryPurchaseHistory], This does not make a network request and
-  /// does not return items that are no longer owned.
-  ///
-  /// All purchase information should also be verified manually, with your
-  /// server if at all possible. See ["Verify a
-  /// purchase"](https://developer.android.com/google/play/billing/billing_library_overview#Verify).
-  ///
-  /// This wraps [`BillingClient#queryPurchases(String
-  /// skutype)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchases).
-  Future<PurchasesResultWrapper> queryPurchases(SkuType skuType) async {
-    assert(skuType != null);
-    return PurchasesResultWrapper.fromJson((await channel
-            .invokeMapMethod<String, dynamic>(
-                'BillingClient#queryPurchases(String)', <String, dynamic>{
-          'skuType': SkuTypeConverter().toJson(skuType)
-        })) ??
-        <String, dynamic>{});
-  }
-
-  /// Fetches purchase history for the given [SkuType].
-  ///
-  /// Unlike [queryPurchases], this makes a network request via Play and returns
-  /// the most recent purchase for each [SkuDetailsWrapper] of the given
-  /// [SkuType] even if the item is no longer owned.
-  ///
-  /// All purchase information should also be verified manually, with your
-  /// server if at all possible. See ["Verify a
-  /// purchase"](https://developer.android.com/google/play/billing/billing_library_overview#Verify).
-  ///
-  /// This wraps [`BillingClient#queryPurchaseHistoryAsync(String skuType,
-  /// PurchaseHistoryResponseListener
-  /// listener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#querypurchasehistoryasync).
-  Future<PurchasesHistoryResult> queryPurchaseHistory(SkuType skuType) async {
-    assert(skuType != null);
-    return PurchasesHistoryResult.fromJson((await channel.invokeMapMethod<
-                String, dynamic>(
-            'BillingClient#queryPurchaseHistoryAsync(String, PurchaseHistoryResponseListener)',
-            <String, dynamic>{
-              'skuType': SkuTypeConverter().toJson(skuType)
-            })) ??
-        <String, dynamic>{});
-  }
-
-  /// Consumes a given in-app product.
-  ///
-  /// Consuming can only be done on an item that's owned, and as a result of consumption, the user will no longer own it.
-  /// Consumption is done asynchronously. The method returns a Future containing a [BillingResultWrapper].
-  ///
-  /// This wraps [`BillingClient#consumeAsync(String, ConsumeResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#consumeAsync(java.lang.String,%20com.android.billingclient.api.ConsumeResponseListener))
-  Future<BillingResultWrapper> consumeAsync(String purchaseToken) async {
-    assert(purchaseToken != null);
-    return BillingResultWrapper.fromJson((await channel
-            .invokeMapMethod<String, dynamic>(
-                'BillingClient#consumeAsync(String, ConsumeResponseListener)',
-                <String, dynamic>{
-              'purchaseToken': purchaseToken,
-            })) ??
-        <String, dynamic>{});
-  }
-
-  /// Acknowledge an in-app purchase.
-  ///
-  /// The developer must acknowledge all in-app purchases after they have been granted to the user.
-  /// If this doesn't happen within three days of the purchase, the purchase will be refunded.
-  ///
-  /// Consumables are already implicitly acknowledged by calls to [consumeAsync] and
-  /// do not need to be explicitly acknowledged by using this method.
-  /// However this method can be called for them in order to explicitly acknowledge them if desired.
-  ///
-  /// Be sure to only acknowledge a purchase after it has been granted to the user.
-  /// [PurchaseWrapper.purchaseState] should be [PurchaseStateWrapper.purchased] and
-  /// the purchase should be validated. See [Verify a purchase](https://developer.android.com/google/play/billing/billing_library_overview#Verify) on verifying purchases.
-  ///
-  /// Please refer to [acknowledge](https://developer.android.com/google/play/billing/billing_library_overview#acknowledge) for more
-  /// details.
-  ///
-  /// This wraps [`BillingClient#acknowledgePurchase(String, AcknowledgePurchaseResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#acknowledgePurchase(com.android.billingclient.api.AcknowledgePurchaseParams,%20com.android.billingclient.api.AcknowledgePurchaseResponseListener))
-  Future<BillingResultWrapper> acknowledgePurchase(String purchaseToken) async {
-    assert(purchaseToken != null);
-    return BillingResultWrapper.fromJson((await channel.invokeMapMethod<String,
-                dynamic>(
-            'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)',
-            <String, dynamic>{
-              'purchaseToken': purchaseToken,
-            })) ??
-        <String, dynamic>{});
-  }
-
-  /// The method call handler for [channel].
-  @visibleForTesting
-  Future<void> callHandler(MethodCall call) async {
-    switch (call.method) {
-      case kOnPurchasesUpdated:
-        // The purchases updated listener is a singleton.
-        assert(_callbacks[kOnPurchasesUpdated]!.length == 1);
-        final PurchasesUpdatedListener listener =
-            _callbacks[kOnPurchasesUpdated]!.first as PurchasesUpdatedListener;
-        listener(PurchasesResultWrapper.fromJson(
-            call.arguments.cast<String, dynamic>()));
-        break;
-      case _kOnBillingServiceDisconnected:
-        final int handle = call.arguments['handle'];
-        await _callbacks[_kOnBillingServiceDisconnected]![handle]();
-        break;
-    }
-  }
-}
-
-/// Callback triggered when the [BillingClientWrapper] is disconnected.
-///
-/// Wraps
-/// [`com.android.billingclient.api.BillingClientStateListener.onServiceDisconnected()`](https://developer.android.com/reference/com/android/billingclient/api/BillingClientStateListener.html#onBillingServiceDisconnected())
-/// to call back on `BillingClient` disconnect.
-typedef void OnBillingServiceDisconnected();
-
-/// Possible `BillingClient` response statuses.
-///
-/// Wraps
-/// [`BillingClient.BillingResponse`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponse).
-/// See the `BillingResponse` docs for more explanation of the different
-/// constants.
-enum BillingResponse {
-  // WARNING: Changes to this class need to be reflected in our generated code.
-  // Run `flutter packages pub run build_runner watch` to rebuild and watch for
-  // further changes.
-
-  /// The request has reached the maximum timeout before Google Play responds.
-  @JsonValue(-3)
-  serviceTimeout,
-
-  /// The requested feature is not supported by Play Store on the current device.
-  @JsonValue(-2)
-  featureNotSupported,
-
-  /// The play Store service is not connected now - potentially transient state.
-  @JsonValue(-1)
-  serviceDisconnected,
-
-  /// Success.
-  @JsonValue(0)
-  ok,
-
-  /// The user pressed back or canceled a dialog.
-  @JsonValue(1)
-  userCanceled,
-
-  /// The network connection is down.
-  @JsonValue(2)
-  serviceUnavailable,
-
-  /// The billing API version is not supported for the type requested.
-  @JsonValue(3)
-  billingUnavailable,
-
-  /// The requested product is not available for purchase.
-  @JsonValue(4)
-  itemUnavailable,
-
-  /// Invalid arguments provided to the API.
-  @JsonValue(5)
-  developerError,
-
-  /// Fatal error during the API action.
-  @JsonValue(6)
-  error,
-
-  /// Failure to purchase since item is already owned.
-  @JsonValue(7)
-  itemAlreadyOwned,
-
-  /// Failure to consume since item is not owned.
-  @JsonValue(8)
-  itemNotOwned,
-}
-
-/// Enum representing potential [SkuDetailsWrapper.type]s.
-///
-/// Wraps
-/// [`BillingClient.SkuType`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.SkuType)
-/// See the linked documentation for an explanation of the different constants.
-enum SkuType {
-  // WARNING: Changes to this class need to be reflected in our generated code.
-  // Run `flutter packages pub run build_runner watch` to rebuild and watch for
-  // further changes.
-
-  /// A one time product. Acquired in a single transaction.
-  @JsonValue('inapp')
-  inapp,
-
-  /// A product requiring a recurring charge over time.
-  @JsonValue('subs')
-  subs,
-}
-
-/// Enum representing the proration mode.
-///
-/// When upgrading or downgrading a subscription, set this mode to provide details
-/// about the proration that will be applied when the subscription changes.
-///
-/// Wraps [`BillingFlowParams.ProrationMode`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode)
-/// See the linked documentation for an explanation of the different constants.
-enum ProrationMode {
-// WARNING: Changes to this class need to be reflected in our generated code.
-// Run `flutter packages pub run build_runner watch` to rebuild and watch for
-// further changes.
-
-  /// Unknown upgrade or downgrade policy.
-  @JsonValue(0)
-  unknownSubscriptionUpgradeDowngradePolicy,
-
-  /// Replacement takes effect immediately, and the remaining time will be prorated and credited to the user.
-  ///
-  /// This is the current default behavior.
-  @JsonValue(1)
-  immediateWithTimeProration,
-
-  /// Replacement takes effect immediately, and the billing cycle remains the same.
-  ///
-  /// The price for the remaining period will be charged.
-  /// This option is only available for subscription upgrade.
-  @JsonValue(2)
-  immediateAndChargeProratedPrice,
-
-  /// Replacement takes effect immediately, and the new price will be charged on next recurrence time.
-  ///
-  /// The billing cycle stays the same.
-  @JsonValue(3)
-  immediateWithoutProration,
-
-  /// Replacement takes effect when the old plan expires, and the new price will be charged at the same time.
-  @JsonValue(4)
-  deferred,
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart
deleted file mode 100644
index 1f5e2a2..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.dart
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:in_app_purchase/billing_client_wrappers.dart';
-import 'package:in_app_purchase/in_app_purchase.dart';
-import 'package:json_annotation/json_annotation.dart';
-
-part 'enum_converters.g.dart';
-
-/// Serializer for [BillingResponse].
-///
-/// Use these in `@JsonSerializable()` classes by annotating them with
-/// `@BillingResponseConverter()`.
-class BillingResponseConverter implements JsonConverter<BillingResponse, int?> {
-  /// Default const constructor.
-  const BillingResponseConverter();
-
-  @override
-  BillingResponse fromJson(int? json) {
-    if (json == null) {
-      return BillingResponse.error;
-    }
-    return _$enumDecode<BillingResponse, dynamic>(
-        _$BillingResponseEnumMap.cast<BillingResponse, dynamic>(), json);
-  }
-
-  @override
-  int toJson(BillingResponse object) => _$BillingResponseEnumMap[object]!;
-}
-
-/// Serializer for [SkuType].
-///
-/// Use these in `@JsonSerializable()` classes by annotating them with
-/// `@SkuTypeConverter()`.
-class SkuTypeConverter implements JsonConverter<SkuType, String?> {
-  /// Default const constructor.
-  const SkuTypeConverter();
-
-  @override
-  SkuType fromJson(String? json) {
-    if (json == null) {
-      return SkuType.inapp;
-    }
-    return _$enumDecode<SkuType, dynamic>(
-        _$SkuTypeEnumMap.cast<SkuType, dynamic>(), json);
-  }
-
-  @override
-  String toJson(SkuType object) => _$SkuTypeEnumMap[object]!;
-}
-
-/// Serializer for [ProrationMode].
-///
-/// Use these in `@JsonSerializable()` classes by annotating them with
-/// `@ProrationModeConverter()`.
-class ProrationModeConverter implements JsonConverter<ProrationMode, int?> {
-  /// Default const constructor.
-  const ProrationModeConverter();
-
-  @override
-  ProrationMode fromJson(int? json) {
-    if (json == null) {
-      return ProrationMode.unknownSubscriptionUpgradeDowngradePolicy;
-    }
-    return _$enumDecode<ProrationMode, dynamic>(
-        _$ProrationModeEnumMap.cast<ProrationMode, dynamic>(), json);
-  }
-
-  @override
-  int toJson(ProrationMode object) => _$ProrationModeEnumMap[object]!;
-}
-
-// Define a class so we generate serializer helper methods for the enums
-@JsonSerializable()
-class _SerializedEnums {
-  late BillingResponse response;
-  late SkuType type;
-  late PurchaseStateWrapper purchaseState;
-  late ProrationMode prorationMode;
-}
-
-/// Serializer for [PurchaseStateWrapper].
-///
-/// Use these in `@JsonSerializable()` classes by annotating them with
-/// `@PurchaseStateConverter()`.
-class PurchaseStateConverter
-    implements JsonConverter<PurchaseStateWrapper, int?> {
-  /// Default const constructor.
-  const PurchaseStateConverter();
-
-  @override
-  PurchaseStateWrapper fromJson(int? json) {
-    if (json == null) {
-      return PurchaseStateWrapper.unspecified_state;
-    }
-    return _$enumDecode<PurchaseStateWrapper, dynamic>(
-        _$PurchaseStateWrapperEnumMap.cast<PurchaseStateWrapper, dynamic>(),
-        json);
-  }
-
-  @override
-  int toJson(PurchaseStateWrapper object) =>
-      _$PurchaseStateWrapperEnumMap[object]!;
-
-  /// Converts the purchase state stored in `object` to a [PurchaseStatus].
-  ///
-  /// [PurchaseStateWrapper.unspecified_state] is mapped to [PurchaseStatus.error].
-  PurchaseStatus toPurchaseStatus(PurchaseStateWrapper object) {
-    switch (object) {
-      case PurchaseStateWrapper.pending:
-        return PurchaseStatus.pending;
-      case PurchaseStateWrapper.purchased:
-        return PurchaseStatus.purchased;
-      case PurchaseStateWrapper.unspecified_state:
-        return PurchaseStatus.error;
-    }
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart
deleted file mode 100644
index 4186a2a..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/enum_converters.g.dart
+++ /dev/null
@@ -1,85 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'enum_converters.dart';
-
-// **************************************************************************
-// JsonSerializableGenerator
-// **************************************************************************
-
-_SerializedEnums _$_SerializedEnumsFromJson(Map json) {
-  return _SerializedEnums()
-    ..response = _$enumDecode(_$BillingResponseEnumMap, json['response'])
-    ..type = _$enumDecode(_$SkuTypeEnumMap, json['type'])
-    ..purchaseState =
-        _$enumDecode(_$PurchaseStateWrapperEnumMap, json['purchaseState'])
-    ..prorationMode =
-        _$enumDecode(_$ProrationModeEnumMap, json['prorationMode']);
-}
-
-Map<String, dynamic> _$_SerializedEnumsToJson(_SerializedEnums instance) =>
-    <String, dynamic>{
-      'response': _$BillingResponseEnumMap[instance.response],
-      'type': _$SkuTypeEnumMap[instance.type],
-      'purchaseState': _$PurchaseStateWrapperEnumMap[instance.purchaseState],
-      'prorationMode': _$ProrationModeEnumMap[instance.prorationMode],
-    };
-
-K _$enumDecode<K, V>(
-  Map<K, V> enumValues,
-  Object? source, {
-  K? unknownValue,
-}) {
-  if (source == null) {
-    throw ArgumentError(
-      'A value must be provided. Supported values: '
-      '${enumValues.values.join(', ')}',
-    );
-  }
-
-  return enumValues.entries.singleWhere(
-    (e) => e.value == source,
-    orElse: () {
-      if (unknownValue == null) {
-        throw ArgumentError(
-          '`$source` is not one of the supported values: '
-          '${enumValues.values.join(', ')}',
-        );
-      }
-      return MapEntry(unknownValue, enumValues.values.first);
-    },
-  ).key;
-}
-
-const _$BillingResponseEnumMap = {
-  BillingResponse.serviceTimeout: -3,
-  BillingResponse.featureNotSupported: -2,
-  BillingResponse.serviceDisconnected: -1,
-  BillingResponse.ok: 0,
-  BillingResponse.userCanceled: 1,
-  BillingResponse.serviceUnavailable: 2,
-  BillingResponse.billingUnavailable: 3,
-  BillingResponse.itemUnavailable: 4,
-  BillingResponse.developerError: 5,
-  BillingResponse.error: 6,
-  BillingResponse.itemAlreadyOwned: 7,
-  BillingResponse.itemNotOwned: 8,
-};
-
-const _$SkuTypeEnumMap = {
-  SkuType.inapp: 'inapp',
-  SkuType.subs: 'subs',
-};
-
-const _$PurchaseStateWrapperEnumMap = {
-  PurchaseStateWrapper.unspecified_state: 0,
-  PurchaseStateWrapper.purchased: 1,
-  PurchaseStateWrapper.pending: 2,
-};
-
-const _$ProrationModeEnumMap = {
-  ProrationMode.unknownSubscriptionUpgradeDowngradePolicy: 0,
-  ProrationMode.immediateWithTimeProration: 1,
-  ProrationMode.immediateAndChargeProratedPrice: 2,
-  ProrationMode.immediateWithoutProration: 3,
-  ProrationMode.deferred: 4,
-};
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart
deleted file mode 100644
index 7ef089f..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.dart
+++ /dev/null
@@ -1,332 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:ui' show hashValues;
-import 'package:flutter/foundation.dart';
-import 'package:json_annotation/json_annotation.dart';
-import 'enum_converters.dart';
-import 'billing_client_wrapper.dart';
-import 'sku_details_wrapper.dart';
-
-// WARNING: Changes to `@JsonSerializable` classes need to be reflected in the
-// below generated file. Run `flutter packages pub run build_runner watch` to
-// rebuild and watch for further changes.
-part 'purchase_wrapper.g.dart';
-
-/// Data structure representing a successful purchase.
-///
-/// All purchase information should also be verified manually, with your
-/// server if at all possible. See ["Verify a
-/// purchase"](https://developer.android.com/google/play/billing/billing_library_overview#Verify).
-///
-/// This wraps [`com.android.billlingclient.api.Purchase`](https://developer.android.com/reference/com/android/billingclient/api/Purchase)
-@JsonSerializable()
-@PurchaseStateConverter()
-class PurchaseWrapper {
-  /// Creates a purchase wrapper with the given purchase details.
-  @visibleForTesting
-  PurchaseWrapper(
-      {required this.orderId,
-      required this.packageName,
-      required this.purchaseTime,
-      required this.purchaseToken,
-      required this.signature,
-      required this.sku,
-      required this.isAutoRenewing,
-      required this.originalJson,
-      this.developerPayload,
-      required this.isAcknowledged,
-      required this.purchaseState});
-
-  /// Factory for creating a [PurchaseWrapper] from a [Map] with the purchase details.
-  factory PurchaseWrapper.fromJson(Map<String, dynamic> map) =>
-      _$PurchaseWrapperFromJson(map);
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) return true;
-    if (other.runtimeType != runtimeType) return false;
-    final PurchaseWrapper typedOther = other as PurchaseWrapper;
-    return typedOther.orderId == orderId &&
-        typedOther.packageName == packageName &&
-        typedOther.purchaseTime == purchaseTime &&
-        typedOther.purchaseToken == purchaseToken &&
-        typedOther.signature == signature &&
-        typedOther.sku == sku &&
-        typedOther.isAutoRenewing == isAutoRenewing &&
-        typedOther.originalJson == originalJson &&
-        typedOther.isAcknowledged == isAcknowledged &&
-        typedOther.purchaseState == purchaseState;
-  }
-
-  @override
-  int get hashCode => hashValues(
-      orderId,
-      packageName,
-      purchaseTime,
-      purchaseToken,
-      signature,
-      sku,
-      isAutoRenewing,
-      originalJson,
-      isAcknowledged,
-      purchaseState);
-
-  /// The unique ID for this purchase. Corresponds to the Google Payments order
-  /// ID.
-  @JsonKey(defaultValue: '')
-  final String orderId;
-
-  /// The package name the purchase was made from.
-  @JsonKey(defaultValue: '')
-  final String packageName;
-
-  /// When the purchase was made, as an epoch timestamp.
-  @JsonKey(defaultValue: 0)
-  final int purchaseTime;
-
-  /// A unique ID for a given [SkuDetailsWrapper], user, and purchase.
-  @JsonKey(defaultValue: '')
-  final String purchaseToken;
-
-  /// Signature of purchase data, signed with the developer's private key. Uses
-  /// RSASSA-PKCS1-v1_5.
-  @JsonKey(defaultValue: '')
-  final String signature;
-
-  /// The product ID of this purchase.
-  @JsonKey(defaultValue: '')
-  final String sku;
-
-  /// True for subscriptions that renew automatically. Does not apply to
-  /// [SkuType.inapp] products.
-  ///
-  /// For [SkuType.subs] this means that the subscription is canceled when it is
-  /// false.
-  ///
-  /// The value is `false` for [SkuType.inapp] products.
-  final bool isAutoRenewing;
-
-  /// Details about this purchase, in JSON.
-  ///
-  /// This can be used verify a purchase. See ["Verify a purchase on a
-  /// device"](https://developer.android.com/google/play/billing/billing_library_overview#Verify-purchase-device).
-  /// Note though that verifying a purchase locally is inherently insecure (see
-  /// the article for more details).
-  @JsonKey(defaultValue: '')
-  final String originalJson;
-
-  /// The payload specified by the developer when the purchase was acknowledged or consumed.
-  ///
-  /// The value is `null` if it wasn't specified when the purchase was acknowledged or consumed.
-  /// The `developerPayload` is removed from [BillingClientWrapper.acknowledgePurchase], [BillingClientWrapper.consumeAsync], [InAppPurchaseConnection.completePurchase], [InAppPurchaseConnection.consumePurchase]
-  /// after plugin version `0.5.0`. As a result, this will be `null` for new purchases that happen after updating to `0.5.0`.
-  final String? developerPayload;
-
-  /// Whether the purchase has been acknowledged.
-  ///
-  /// A successful purchase has to be acknowledged within 3 days after the purchase via [BillingClient.acknowledgePurchase].
-  /// * See also [BillingClient.acknowledgePurchase] for more details on acknowledging purchases.
-  @JsonKey(defaultValue: false)
-  final bool isAcknowledged;
-
-  /// Determines the current state of the purchase.
-  ///
-  /// [BillingClient.acknowledgePurchase] should only be called when the `purchaseState` is [PurchaseStateWrapper.purchased].
-  /// * See also [BillingClient.acknowledgePurchase] for more details on acknowledging purchases.
-  final PurchaseStateWrapper purchaseState;
-}
-
-/// Data structure representing a purchase history record.
-///
-/// This class includes a subset of fields in [PurchaseWrapper].
-///
-/// This wraps [`com.android.billlingclient.api.PurchaseHistoryRecord`](https://developer.android.com/reference/com/android/billingclient/api/PurchaseHistoryRecord)
-///
-/// * See also: [BillingClient.queryPurchaseHistory] for obtaining a [PurchaseHistoryRecordWrapper].
-// We can optionally make [PurchaseWrapper] extend or implement [PurchaseHistoryRecordWrapper].
-// For now, we keep them separated classes to be consistent with Android's BillingClient implementation.
-@JsonSerializable()
-class PurchaseHistoryRecordWrapper {
-  /// Creates a [PurchaseHistoryRecordWrapper] with the given record details.
-  @visibleForTesting
-  PurchaseHistoryRecordWrapper({
-    required this.purchaseTime,
-    required this.purchaseToken,
-    required this.signature,
-    required this.sku,
-    required this.originalJson,
-    required this.developerPayload,
-  });
-
-  /// Factory for creating a [PurchaseHistoryRecordWrapper] from a [Map] with the record details.
-  factory PurchaseHistoryRecordWrapper.fromJson(Map<String, dynamic> map) =>
-      _$PurchaseHistoryRecordWrapperFromJson(map);
-
-  /// When the purchase was made, as an epoch timestamp.
-  @JsonKey(defaultValue: 0)
-  final int purchaseTime;
-
-  /// A unique ID for a given [SkuDetailsWrapper], user, and purchase.
-  @JsonKey(defaultValue: '')
-  final String purchaseToken;
-
-  /// Signature of purchase data, signed with the developer's private key. Uses
-  /// RSASSA-PKCS1-v1_5.
-  @JsonKey(defaultValue: '')
-  final String signature;
-
-  /// The product ID of this purchase.
-  @JsonKey(defaultValue: '')
-  final String sku;
-
-  /// Details about this purchase, in JSON.
-  ///
-  /// This can be used verify a purchase. See ["Verify a purchase on a
-  /// device"](https://developer.android.com/google/play/billing/billing_library_overview#Verify-purchase-device).
-  /// Note though that verifying a purchase locally is inherently insecure (see
-  /// the article for more details).
-  @JsonKey(defaultValue: '')
-  final String originalJson;
-
-  /// The payload specified by the developer when the purchase was acknowledged or consumed.
-  ///
-  /// The value is `null` if it wasn't specified when the purchase was acknowledged or consumed.
-  final String? developerPayload;
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) return true;
-    if (other.runtimeType != runtimeType) return false;
-    final PurchaseHistoryRecordWrapper typedOther =
-        other as PurchaseHistoryRecordWrapper;
-    return typedOther.purchaseTime == purchaseTime &&
-        typedOther.purchaseToken == purchaseToken &&
-        typedOther.signature == signature &&
-        typedOther.sku == sku &&
-        typedOther.originalJson == originalJson &&
-        typedOther.developerPayload == developerPayload;
-  }
-
-  @override
-  int get hashCode => hashValues(purchaseTime, purchaseToken, signature, sku,
-      originalJson, developerPayload);
-}
-
-/// A data struct representing the result of a transaction.
-///
-/// Contains a potentially empty list of [PurchaseWrapper]s, a [BillingResultWrapper]
-/// that contains a detailed description of the status and a
-/// [BillingResponse] to signify the overall state of the transaction.
-///
-/// Wraps [`com.android.billingclient.api.Purchase.PurchasesResult`](https://developer.android.com/reference/com/android/billingclient/api/Purchase.PurchasesResult).
-@JsonSerializable()
-@BillingResponseConverter()
-class PurchasesResultWrapper {
-  /// Creates a [PurchasesResultWrapper] with the given purchase result details.
-  PurchasesResultWrapper(
-      {required this.responseCode,
-      required this.billingResult,
-      required this.purchasesList});
-
-  /// Factory for creating a [PurchaseResultWrapper] from a [Map] with the result details.
-  factory PurchasesResultWrapper.fromJson(Map<String, dynamic> map) =>
-      _$PurchasesResultWrapperFromJson(map);
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) return true;
-    if (other.runtimeType != runtimeType) return false;
-    final PurchasesResultWrapper typedOther = other as PurchasesResultWrapper;
-    return typedOther.responseCode == responseCode &&
-        typedOther.purchasesList == purchasesList &&
-        typedOther.billingResult == billingResult;
-  }
-
-  @override
-  int get hashCode => hashValues(billingResult, responseCode, purchasesList);
-
-  /// The detailed description of the status of the operation.
-  final BillingResultWrapper billingResult;
-
-  /// The status of the operation.
-  ///
-  /// This can represent either the status of the "query purchase history" half
-  /// of the operation and the "user made purchases" transaction itself.
-  final BillingResponse responseCode;
-
-  /// The list of successful purchases made in this transaction.
-  ///
-  /// May be empty, especially if [responseCode] is not [BillingResponse.ok].
-  @JsonKey(defaultValue: <PurchaseWrapper>[])
-  final List<PurchaseWrapper> purchasesList;
-}
-
-/// A data struct representing the result of a purchase history.
-///
-/// Contains a potentially empty list of [PurchaseHistoryRecordWrapper]s and a [BillingResultWrapper]
-/// that contains a detailed description of the status.
-@JsonSerializable()
-@BillingResponseConverter()
-class PurchasesHistoryResult {
-  /// Creates a [PurchasesHistoryResult] with the provided history.
-  PurchasesHistoryResult(
-      {required this.billingResult, required this.purchaseHistoryRecordList});
-
-  /// Factory for creating a [PurchasesHistoryResult] from a [Map] with the history result details.
-  factory PurchasesHistoryResult.fromJson(Map<String, dynamic> map) =>
-      _$PurchasesHistoryResultFromJson(map);
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) return true;
-    if (other.runtimeType != runtimeType) return false;
-    final PurchasesHistoryResult typedOther = other as PurchasesHistoryResult;
-    return typedOther.purchaseHistoryRecordList == purchaseHistoryRecordList &&
-        typedOther.billingResult == billingResult;
-  }
-
-  @override
-  int get hashCode => hashValues(billingResult, purchaseHistoryRecordList);
-
-  /// The detailed description of the status of the [BillingClient.queryPurchaseHistory].
-  final BillingResultWrapper billingResult;
-
-  /// The list of queried purchase history records.
-  ///
-  /// May be empty, especially if [billingResult.responseCode] is not [BillingResponse.ok].
-  @JsonKey(defaultValue: <PurchaseHistoryRecordWrapper>[])
-  final List<PurchaseHistoryRecordWrapper> purchaseHistoryRecordList;
-}
-
-/// Possible state of a [PurchaseWrapper].
-///
-/// Wraps
-/// [`BillingClient.api.Purchase.PurchaseState`](https://developer.android.com/reference/com/android/billingclient/api/Purchase.PurchaseState.html).
-/// * See also: [PurchaseWrapper].
-enum PurchaseStateWrapper {
-  /// The state is unspecified.
-  ///
-  /// No actions on the [PurchaseWrapper] should be performed on this state.
-  /// This is a catch-all. It should never be returned by the Play Billing Library.
-  @JsonValue(0)
-  unspecified_state,
-
-  /// The user has completed the purchase process.
-  ///
-  /// The production should be delivered and then the purchase should be acknowledged.
-  /// * See also [BillingClient.acknowledgePurchase] for more details on acknowledging purchases.
-  @JsonValue(1)
-  purchased,
-
-  /// The user has started the purchase process.
-  ///
-  /// The user should follow the instructions that were given to them by the Play
-  /// Billing Library to complete the purchase.
-  ///
-  /// You can also choose to remind the user to complete the purchase if you detected a
-  /// [PurchaseWrapper] is still in the `pending` state in the future while calling [BillingClient.queryPurchases].
-  @JsonValue(2)
-  pending,
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart
deleted file mode 100644
index 5f0d936..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/purchase_wrapper.g.dart
+++ /dev/null
@@ -1,109 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'purchase_wrapper.dart';
-
-// **************************************************************************
-// JsonSerializableGenerator
-// **************************************************************************
-
-PurchaseWrapper _$PurchaseWrapperFromJson(Map json) {
-  return PurchaseWrapper(
-    orderId: json['orderId'] as String? ?? '',
-    packageName: json['packageName'] as String? ?? '',
-    purchaseTime: json['purchaseTime'] as int? ?? 0,
-    purchaseToken: json['purchaseToken'] as String? ?? '',
-    signature: json['signature'] as String? ?? '',
-    sku: json['sku'] as String? ?? '',
-    isAutoRenewing: json['isAutoRenewing'] as bool,
-    originalJson: json['originalJson'] as String? ?? '',
-    developerPayload: json['developerPayload'] as String?,
-    isAcknowledged: json['isAcknowledged'] as bool? ?? false,
-    purchaseState:
-        const PurchaseStateConverter().fromJson(json['purchaseState'] as int?),
-  );
-}
-
-Map<String, dynamic> _$PurchaseWrapperToJson(PurchaseWrapper instance) =>
-    <String, dynamic>{
-      'orderId': instance.orderId,
-      'packageName': instance.packageName,
-      'purchaseTime': instance.purchaseTime,
-      'purchaseToken': instance.purchaseToken,
-      'signature': instance.signature,
-      'sku': instance.sku,
-      'isAutoRenewing': instance.isAutoRenewing,
-      'originalJson': instance.originalJson,
-      'developerPayload': instance.developerPayload,
-      'isAcknowledged': instance.isAcknowledged,
-      'purchaseState':
-          const PurchaseStateConverter().toJson(instance.purchaseState),
-    };
-
-PurchaseHistoryRecordWrapper _$PurchaseHistoryRecordWrapperFromJson(Map json) {
-  return PurchaseHistoryRecordWrapper(
-    purchaseTime: json['purchaseTime'] as int? ?? 0,
-    purchaseToken: json['purchaseToken'] as String? ?? '',
-    signature: json['signature'] as String? ?? '',
-    sku: json['sku'] as String? ?? '',
-    originalJson: json['originalJson'] as String? ?? '',
-    developerPayload: json['developerPayload'] as String?,
-  );
-}
-
-Map<String, dynamic> _$PurchaseHistoryRecordWrapperToJson(
-        PurchaseHistoryRecordWrapper instance) =>
-    <String, dynamic>{
-      'purchaseTime': instance.purchaseTime,
-      'purchaseToken': instance.purchaseToken,
-      'signature': instance.signature,
-      'sku': instance.sku,
-      'originalJson': instance.originalJson,
-      'developerPayload': instance.developerPayload,
-    };
-
-PurchasesResultWrapper _$PurchasesResultWrapperFromJson(Map json) {
-  return PurchasesResultWrapper(
-    responseCode:
-        const BillingResponseConverter().fromJson(json['responseCode'] as int?),
-    billingResult:
-        BillingResultWrapper.fromJson((json['billingResult'] as Map?)?.map(
-      (k, e) => MapEntry(k as String, e),
-    )),
-    purchasesList: (json['purchasesList'] as List<dynamic>?)
-            ?.map((e) =>
-                PurchaseWrapper.fromJson(Map<String, dynamic>.from(e as Map)))
-            .toList() ??
-        [],
-  );
-}
-
-Map<String, dynamic> _$PurchasesResultWrapperToJson(
-        PurchasesResultWrapper instance) =>
-    <String, dynamic>{
-      'billingResult': instance.billingResult,
-      'responseCode':
-          const BillingResponseConverter().toJson(instance.responseCode),
-      'purchasesList': instance.purchasesList,
-    };
-
-PurchasesHistoryResult _$PurchasesHistoryResultFromJson(Map json) {
-  return PurchasesHistoryResult(
-    billingResult:
-        BillingResultWrapper.fromJson((json['billingResult'] as Map?)?.map(
-      (k, e) => MapEntry(k as String, e),
-    )),
-    purchaseHistoryRecordList:
-        (json['purchaseHistoryRecordList'] as List<dynamic>?)
-                ?.map((e) => PurchaseHistoryRecordWrapper.fromJson(
-                    Map<String, dynamic>.from(e as Map)))
-                .toList() ??
-            [],
-  );
-}
-
-Map<String, dynamic> _$PurchasesHistoryResultToJson(
-        PurchasesHistoryResult instance) =>
-    <String, dynamic>{
-      'billingResult': instance.billingResult,
-      'purchaseHistoryRecordList': instance.purchaseHistoryRecordList,
-    };
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart
deleted file mode 100644
index e3d13df..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.dart
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:ui' show hashValues;
-import 'package:flutter/foundation.dart';
-import 'package:json_annotation/json_annotation.dart';
-import 'billing_client_wrapper.dart';
-import 'enum_converters.dart';
-
-// WARNING: Changes to `@JsonSerializable` classes need to be reflected in the
-// below generated file. Run `flutter packages pub run build_runner watch` to
-// rebuild and watch for further changes.
-part 'sku_details_wrapper.g.dart';
-
-/// The error message shown when the map represents billing result is invalid from method channel.
-///
-/// This usually indicates a series underlining code issue in the plugin.
-@visibleForTesting
-const kInvalidBillingResultErrorMessage =
-    'Invalid billing result map from method channel.';
-
-/// Dart wrapper around [`com.android.billingclient.api.SkuDetails`](https://developer.android.com/reference/com/android/billingclient/api/SkuDetails).
-///
-/// Contains the details of an available product in Google Play Billing.
-@JsonSerializable()
-@SkuTypeConverter()
-class SkuDetailsWrapper {
-  /// Creates a [SkuDetailsWrapper] with the given purchase details.
-  @visibleForTesting
-  SkuDetailsWrapper({
-    required this.description,
-    required this.freeTrialPeriod,
-    required this.introductoryPrice,
-    required this.introductoryPriceMicros,
-    required this.introductoryPriceCycles,
-    required this.introductoryPricePeriod,
-    required this.price,
-    required this.priceAmountMicros,
-    required this.priceCurrencyCode,
-    required this.sku,
-    required this.subscriptionPeriod,
-    required this.title,
-    required this.type,
-    required this.originalPrice,
-    required this.originalPriceAmountMicros,
-  });
-
-  /// Constructs an instance of this from a key value map of data.
-  ///
-  /// The map needs to have named string keys with values matching the names and
-  /// types of all of the members on this class.
-  @visibleForTesting
-  factory SkuDetailsWrapper.fromJson(Map<String, dynamic> map) =>
-      _$SkuDetailsWrapperFromJson(map);
-
-  /// Textual description of the product.
-  @JsonKey(defaultValue: '')
-  final String description;
-
-  /// Trial period in ISO 8601 format.
-  @JsonKey(defaultValue: '')
-  final String freeTrialPeriod;
-
-  /// Introductory price, only applies to [SkuType.subs]. Formatted ("$0.99").
-  @JsonKey(defaultValue: '')
-  final String introductoryPrice;
-
-  /// [introductoryPrice] in micro-units 990000
-  @JsonKey(defaultValue: '')
-  final String introductoryPriceMicros;
-
-  /// The number of subscription billing periods for which the user will be given the introductory price, such as 3.
-  /// Returns 0 if the SKU is not a subscription or doesn't have an introductory period.
-  @JsonKey(defaultValue: 0)
-  final int introductoryPriceCycles;
-
-  /// The billing period of [introductoryPrice], in ISO 8601 format.
-  @JsonKey(defaultValue: '')
-  final String introductoryPricePeriod;
-
-  /// Formatted with currency symbol ("$0.99").
-  @JsonKey(defaultValue: '')
-  final String price;
-
-  /// [price] in micro-units ("990000").
-  @JsonKey(defaultValue: 0)
-  final int priceAmountMicros;
-
-  /// [price] ISO 4217 currency code.
-  @JsonKey(defaultValue: '')
-  final String priceCurrencyCode;
-
-  /// The product ID in Google Play Console.
-  @JsonKey(defaultValue: '')
-  final String sku;
-
-  /// Applies to [SkuType.subs], formatted in ISO 8601.
-  @JsonKey(defaultValue: '')
-  final String subscriptionPeriod;
-
-  /// The product's title.
-  @JsonKey(defaultValue: '')
-  final String title;
-
-  /// The [SkuType] of the product.
-  final SkuType type;
-
-  /// The original price that the user purchased this product for.
-  @JsonKey(defaultValue: '')
-  final String originalPrice;
-
-  /// [originalPrice] in micro-units ("990000").
-  @JsonKey(defaultValue: 0)
-  final int originalPriceAmountMicros;
-
-  @override
-  bool operator ==(dynamic other) {
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-
-    final SkuDetailsWrapper typedOther = other;
-    return typedOther is SkuDetailsWrapper &&
-        typedOther.description == description &&
-        typedOther.freeTrialPeriod == freeTrialPeriod &&
-        typedOther.introductoryPrice == introductoryPrice &&
-        typedOther.introductoryPriceMicros == introductoryPriceMicros &&
-        typedOther.introductoryPriceCycles == introductoryPriceCycles &&
-        typedOther.introductoryPricePeriod == introductoryPricePeriod &&
-        typedOther.price == price &&
-        typedOther.priceAmountMicros == priceAmountMicros &&
-        typedOther.sku == sku &&
-        typedOther.subscriptionPeriod == subscriptionPeriod &&
-        typedOther.title == title &&
-        typedOther.type == type &&
-        typedOther.originalPrice == originalPrice &&
-        typedOther.originalPriceAmountMicros == originalPriceAmountMicros;
-  }
-
-  @override
-  int get hashCode {
-    return hashValues(
-        description.hashCode,
-        freeTrialPeriod.hashCode,
-        introductoryPrice.hashCode,
-        introductoryPriceMicros.hashCode,
-        introductoryPriceCycles.hashCode,
-        introductoryPricePeriod.hashCode,
-        price.hashCode,
-        priceAmountMicros.hashCode,
-        sku.hashCode,
-        subscriptionPeriod.hashCode,
-        title.hashCode,
-        type.hashCode,
-        originalPrice,
-        originalPriceAmountMicros);
-  }
-}
-
-/// Translation of [`com.android.billingclient.api.SkuDetailsResponseListener`](https://developer.android.com/reference/com/android/billingclient/api/SkuDetailsResponseListener.html).
-///
-/// Returned by [BillingClient.querySkuDetails].
-@JsonSerializable()
-class SkuDetailsResponseWrapper {
-  /// Creates a [SkuDetailsResponseWrapper] with the given purchase details.
-  @visibleForTesting
-  SkuDetailsResponseWrapper(
-      {required this.billingResult, required this.skuDetailsList});
-
-  /// Constructs an instance of this from a key value map of data.
-  ///
-  /// The map needs to have named string keys with values matching the names and
-  /// types of all of the members on this class.
-  factory SkuDetailsResponseWrapper.fromJson(Map<String, dynamic> map) =>
-      _$SkuDetailsResponseWrapperFromJson(map);
-
-  /// The final result of the [BillingClient.querySkuDetails] call.
-  final BillingResultWrapper billingResult;
-
-  /// A list of [SkuDetailsWrapper] matching the query to [BillingClient.querySkuDetails].
-  @JsonKey(defaultValue: <SkuDetailsWrapper>[])
-  final List<SkuDetailsWrapper> skuDetailsList;
-
-  @override
-  bool operator ==(dynamic other) {
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-
-    final SkuDetailsResponseWrapper typedOther = other;
-    return typedOther is SkuDetailsResponseWrapper &&
-        typedOther.billingResult == billingResult &&
-        typedOther.skuDetailsList == skuDetailsList;
-  }
-
-  @override
-  int get hashCode => hashValues(billingResult, skuDetailsList);
-}
-
-/// Params containing the response code and the debug message from the Play Billing API response.
-@JsonSerializable()
-@BillingResponseConverter()
-class BillingResultWrapper {
-  /// Constructs the object with [responseCode] and [debugMessage].
-  BillingResultWrapper({required this.responseCode, this.debugMessage});
-
-  /// Constructs an instance of this from a key value map of data.
-  ///
-  /// The map needs to have named string keys with values matching the names and
-  /// types of all of the members on this class.
-  factory BillingResultWrapper.fromJson(Map<String, dynamic>? map) {
-    if (map == null || map.isEmpty) {
-      return BillingResultWrapper(
-          responseCode: BillingResponse.error,
-          debugMessage: kInvalidBillingResultErrorMessage);
-    }
-    return _$BillingResultWrapperFromJson(map);
-  }
-
-  /// Response code returned in the Play Billing API calls.
-  final BillingResponse responseCode;
-
-  /// Debug message returned in the Play Billing API calls.
-  ///
-  /// Defaults to `null`.
-  /// This message uses an en-US locale and should not be shown to users.
-  final String? debugMessage;
-
-  @override
-  bool operator ==(dynamic other) {
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-
-    final BillingResultWrapper typedOther = other;
-    return typedOther is BillingResultWrapper &&
-        typedOther.responseCode == responseCode &&
-        typedOther.debugMessage == debugMessage;
-  }
-
-  @override
-  int get hashCode => hashValues(responseCode, debugMessage);
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart
deleted file mode 100644
index a14affd..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/billing_client_wrappers/sku_details_wrapper.g.dart
+++ /dev/null
@@ -1,83 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'sku_details_wrapper.dart';
-
-// **************************************************************************
-// JsonSerializableGenerator
-// **************************************************************************
-
-SkuDetailsWrapper _$SkuDetailsWrapperFromJson(Map json) {
-  return SkuDetailsWrapper(
-    description: json['description'] as String? ?? '',
-    freeTrialPeriod: json['freeTrialPeriod'] as String? ?? '',
-    introductoryPrice: json['introductoryPrice'] as String? ?? '',
-    introductoryPriceMicros: json['introductoryPriceMicros'] as String? ?? '',
-    introductoryPriceCycles: json['introductoryPriceCycles'] as int? ?? 0,
-    introductoryPricePeriod: json['introductoryPricePeriod'] as String? ?? '',
-    price: json['price'] as String? ?? '',
-    priceAmountMicros: json['priceAmountMicros'] as int? ?? 0,
-    priceCurrencyCode: json['priceCurrencyCode'] as String? ?? '',
-    sku: json['sku'] as String? ?? '',
-    subscriptionPeriod: json['subscriptionPeriod'] as String? ?? '',
-    title: json['title'] as String? ?? '',
-    type: const SkuTypeConverter().fromJson(json['type'] as String?),
-    originalPrice: json['originalPrice'] as String? ?? '',
-    originalPriceAmountMicros: json['originalPriceAmountMicros'] as int? ?? 0,
-  );
-}
-
-Map<String, dynamic> _$SkuDetailsWrapperToJson(SkuDetailsWrapper instance) =>
-    <String, dynamic>{
-      'description': instance.description,
-      'freeTrialPeriod': instance.freeTrialPeriod,
-      'introductoryPrice': instance.introductoryPrice,
-      'introductoryPriceMicros': instance.introductoryPriceMicros,
-      'introductoryPriceCycles': instance.introductoryPriceCycles,
-      'introductoryPricePeriod': instance.introductoryPricePeriod,
-      'price': instance.price,
-      'priceAmountMicros': instance.priceAmountMicros,
-      'priceCurrencyCode': instance.priceCurrencyCode,
-      'sku': instance.sku,
-      'subscriptionPeriod': instance.subscriptionPeriod,
-      'title': instance.title,
-      'type': const SkuTypeConverter().toJson(instance.type),
-      'originalPrice': instance.originalPrice,
-      'originalPriceAmountMicros': instance.originalPriceAmountMicros,
-    };
-
-SkuDetailsResponseWrapper _$SkuDetailsResponseWrapperFromJson(Map json) {
-  return SkuDetailsResponseWrapper(
-    billingResult:
-        BillingResultWrapper.fromJson((json['billingResult'] as Map?)?.map(
-      (k, e) => MapEntry(k as String, e),
-    )),
-    skuDetailsList: (json['skuDetailsList'] as List<dynamic>?)
-            ?.map((e) =>
-                SkuDetailsWrapper.fromJson(Map<String, dynamic>.from(e as Map)))
-            .toList() ??
-        [],
-  );
-}
-
-Map<String, dynamic> _$SkuDetailsResponseWrapperToJson(
-        SkuDetailsResponseWrapper instance) =>
-    <String, dynamic>{
-      'billingResult': instance.billingResult,
-      'skuDetailsList': instance.skuDetailsList,
-    };
-
-BillingResultWrapper _$BillingResultWrapperFromJson(Map json) {
-  return BillingResultWrapper(
-    responseCode:
-        const BillingResponseConverter().fromJson(json['responseCode'] as int?),
-    debugMessage: json['debugMessage'] as String?,
-  );
-}
-
-Map<String, dynamic> _$BillingResultWrapperToJson(
-        BillingResultWrapper instance) =>
-    <String, dynamic>{
-      'responseCode':
-          const BillingResponseConverter().toJson(instance.responseCode),
-      'debugMessage': instance.debugMessage,
-    };
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/channel.dart b/packages/in_app_purchase/in_app_purchase/lib/src/channel.dart
deleted file mode 100644
index f8ab4d4..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/channel.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter/services.dart';
-
-/// Method channel for the plugin's platform<-->Dart calls.
-const MethodChannel channel =
-    MethodChannel('plugins.flutter.io/in_app_purchase');
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/README.md b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/README.md
deleted file mode 100644
index 8e064c6..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/README.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# in_app_purchase
-
-A simplified, generic API for handling in app purchases with a single code base.
-
-You can use this to:
-
-* Display a list of products for sale from App Store (on iOS) or Google Play (on
-  Android)
-* Purchase a product. From the App Store this supports consumables,
-  non-consumables, and subscriptions. From Google Play this supports both in app
-  purchases and subscriptions.
-* Load previously purchased products, to the extent that this is supported in
-  both underlying platforms.
-
-This can be used in addition to or as an alternative to
-[billing_client_wrappers](../billing_client_wrappers/README.md) and
-[store_kit_wrappers](../store_kit_wrappers/README.md).
-
-`InAppPurchaseConnection` tries to be as platform agnostic as possible, but in
-some cases differentiating between the underlying platforms is unavoidable.
-
-You can see a sample usage of this in the [example
-app](../../../example/README.md).
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart
deleted file mode 100644
index 3c56f01..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:flutter/foundation.dart';
-import 'package:flutter/services.dart';
-import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart';
-import 'in_app_purchase_connection.dart';
-import 'product_details.dart';
-import 'package:in_app_purchase/store_kit_wrappers.dart';
-import 'package:in_app_purchase/src/store_kit_wrappers/enum_converters.dart';
-import '../../billing_client_wrappers.dart';
-
-/// An [InAppPurchaseConnection] that wraps StoreKit.
-///
-/// This translates various `StoreKit` calls and responses into the
-/// generic plugin API.
-class AppStoreConnection implements InAppPurchaseConnection {
-  /// Returns the singleton instance of the [AppStoreConnection] that should be
-  /// used across the app.
-  static AppStoreConnection get instance => _getOrCreateInstance();
-  static AppStoreConnection? _instance;
-  static late SKPaymentQueueWrapper _skPaymentQueueWrapper;
-  static late _TransactionObserver _observer;
-
-  /// Creates an [AppStoreConnection] object.
-  ///
-  /// This constructor should only be used for testing, for any other purpose
-  /// get the connection from the [instance] getter.
-  @visibleForTesting
-  AppStoreConnection();
-
-  Stream<List<PurchaseDetails>> get purchaseUpdatedStream =>
-      _observer.purchaseUpdatedController.stream;
-
-  /// Callback handler for transaction status changes.
-  @visibleForTesting
-  static SKTransactionObserverWrapper get observer => _observer;
-
-  static AppStoreConnection _getOrCreateInstance() {
-    if (_instance != null) {
-      return _instance!;
-    }
-
-    _instance = AppStoreConnection();
-    _skPaymentQueueWrapper = SKPaymentQueueWrapper();
-    _observer = _TransactionObserver(StreamController.broadcast());
-    _skPaymentQueueWrapper.setTransactionObserver(observer);
-    return _instance!;
-  }
-
-  @override
-  Future<bool> isAvailable() => SKPaymentQueueWrapper.canMakePayments();
-
-  @override
-  Future<bool> buyNonConsumable({required PurchaseParam purchaseParam}) async {
-    assert(
-        purchaseParam.changeSubscriptionParam == null,
-        "`purchaseParam.changeSubscriptionParam` must be null. It is not supported on iOS "
-        "as Apple provides a subscription grouping mechanism. "
-        "Each subscription you offer must be assigned to a subscription group. "
-        "So the developers can group related subscriptions together to prevents users "
-        "from accidentally purchasing multiple subscriptions. "
-        "Please refer to the 'Creating a Subscription Group' sections of "
-        "Apple's subscription guide (https://developer.apple.com/app-store/subscriptions/)");
-    await _skPaymentQueueWrapper.addPayment(SKPaymentWrapper(
-        productIdentifier: purchaseParam.productDetails.id,
-        quantity: 1,
-        applicationUsername: purchaseParam.applicationUserName,
-        simulatesAskToBuyInSandbox: purchaseParam.simulatesAskToBuyInSandbox ||
-            // ignore: deprecated_member_use_from_same_package
-            purchaseParam.sandboxTesting,
-        requestData: null));
-    return true; // There's no error feedback from iOS here to return.
-  }
-
-  @override
-  Future<bool> buyConsumable(
-      {required PurchaseParam purchaseParam, bool autoConsume = true}) {
-    assert(autoConsume == true, 'On iOS, we should always auto consume');
-    return buyNonConsumable(purchaseParam: purchaseParam);
-  }
-
-  @override
-  Future<BillingResultWrapper> completePurchase(
-      PurchaseDetails purchase) async {
-    if (purchase.skPaymentTransaction == null) {
-      throw ArgumentError(
-          'completePurchase unsuccessful. The `purchase.skPaymentTransaction` is not valid');
-    }
-    await _skPaymentQueueWrapper
-        .finishTransaction(purchase.skPaymentTransaction!);
-    return BillingResultWrapper(responseCode: BillingResponse.ok);
-  }
-
-  @override
-  Future<BillingResultWrapper> consumePurchase(PurchaseDetails purchase) {
-    throw UnsupportedError('consume purchase is not available on iOS');
-  }
-
-  @override
-  Future<QueryPurchaseDetailsResponse> queryPastPurchases(
-      {String? applicationUserName}) async {
-    IAPError? error;
-    List<PurchaseDetails> pastPurchases = [];
-
-    try {
-      String receiptData = await _observer.getReceiptData();
-      final List<SKPaymentTransactionWrapper> restoredTransactions =
-          await _observer.getRestoredTransactions(
-              queue: _skPaymentQueueWrapper,
-              applicationUserName: applicationUserName);
-      pastPurchases =
-          restoredTransactions.map((SKPaymentTransactionWrapper transaction) {
-        assert(transaction.transactionState ==
-            SKPaymentTransactionStateWrapper.restored);
-        return PurchaseDetails.fromSKTransaction(transaction, receiptData)
-          ..status = SKTransactionStatusConverter()
-              .toPurchaseStatus(transaction.transactionState)
-          ..error = transaction.error != null
-              ? IAPError(
-                  source: IAPSource.AppStore,
-                  code: kPurchaseErrorCode,
-                  message: transaction.error?.domain ?? '',
-                  details: transaction.error?.userInfo,
-                )
-              : null;
-      }).toList();
-      _observer.cleanUpRestoredTransactions();
-    } on PlatformException catch (e) {
-      error = IAPError(
-          source: IAPSource.AppStore,
-          code: e.code,
-          message: e.message ?? '',
-          details: e.details);
-    } on SKError catch (e) {
-      error = IAPError(
-          source: IAPSource.AppStore,
-          code: kRestoredPurchaseErrorCode,
-          message: e.domain,
-          details: e.userInfo);
-    }
-    return QueryPurchaseDetailsResponse(
-        pastPurchases: pastPurchases, error: error);
-  }
-
-  @override
-  Future<PurchaseVerificationData?> refreshPurchaseVerificationData() async {
-    await SKRequestMaker().startRefreshReceiptRequest();
-    final String? receipt = await SKReceiptManager.retrieveReceiptData();
-    if (receipt == null) {
-      return null;
-    }
-    return PurchaseVerificationData(
-        localVerificationData: receipt,
-        serverVerificationData: receipt,
-        source: IAPSource.AppStore);
-  }
-
-  /// Query the product detail list.
-  ///
-  /// This method only returns [ProductDetailsResponse].
-  /// To get detailed Store Kit product list, use [SkProductResponseWrapper.startProductRequest]
-  /// to get the [SKProductResponseWrapper].
-  @override
-  Future<ProductDetailsResponse> queryProductDetails(
-      Set<String> identifiers) async {
-    final SKRequestMaker requestMaker = SKRequestMaker();
-    SkProductResponseWrapper response;
-    PlatformException? exception;
-    try {
-      response = await requestMaker.startProductRequest(identifiers.toList());
-    } on PlatformException catch (e) {
-      exception = e;
-      response = SkProductResponseWrapper(
-          products: [], invalidProductIdentifiers: identifiers.toList());
-    }
-    List<ProductDetails> productDetails = [];
-    if (response.products != null) {
-      productDetails = response.products
-          .map((SKProductWrapper productWrapper) =>
-              ProductDetails.fromSKProduct(productWrapper))
-          .toList();
-    }
-    List<String> invalidIdentifiers = response.invalidProductIdentifiers;
-    if (productDetails.isEmpty) {
-      invalidIdentifiers = identifiers.toList();
-    }
-    ProductDetailsResponse productDetailsResponse = ProductDetailsResponse(
-      productDetails: productDetails,
-      notFoundIDs: invalidIdentifiers,
-      error: exception == null
-          ? null
-          : IAPError(
-              source: IAPSource.AppStore,
-              code: exception.code,
-              message: exception.message ?? '',
-              details: exception.details),
-    );
-    return productDetailsResponse;
-  }
-
-  @override
-  Future presentCodeRedemptionSheet() {
-    return _skPaymentQueueWrapper.presentCodeRedemptionSheet();
-  }
-}
-
-class _TransactionObserver implements SKTransactionObserverWrapper {
-  final StreamController<List<PurchaseDetails>> purchaseUpdatedController;
-
-  Completer<List<SKPaymentTransactionWrapper>>? _restoreCompleter;
-  List<SKPaymentTransactionWrapper> _restoredTransactions =
-      <SKPaymentTransactionWrapper>[];
-  late String _receiptData;
-
-  _TransactionObserver(this.purchaseUpdatedController);
-
-  Future<List<SKPaymentTransactionWrapper>> getRestoredTransactions(
-      {required SKPaymentQueueWrapper queue, String? applicationUserName}) {
-    _restoreCompleter = Completer();
-    queue.restoreTransactions(applicationUserName: applicationUserName);
-    return _restoreCompleter!.future;
-  }
-
-  void cleanUpRestoredTransactions() {
-    _restoredTransactions.clear();
-    _restoreCompleter = null;
-  }
-
-  void updatedTransactions(
-      {required List<SKPaymentTransactionWrapper> transactions}) async {
-    if (_restoreCompleter != null) {
-      if (_restoredTransactions == null) {
-        _restoredTransactions = [];
-      }
-      _restoredTransactions
-          .addAll(transactions.where((SKPaymentTransactionWrapper wrapper) {
-        return wrapper.transactionState ==
-            SKPaymentTransactionStateWrapper.restored;
-      }).map((SKPaymentTransactionWrapper wrapper) => wrapper));
-    }
-
-    String receiptData = await getReceiptData();
-    purchaseUpdatedController
-        .add(transactions.where((SKPaymentTransactionWrapper wrapper) {
-      return wrapper.transactionState !=
-          SKPaymentTransactionStateWrapper.restored;
-    }).map((SKPaymentTransactionWrapper transaction) {
-      PurchaseDetails purchaseDetails =
-          PurchaseDetails.fromSKTransaction(transaction, receiptData);
-      return purchaseDetails;
-    }).toList());
-  }
-
-  void removedTransactions(
-      {required List<SKPaymentTransactionWrapper> transactions}) {}
-
-  /// Triggered when there is an error while restoring transactions.
-  void restoreCompletedTransactionsFailed({required SKError error}) {
-    _restoreCompleter!.completeError(error);
-  }
-
-  void paymentQueueRestoreCompletedTransactionsFinished() {
-    _restoreCompleter!.complete(_restoredTransactions);
-  }
-
-  bool shouldAddStorePayment(
-      {required SKPaymentWrapper payment, required SKProductWrapper product}) {
-    // In this unified API, we always return true to keep it consistent with the behavior on Google Play.
-    return true;
-  }
-
-  Future<String> getReceiptData() async {
-    try {
-      _receiptData = await SKReceiptManager.retrieveReceiptData();
-    } catch (e) {
-      _receiptData = '';
-    }
-    return _receiptData;
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart
deleted file mode 100644
index 069dad5..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/google_play_connection.dart
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:flutter/services.dart';
-import 'package:flutter/widgets.dart';
-import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart';
-import '../../billing_client_wrappers.dart';
-import '../../in_app_purchase.dart';
-import 'in_app_purchase_connection.dart';
-import 'product_details.dart';
-
-/// An [InAppPurchaseConnection] that wraps Google Play Billing.
-///
-/// This translates various [BillingClient] calls and responses into the
-/// common plugin API.
-class GooglePlayConnection
-    with WidgetsBindingObserver
-    implements InAppPurchaseConnection {
-  GooglePlayConnection._()
-      : billingClient =
-            BillingClient((PurchasesResultWrapper resultWrapper) async {
-          _purchaseUpdatedController
-              .add(await _getPurchaseDetailsFromResult(resultWrapper));
-        }) {
-    if (InAppPurchaseConnection.enablePendingPurchase) {
-      billingClient.enablePendingPurchases();
-    }
-    _readyFuture = _connect();
-    WidgetsBinding.instance!.addObserver(this);
-    _purchaseUpdatedController = StreamController.broadcast();
-    ;
-  }
-
-  /// Returns the singleton instance of the [GooglePlayConnection].
-  static GooglePlayConnection get instance => _getOrCreateInstance();
-  static GooglePlayConnection? _instance;
-
-  Stream<List<PurchaseDetails>> get purchaseUpdatedStream =>
-      _purchaseUpdatedController.stream;
-  static late StreamController<List<PurchaseDetails>>
-      _purchaseUpdatedController;
-
-  /// The [BillingClient] that's abstracted by [GooglePlayConnection].
-  ///
-  /// This field should not be used out of test code.
-  @visibleForTesting
-  late final BillingClient billingClient;
-
-  late Future<void> _readyFuture;
-  static Set<String> _productIdsToConsume = Set<String>();
-
-  @override
-  Future<bool> isAvailable() async {
-    await _readyFuture;
-    return billingClient.isReady();
-  }
-
-  @override
-  Future<bool> buyNonConsumable({required PurchaseParam purchaseParam}) async {
-    BillingResultWrapper billingResultWrapper =
-        await billingClient.launchBillingFlow(
-            sku: purchaseParam.productDetails.id,
-            accountId: purchaseParam.applicationUserName,
-            oldSku: purchaseParam
-                .changeSubscriptionParam?.oldPurchaseDetails.productID,
-            purchaseToken: purchaseParam.changeSubscriptionParam
-                ?.oldPurchaseDetails.verificationData.serverVerificationData,
-            prorationMode:
-                purchaseParam.changeSubscriptionParam?.prorationMode);
-    return billingResultWrapper.responseCode == BillingResponse.ok;
-  }
-
-  @override
-  Future<bool> buyConsumable(
-      {required PurchaseParam purchaseParam, bool autoConsume = true}) {
-    if (autoConsume) {
-      _productIdsToConsume.add(purchaseParam.productDetails.id);
-    }
-    return buyNonConsumable(purchaseParam: purchaseParam);
-  }
-
-  @override
-  Future<BillingResultWrapper> completePurchase(
-      PurchaseDetails purchase) async {
-    if (purchase.billingClientPurchase!.isAcknowledged) {
-      return BillingResultWrapper(responseCode: BillingResponse.ok);
-    }
-    if (purchase.verificationData == null) {
-      throw ArgumentError(
-          'completePurchase unsuccessful. The `purchase.verificationData` is not valid');
-    }
-    return await billingClient
-        .acknowledgePurchase(purchase.verificationData.serverVerificationData);
-  }
-
-  @override
-  Future<BillingResultWrapper> consumePurchase(PurchaseDetails purchase) {
-    if (purchase.verificationData == null) {
-      throw ArgumentError(
-          'consumePurchase unsuccessful. The `purchase.verificationData` is not valid');
-    }
-    return billingClient
-        .consumeAsync(purchase.verificationData.serverVerificationData);
-  }
-
-  @override
-  Future<QueryPurchaseDetailsResponse> queryPastPurchases(
-      {String? applicationUserName}) async {
-    List<PurchasesResultWrapper> responses;
-    PlatformException? exception;
-    try {
-      responses = await Future.wait([
-        billingClient.queryPurchases(SkuType.inapp),
-        billingClient.queryPurchases(SkuType.subs)
-      ]);
-    } on PlatformException catch (e) {
-      exception = e;
-      responses = [
-        PurchasesResultWrapper(
-          responseCode: BillingResponse.error,
-          purchasesList: [],
-          billingResult: BillingResultWrapper(
-            responseCode: BillingResponse.error,
-            debugMessage: e.details.toString(),
-          ),
-        ),
-        PurchasesResultWrapper(
-          responseCode: BillingResponse.error,
-          purchasesList: [],
-          billingResult: BillingResultWrapper(
-            responseCode: BillingResponse.error,
-            debugMessage: e.details.toString(),
-          ),
-        )
-      ];
-    }
-
-    Set errorCodeSet = responses
-        .where((PurchasesResultWrapper response) =>
-            response.responseCode != BillingResponse.ok)
-        .map((PurchasesResultWrapper response) =>
-            response.responseCode.toString())
-        .toSet();
-
-    String errorMessage =
-        errorCodeSet.isNotEmpty ? errorCodeSet.join(', ') : '';
-
-    List<PurchaseDetails> pastPurchases =
-        responses.expand((PurchasesResultWrapper response) {
-      return response.purchasesList;
-    }).map((PurchaseWrapper purchaseWrapper) {
-      return PurchaseDetails.fromPurchase(purchaseWrapper);
-    }).toList();
-
-    IAPError? error;
-    if (exception != null) {
-      error = IAPError(
-          source: IAPSource.GooglePlay,
-          code: exception.code,
-          message: exception.message ?? '',
-          details: exception.details);
-    } else if (errorMessage.isNotEmpty) {
-      error = IAPError(
-          source: IAPSource.GooglePlay,
-          code: kRestoredPurchaseErrorCode,
-          message: errorMessage);
-    }
-
-    return QueryPurchaseDetailsResponse(
-        pastPurchases: pastPurchases, error: error);
-  }
-
-  @override
-  Future<PurchaseVerificationData> refreshPurchaseVerificationData() async {
-    throw UnsupportedError(
-        'The method <refreshPurchaseVerificationData> only works on iOS.');
-  }
-
-  @override
-  Future presentCodeRedemptionSheet() async {
-    throw UnsupportedError(
-        'The method <presentCodeRedemptionSheet> only works on iOS.');
-  }
-
-  /// Resets the connection instance.
-  ///
-  /// The next call to [instance] will create a new instance. Should only be
-  /// used in tests.
-  @visibleForTesting
-  static void reset() => _instance = null;
-
-  static GooglePlayConnection _getOrCreateInstance() {
-    if (_instance != null) {
-      return _instance!;
-    }
-
-    _instance = GooglePlayConnection._();
-    return _instance!;
-  }
-
-  Future<void> _connect() =>
-      billingClient.startConnection(onBillingServiceDisconnected: () {});
-
-  /// Query the product detail list.
-  ///
-  /// This method only returns [ProductDetailsResponse].
-  /// To get detailed Google Play sku list, use [BillingClient.querySkuDetails]
-  /// to get the [SkuDetailsResponseWrapper].
-  Future<ProductDetailsResponse> queryProductDetails(
-      Set<String> identifiers) async {
-    List<SkuDetailsResponseWrapper> responses;
-    PlatformException? exception;
-    try {
-      responses = await Future.wait([
-        billingClient.querySkuDetails(
-            skuType: SkuType.inapp, skusList: identifiers.toList()),
-        billingClient.querySkuDetails(
-            skuType: SkuType.subs, skusList: identifiers.toList())
-      ]);
-    } on PlatformException catch (e) {
-      exception = e;
-      responses = [
-        // ignore: invalid_use_of_visible_for_testing_member
-        SkuDetailsResponseWrapper(
-            billingResult: BillingResultWrapper(
-                responseCode: BillingResponse.error, debugMessage: e.code),
-            skuDetailsList: []),
-        // ignore: invalid_use_of_visible_for_testing_member
-        SkuDetailsResponseWrapper(
-            billingResult: BillingResultWrapper(
-                responseCode: BillingResponse.error, debugMessage: e.code),
-            skuDetailsList: [])
-      ];
-    }
-    List<ProductDetails> productDetailsList =
-        responses.expand((SkuDetailsResponseWrapper response) {
-      return response.skuDetailsList;
-    }).map((SkuDetailsWrapper skuDetailWrapper) {
-      return ProductDetails.fromSkuDetails(skuDetailWrapper);
-    }).toList();
-
-    Set<String> successIDS = productDetailsList
-        .map((ProductDetails productDetails) => productDetails.id)
-        .toSet();
-    List<String> notFoundIDS = identifiers.difference(successIDS).toList();
-    return ProductDetailsResponse(
-        productDetails: productDetailsList,
-        notFoundIDs: notFoundIDS,
-        error: exception == null
-            ? null
-            : IAPError(
-                source: IAPSource.GooglePlay,
-                code: exception.code,
-                message: exception.message ?? '',
-                details: exception.details));
-  }
-
-  static Future<List<PurchaseDetails>> _getPurchaseDetailsFromResult(
-      PurchasesResultWrapper resultWrapper) async {
-    IAPError? error;
-    if (resultWrapper.responseCode != BillingResponse.ok) {
-      error = IAPError(
-        source: IAPSource.GooglePlay,
-        code: kPurchaseErrorCode,
-        message: resultWrapper.responseCode.toString(),
-        details: resultWrapper.billingResult.debugMessage,
-      );
-    }
-    final List<Future<PurchaseDetails>> purchases =
-        resultWrapper.purchasesList.map((PurchaseWrapper purchase) {
-      return _maybeAutoConsumePurchase(
-          PurchaseDetails.fromPurchase(purchase)..error = error);
-    }).toList();
-    if (purchases.isNotEmpty) {
-      return Future.wait(purchases);
-    } else {
-      return [
-        PurchaseDetails(
-            purchaseID: '',
-            productID: '',
-            transactionDate: null,
-            verificationData: PurchaseVerificationData(
-                localVerificationData: '',
-                serverVerificationData: '',
-                source: IAPSource.GooglePlay))
-          ..status = PurchaseStatus.error
-          ..error = error
-      ];
-    }
-  }
-
-  static Future<PurchaseDetails> _maybeAutoConsumePurchase(
-      PurchaseDetails purchaseDetails) async {
-    if (!(purchaseDetails.status == PurchaseStatus.purchased &&
-        _productIdsToConsume.contains(purchaseDetails.productID))) {
-      return purchaseDetails;
-    }
-
-    final BillingResultWrapper billingResult =
-        await instance.consumePurchase(purchaseDetails);
-    final BillingResponse consumedResponse = billingResult.responseCode;
-    if (consumedResponse != BillingResponse.ok) {
-      purchaseDetails.status = PurchaseStatus.error;
-      purchaseDetails.error = IAPError(
-        source: IAPSource.GooglePlay,
-        code: kConsumptionFailedErrorCode,
-        message: consumedResponse.toString(),
-        details: billingResult.debugMessage,
-      );
-    }
-    _productIdsToConsume.remove(purchaseDetails.productID);
-
-    return purchaseDetails;
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart
deleted file mode 100644
index c333478..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart
+++ /dev/null
@@ -1,308 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:io';
-import 'app_store_connection.dart';
-import 'google_play_connection.dart';
-import 'product_details.dart';
-import 'package:in_app_purchase/billing_client_wrappers.dart';
-import './purchase_details.dart';
-
-export 'package:in_app_purchase/billing_client_wrappers.dart';
-
-/// Basic API for making in app purchases across multiple platforms.
-///
-/// This is a generic abstraction built from `billing_client_wrapers` and
-/// `store_kit_wrappers`. Either library can be used for their respective
-/// platform instead of this.
-abstract class InAppPurchaseConnection {
-  /// Listen to this broadcast stream to get real time update for purchases.
-  ///
-  /// This stream will never close as long as the app is active.
-  ///
-  /// Purchase updates can happen in several situations:
-  /// * When a purchase is triggered by user in the app.
-  /// * When a purchase is triggered by user from App Store or Google Play.
-  /// * If a purchase is not completed ([completePurchase] is not called on the
-  ///   purchase object) from the last app session. Purchase updates will happen
-  ///   when a new app session starts instead.
-  ///
-  /// IMPORTANT! You must subscribe to this stream as soon as your app launches,
-  /// preferably before returning your main App Widget in main(). Otherwise you
-  /// will miss purchase updated made before this stream is subscribed to.
-  ///
-  /// We also recommend listening to the stream with one subscription at a given
-  /// time. If you choose to have multiple subscription at the same time, you
-  /// should be careful at the fact that each subscription will receive all the
-  /// events after they start to listen.
-  Stream<List<PurchaseDetails>> get purchaseUpdatedStream => _getStream();
-
-  Stream<List<PurchaseDetails>>? _purchaseUpdatedStream;
-
-  Stream<List<PurchaseDetails>> _getStream() {
-    if (_purchaseUpdatedStream != null) {
-      return _purchaseUpdatedStream!;
-    }
-
-    if (Platform.isAndroid) {
-      _purchaseUpdatedStream =
-          GooglePlayConnection.instance.purchaseUpdatedStream;
-    } else if (Platform.isIOS) {
-      _purchaseUpdatedStream =
-          AppStoreConnection.instance.purchaseUpdatedStream;
-    } else {
-      throw UnsupportedError(
-          'InAppPurchase plugin only works on Android and iOS.');
-    }
-    return _purchaseUpdatedStream!;
-  }
-
-  /// Whether pending purchase is enabled.
-  ///
-  /// See also [enablePendingPurchases] for more on pending purchases.
-  static bool get enablePendingPurchase => _enablePendingPurchase;
-  static bool _enablePendingPurchase = false;
-
-  /// Returns true if the payment platform is ready and available.
-  Future<bool> isAvailable();
-
-  /// Enable the [InAppPurchaseConnection] to handle pending purchases.
-  ///
-  /// This method is required to be called when initialize the application.
-  /// It is to acknowledge your application has been updated to support pending purchases.
-  /// See [Support pending transactions](https://developer.android.com/google/play/billing/billing_library_overview#pending)
-  /// for more details.
-  /// Failure to call this method before access [instance] will throw an exception.
-  ///
-  /// It is an no-op on iOS.
-  static void enablePendingPurchases() {
-    _enablePendingPurchase = true;
-  }
-
-  /// Query product details for the given set of IDs.
-  ///
-  /// The [identifiers] need to exactly match existing configured product
-  /// identifiers in the underlying payment platform, whether that's [App Store
-  /// Connect](https://appstoreconnect.apple.com/) or [Google Play
-  /// Console](https://play.google.com/).
-  ///
-  /// See the [example readme](../../../../example/README.md) for steps on how
-  /// to initialize products on both payment platforms.
-  Future<ProductDetailsResponse> queryProductDetails(Set<String> identifiers);
-
-  /// Buy a non consumable product or subscription.
-  ///
-  /// Non consumable items can only be bought once. For example, a purchase that
-  /// unlocks a special content in your app. Subscriptions are also non
-  /// consumable products.
-  ///
-  /// You always need to restore all the non consumable products for user when
-  /// they switch their phones.
-  ///
-  /// This method does not return the result of the purchase. Instead, after
-  /// triggering this method, purchase updates will be sent to
-  /// [purchaseUpdatedStream]. You should [Stream.listen] to
-  /// [purchaseUpdatedStream] to get [PurchaseDetails] objects in different
-  /// [PurchaseDetails.status] and update your UI accordingly. When the
-  /// [PurchaseDetails.status] is [PurchaseStatus.purchased] or
-  /// [PurchaseStatus.error], you should deliver the content or handle the
-  /// error, then call [completePurchase] to finish the purchasing process.
-  ///
-  /// This method does return whether or not the purchase request was initially
-  /// sent successfully.
-  ///
-  /// Consumable items are defined differently by the different underlying
-  /// payment platforms, and there's no way to query for whether or not the
-  /// [ProductDetail] is a consumable at runtime. On iOS, products are defined
-  /// as non consumable items in the [App Store
-  /// Connect](https://appstoreconnect.apple.com/). [Google Play
-  /// Console](https://play.google.com/) products are considered consumable if
-  /// and when they are actively consumed manually.
-  ///
-  /// You can find more details on testing payments on iOS
-  /// [here](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/ShowUI.html#//apple_ref/doc/uid/TP40008267-CH3-SW11).
-  /// You can find more details on testing payments on Android
-  /// [here](https://developer.android.com/google/play/billing/billing_testing).
-  ///
-  /// See also:
-  ///
-  ///  * [buyConsumable], for buying a consumable product.
-  ///  * [queryPastPurchases], for restoring non consumable products.
-  ///
-  /// Calling this method for consumable items will cause unwanted behaviors!
-  Future<bool> buyNonConsumable({required PurchaseParam purchaseParam});
-
-  /// Buy a consumable product.
-  ///
-  /// Consumable items can be "consumed" to mark that they've been used and then
-  /// bought additional times. For example, a health potion.
-  ///
-  /// To restore consumable purchases across devices, you should keep track of
-  /// those purchase on your own server and restore the purchase for your users.
-  /// Consumed products are no longer considered to be "owned" by payment
-  /// platforms and will not be delivered by calling [queryPastPurchases].
-  ///
-  /// Consumable items are defined differently by the different underlying
-  /// payment platforms, and there's no way to query for whether or not the
-  /// [ProductDetail] is a consumable at runtime. On iOS, products are defined
-  /// as consumable items in the [App Store
-  /// Connect](https://appstoreconnect.apple.com/). [Google Play
-  /// Console](https://play.google.com/) products are considered consumable if
-  /// and when they are actively consumed manually.
-  ///
-  /// `autoConsume` is provided as a utility for Android only. It's meaningless
-  /// on iOS because the App Store automatically considers all potentially
-  /// consumable purchases "consumed" once the initial transaction is complete.
-  /// `autoConsume` is `true` by default, and we will call [consumePurchase]
-  /// after a successful purchase for you so that Google Play considers a
-  /// purchase consumed after the initial transaction, like iOS. If you'd like
-  /// to manually consume purchases in Play, you should set it to `false` and
-  /// manually call [consumePurchase] instead. Failing to consume a purchase
-  /// will cause user never be able to buy the same item again. Manually setting
-  /// this to `false` on iOS will throw an `Exception`.
-  ///
-  /// This method does not return the result of the purchase. Instead, after
-  /// triggering this method, purchase updates will be sent to
-  /// [purchaseUpdatedStream]. You should [Stream.listen] to
-  /// [purchaseUpdatedStream] to get [PurchaseDetails] objects in different
-  /// [PurchaseDetails.status] and update your UI accordingly. When the
-  /// [PurchaseDetails.status] is [PurchaseStatus.purchased] or
-  /// [PurchaseStatus.error], you should deliver the content or handle the
-  /// error, then call [completePurchase] to finish the purchasing process.
-  ///
-  /// This method does return whether or not the purchase request was initially
-  /// sent succesfully.
-  ///
-  /// See also:
-  ///
-  ///  * [buyNonConsumable], for buying a non consumable product or
-  ///    subscription.
-  ///  * [queryPastPurchases], for restoring non consumable products.
-  ///  * [consumePurchase], for manually consuming products on Android.
-  ///
-  /// Calling this method for non consumable items will cause unwanted
-  /// behaviors!
-  Future<bool> buyConsumable(
-      {required PurchaseParam purchaseParam, bool autoConsume = true});
-
-  /// Mark that purchased content has been delivered to the
-  /// user.
-  ///
-  /// You are responsible for completing every [PurchaseDetails] whose
-  /// [PurchaseDetails.status] is [PurchaseStatus.purchased]. Additionally on iOS,
-  /// the purchase needs to be completed if the [PurchaseDetails.status] is [PurchaseStatus.error].
-  /// Completing a [PurchaseStatus.pending] purchase will cause an exception.
-  /// For convenience, [PurchaseDetails.pendingCompletePurchase] indicates if a purchase is pending for completion.
-  ///
-  /// The method returns a [BillingResultWrapper] to indicate a detailed status of the complete process.
-  /// If the result contains [BillingResponse.error] or [BillingResponse.serviceUnavailable], the developer should try
-  /// to complete the purchase via this method again, or retry the [completePurchase] it at a later time.
-  /// If the result indicates other errors, there might be some issue with
-  /// the app's code. The developer is responsible to fix the issue.
-  ///
-  /// Warning! Failure to call this method and get a successful response within 3 days of the purchase will result a refund on Android.
-  /// The [consumePurchase] acts as an implicit [completePurchase] on Android.
-  Future<BillingResultWrapper> completePurchase(PurchaseDetails purchase);
-
-  /// (Play only) Mark that the user has consumed a product.
-  ///
-  /// You are responsible for consuming all consumable purchases once they are
-  /// delivered. The user won't be able to buy the same product again until the
-  /// purchase of the product is consumed.
-  ///
-  /// This throws an [UnsupportedError] on iOS.
-  Future<BillingResultWrapper> consumePurchase(PurchaseDetails purchase);
-
-  /// Query all previous purchases.
-  ///
-  /// The `applicationUserName` should match whatever was sent in the initial
-  /// `PurchaseParam`, if anything. If no `applicationUserName` was specified in the initial
-  /// `PurchaseParam`, use `null`.
-  ///
-  /// This does not return consumed products. If you want to restore unused
-  /// consumable products, you need to persist consumable product information
-  /// for your user on your own server.
-  ///
-  /// See also:
-  ///
-  ///  * [refreshPurchaseVerificationData], for reloading failed
-  ///    [PurchaseDetails.verificationData].
-  Future<QueryPurchaseDetailsResponse> queryPastPurchases(
-      {String? applicationUserName});
-
-  /// (App Store only) retry loading purchase data after an initial failure.
-  ///
-  /// If no results, a `null` value is returned.
-  ///
-  /// Throws an [UnsupportedError] on Android.
-  Future<PurchaseVerificationData?> refreshPurchaseVerificationData();
-
-  /// (App Store only) present Code Redemption Sheet.
-  /// Available on devices running iOS 14 and iPadOS 14 and later.
-  ///
-  /// Throws an [UnsupportedError] on Android.
-  Future<void> presentCodeRedemptionSheet();
-
-  /// The [InAppPurchaseConnection] implemented for this platform.
-  ///
-  /// Throws an [UnsupportedError] when accessed on a platform other than
-  /// Android or iOS.
-  static InAppPurchaseConnection get instance => _getOrCreateInstance();
-  static InAppPurchaseConnection? _instance;
-
-  static InAppPurchaseConnection _getOrCreateInstance() {
-    if (_instance != null) {
-      return _instance!;
-    }
-
-    if (Platform.isAndroid) {
-      _instance = GooglePlayConnection.instance;
-    } else if (Platform.isIOS) {
-      _instance = AppStoreConnection.instance;
-    } else {
-      throw UnsupportedError(
-          'InAppPurchase plugin only works on Android and iOS.');
-    }
-
-    return _instance!;
-  }
-}
-
-/// Which platform the request is on.
-enum IAPSource {
-  /// Google's Play Store.
-  GooglePlay,
-
-  /// Apple's App Store.
-  AppStore
-}
-
-/// Captures an error from the underlying purchase platform.
-///
-/// The error can happen during the purchase, restoring a purchase, or querying product.
-/// Errors from restoring a purchase are not indicative of any errors during the original purchase.
-/// See also:
-/// * [ProductDetailsResponse] for error when querying product details.
-/// * [PurchaseDetails] for error happened in purchase.
-class IAPError {
-  /// Creates a new IAP error object with the given error details.
-  IAPError(
-      {required this.source,
-      required this.code,
-      required this.message,
-      this.details});
-
-  /// Which source is the error on.
-  final IAPSource source;
-
-  /// The error code.
-  final String code;
-
-  /// A human-readable error message.
-  final String message;
-
-  /// Error details, possibly null.
-  final dynamic details;
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/product_details.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/product_details.dart
deleted file mode 100644
index 4ba6130..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/product_details.dart
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:in_app_purchase/store_kit_wrappers.dart';
-import 'package:in_app_purchase/billing_client_wrappers.dart';
-import 'in_app_purchase_connection.dart';
-
-/// The class represents the information of a product.
-///
-/// This class unifies the BillingClient's [SkuDetailsWrapper] and StoreKit's [SKProductWrapper]. You can use the common attributes in
-/// This class for simple operations. If you would like to see the detailed representation of the product, instead,  use [skuDetails] on Android and [skProduct] on iOS.
-class ProductDetails {
-  /// Creates a new product details object with the provided details.
-  ProductDetails(
-      {required this.id,
-      required this.title,
-      required this.description,
-      required this.price,
-      required this.rawPrice,
-      required this.currencyCode,
-      this.skProduct,
-      this.skuDetail});
-
-  /// The identifier of the product, specified in App Store Connect or Sku in Google Play console.
-  final String id;
-
-  /// The title of the product, specified in the App Store Connect or Sku in Google Play console based on the platform.
-  final String title;
-
-  /// The description of the product, specified in the App Store Connect or Sku in Google Play console based on the platform.
-  final String description;
-
-  /// The price of the product, specified in the App Store Connect or Sku in Google Play console based on the platform.
-  /// Formatted with currency symbol ("$0.99").
-  final String price;
-
-  /// The unformatted price of the product, specified in the App Store Connect or Sku in Google Play console based on the platform.
-  /// The currency unit for this value can be found in the [currencyCode] property.
-  /// The value always describes full units of the currency. (e.g. 2.45 in the case of $2.45)
-  final double rawPrice;
-
-  /// The currency code for the price of the product.
-  /// Based on the price specified in the App Store Connect or Sku in Google Play console based on the platform.
-  final String currencyCode;
-
-  /// Points back to the `StoreKits`'s [SKProductWrapper] object that generated this [ProductDetails] object.
-  ///
-  /// This is `null` on Android.
-  final SKProductWrapper? skProduct;
-
-  /// Points back to the `BillingClient1`'s [SkuDetailsWrapper] object that generated this [ProductDetails] object.
-  ///
-  /// This is `null` on iOS.
-  final SkuDetailsWrapper? skuDetail;
-
-  /// Generate a [ProductDetails] object based on an iOS [SKProductWrapper] object.
-  ProductDetails.fromSKProduct(SKProductWrapper product)
-      : this.id = product.productIdentifier,
-        this.title = product.localizedTitle,
-        this.description = product.localizedDescription,
-        this.price = product.priceLocale.currencySymbol + product.price,
-        this.rawPrice = double.parse(product.price),
-        this.currencyCode = product.priceLocale.currencyCode,
-        this.skProduct = product,
-        this.skuDetail = null;
-
-  /// Generate a [ProductDetails] object based on an Android [SkuDetailsWrapper] object.
-  ProductDetails.fromSkuDetails(SkuDetailsWrapper skuDetails)
-      : this.id = skuDetails.sku,
-        this.title = skuDetails.title,
-        this.description = skuDetails.description,
-        this.price = skuDetails.price,
-        this.rawPrice = ((skuDetails.priceAmountMicros) / 1000000.0).toDouble(),
-        this.currencyCode = skuDetails.priceCurrencyCode,
-        this.skProduct = null,
-        this.skuDetail = skuDetails;
-}
-
-/// The response returned by [InAppPurchaseConnection.queryProductDetails].
-///
-/// A list of [ProductDetails] can be obtained from the this response.
-class ProductDetailsResponse {
-  /// Creates a new [ProductDetailsResponse] with the provided response details.
-  ProductDetailsResponse(
-      {required this.productDetails, required this.notFoundIDs, this.error});
-
-  /// Each [ProductDetails] uniquely matches one valid identifier in [identifiers] of [InAppPurchaseConnection.queryProductDetails].
-  final List<ProductDetails> productDetails;
-
-  /// The list of identifiers that are in the `identifiers` of [InAppPurchaseConnection.queryProductDetails] but failed to be fetched.
-  ///
-  /// There's multiple platform-specific reasons that product information could fail to be fetched,
-  /// ranging from products not being correctly configured in the storefront to the queried IDs not existing.
-  final List<String> notFoundIDs;
-
-  /// A caught platform exception thrown while querying the purchases.
-  ///
-  /// The value is `null` if there is no error.
-  ///
-  /// It's possible for this to be null but for there still to be notFoundIds in cases where the request itself was a success but the
-  /// requested IDs could not be found.
-  final IAPError? error;
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart
deleted file mode 100644
index fc286d4..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/purchase_details.dart
+++ /dev/null
@@ -1,310 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:in_app_purchase/src/billing_client_wrappers/enum_converters.dart';
-import 'package:in_app_purchase/src/billing_client_wrappers/purchase_wrapper.dart';
-import 'package:in_app_purchase/src/store_kit_wrappers/enum_converters.dart';
-import 'package:in_app_purchase/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart';
-import './in_app_purchase_connection.dart';
-import './product_details.dart';
-
-/// [IAPError.code] code for failed purchases.
-final String kPurchaseErrorCode = 'purchase_error';
-
-/// [IAPError.code] code used when a query for previouys transaction has failed.
-final String kRestoredPurchaseErrorCode = 'restore_transactions_failed';
-
-/// [IAPError.code] code used when a consuming a purchased item fails.
-final String kConsumptionFailedErrorCode = 'consume_purchase_failed';
-
-final String _kPlatformIOS = 'ios';
-final String _kPlatformAndroid = 'android';
-
-/// Represents the data that is used to verify purchases.
-///
-/// The property [source] helps you to determine the method to verify purchases.
-/// Different source of purchase has different methods of verifying purchases.
-///
-/// Both platforms have 2 ways to verify purchase data. You can either choose to verify the data locally using [localVerificationData]
-/// or verify the data using your own server with [serverVerificationData].
-///
-/// For details on how to verify your purchase on iOS,
-/// you can refer to Apple's document about [`About Receipt Validation`](https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Introduction.html#//apple_ref/doc/uid/TP40010573-CH105-SW1).
-///
-/// On Android, all purchase information should also be verified manually. See [`Verify a purchase`](https://developer.android.com/google/play/billing/billing_library_overview#Verify).
-///
-/// It is preferable to verify purchases using a server with [serverVerificationData].
-///
-/// If the platform is iOS, it is possible the data can be null or your validation of this data turns out invalid. When this happens,
-/// Call [InAppPurchaseConnection.refreshPurchaseVerificationData] to get a new [PurchaseVerificationData] object. And then you can
-/// validate the receipt data again using one of the methods mentioned in [`Receipt Validation`](https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Introduction.html#//apple_ref/doc/uid/TP40010573-CH105-SW1).
-///
-/// You should never use any purchase data until verified.
-class PurchaseVerificationData {
-  /// The data used for local verification.
-  ///
-  /// If the [source] is [IAPSource.AppStore], this data is a based64 encoded string. The structure of the payload is defined using ASN.1.
-  /// If the [source] is [IAPSource.GooglePlay], this data is a JSON String.
-  final String localVerificationData;
-
-  /// The data used for server verification.
-  ///
-  /// If the platform is iOS, this data is identical to [localVerificationData].
-  final String serverVerificationData;
-
-  /// Indicates the source of the purchase.
-  final IAPSource source;
-
-  /// Creates a [PurchaseVerificationData] object with the provided information.
-  PurchaseVerificationData(
-      {required this.localVerificationData,
-      required this.serverVerificationData,
-      required this.source});
-}
-
-/// Status for a [PurchaseDetails].
-///
-/// This is the type for [PurchaseDetails.status].
-enum PurchaseStatus {
-  /// The purchase process is pending.
-  ///
-  /// You can update UI to let your users know the purchase is pending.
-  pending,
-
-  /// The purchase is finished and successful.
-  ///
-  /// Update your UI to indicate the purchase is finished and deliver the product.
-  /// On Android, the google play store is handling the purchase, so we set the status to
-  /// `purchased` as long as we can successfully launch play store purchase flow.
-  purchased,
-
-  /// Some error occurred in the purchase. The purchasing process if aborted.
-  error
-}
-
-/// The parameter object for generating a purchase.
-class PurchaseParam {
-  /// Creates a new purchase parameter object with the given data.
-  PurchaseParam(
-      {required this.productDetails,
-      this.applicationUserName,
-      this.sandboxTesting = false,
-      this.simulatesAskToBuyInSandbox = false,
-      this.changeSubscriptionParam});
-
-  /// The product to create payment for.
-  ///
-  /// It has to match one of the valid [ProductDetails] objects that you get from [ProductDetailsResponse] after calling [InAppPurchaseConnection.queryProductDetails].
-  final ProductDetails productDetails;
-
-  /// An opaque id for the user's account that's unique to your app. (Optional)
-  ///
-  /// Used to help the store detect irregular activity.
-  /// Do not pass in a clear text, your developer ID, the user’s Apple ID, or the
-  /// user's Google ID for this field.
-  /// For example, you can use a one-way hash of the user’s account name on your server.
-  final String? applicationUserName;
-
-  /// @deprecated Use [simulatesAskToBuyInSandbox] instead.
-  ///
-  /// Only available on iOS, set it to `true` to produce an "ask to buy" flow for this payment in the sandbox.
-  ///
-  /// See also [SKPaymentWrapper.simulatesAskToBuyInSandbox].
-  @deprecated
-  final bool sandboxTesting;
-
-  /// Only available on iOS, set it to `true` to produce an "ask to buy" flow for this payment in the sandbox.
-  ///
-  /// See also [SKPaymentWrapper.simulatesAskToBuyInSandbox].
-  final bool simulatesAskToBuyInSandbox;
-
-  /// The 'changeSubscriptionParam' is only available on Android, for upgrading or
-  /// downgrading an existing subscription.
-  ///
-  /// This does not require on iOS since Apple provides a way to group related subscriptions
-  /// together in iTunesConnect. So when a subscription upgrade or downgrade is requested,
-  /// Apple finds the old subscription details from the group and handle it automatically.
-  final ChangeSubscriptionParam? changeSubscriptionParam;
-}
-
-/// This parameter object which is only applicable on Android for upgrading or downgrading an existing subscription.
-///
-/// This does not require on iOS since iTunesConnect provides a subscription grouping mechanism.
-/// Each subscription you offer must be assigned to a subscription group.
-/// So the developers can group related subscriptions together to prevent users from
-/// accidentally purchasing multiple subscriptions.
-///
-/// Please refer to the 'Creating a Subscription Group' sections of [Apple's subscription guide](https://developer.apple.com/app-store/subscriptions/)
-class ChangeSubscriptionParam {
-  /// Creates a new change subscription param object with given data
-  ChangeSubscriptionParam(
-      {required this.oldPurchaseDetails, this.prorationMode});
-
-  /// The purchase object of the existing subscription that the user needs to
-  /// upgrade/downgrade from.
-  final PurchaseDetails oldPurchaseDetails;
-
-  /// The proration mode.
-  ///
-  /// This is an optional parameter that indicates how to handle the existing
-  /// subscription when the new subscription comes into effect.
-  final ProrationMode? prorationMode;
-}
-
-/// Represents the transaction details of a purchase.
-///
-/// This class unifies the BillingClient's [PurchaseWrapper] and StoreKit's [SKPaymentTransactionWrapper]. You can use the common attributes in
-/// This class for simple operations. If you would like to see the detailed representation of the product, instead,  use [PurchaseWrapper] on Android and [SKPaymentTransactionWrapper] on iOS.
-class PurchaseDetails {
-  /// A unique identifier of the purchase.
-  ///
-  /// The `value` is null on iOS if it is not a successful purchase.
-  final String? purchaseID;
-
-  /// The product identifier of the purchase.
-  final String productID;
-
-  /// The verification data of the purchase.
-  ///
-  /// Use this to verify the purchase. See [PurchaseVerificationData] for
-  /// details on how to verify purchase use this data. You should never use any
-  /// purchase data until verified.
-  ///
-  /// On iOS, [InAppPurchaseConnection.refreshPurchaseVerificationData] can be used to get a new
-  /// [PurchaseVerificationData] object for further validation.
-  final PurchaseVerificationData verificationData;
-
-  /// The timestamp of the transaction.
-  ///
-  /// Milliseconds since epoch.
-  ///
-  /// The value is `null` if [status] is not [PurchaseStatus.purchased].
-  final String? transactionDate;
-
-  /// The status that this [PurchaseDetails] is currently on.
-  PurchaseStatus get status => _status;
-  set status(PurchaseStatus status) {
-    if (_platform == _kPlatformIOS) {
-      if (status == PurchaseStatus.purchased ||
-          status == PurchaseStatus.error) {
-        _pendingCompletePurchase = true;
-      }
-    }
-    if (_platform == _kPlatformAndroid) {
-      if (status == PurchaseStatus.purchased) {
-        _pendingCompletePurchase = true;
-      }
-    }
-    _status = status;
-  }
-
-  late PurchaseStatus _status;
-
-  /// The error details when the [status] is [PurchaseStatus.error].
-  ///
-  /// The value is `null` if [status] is not [PurchaseStatus.error].
-  IAPError? error;
-
-  /// Points back to the `StoreKits`'s [SKPaymentTransactionWrapper] object that generated this [PurchaseDetails] object.
-  ///
-  /// This is `null` on Android.
-  final SKPaymentTransactionWrapper? skPaymentTransaction;
-
-  /// Points back to the `BillingClient`'s [PurchaseWrapper] object that generated this [PurchaseDetails] object.
-  ///
-  /// This is `null` on iOS.
-  final PurchaseWrapper? billingClientPurchase;
-
-  /// The developer has to call [InAppPurchaseConnection.completePurchase] if the value is `true`
-  /// and the product has been delivered to the user.
-  ///
-  /// The initial value is `false`.
-  /// * See also [InAppPurchaseConnection.completePurchase] for more details on completing purchases.
-  bool get pendingCompletePurchase => _pendingCompletePurchase;
-  bool _pendingCompletePurchase = false;
-
-  // The platform that the object is created on.
-  //
-  // The value is either '_kPlatformIOS' or '_kPlatformAndroid'.
-  String? _platform;
-
-  /// Creates a new PurchaseDetails object with the provided data.
-  PurchaseDetails({
-    this.purchaseID,
-    required this.productID,
-    required this.verificationData,
-    required this.transactionDate,
-    this.skPaymentTransaction,
-    this.billingClientPurchase,
-  });
-
-  /// Generate a [PurchaseDetails] object based on an iOS [SKTransactionWrapper] object.
-  PurchaseDetails.fromSKTransaction(
-      SKPaymentTransactionWrapper transaction, String base64EncodedReceipt)
-      : this.purchaseID = transaction.transactionIdentifier,
-        this.productID = transaction.payment.productIdentifier,
-        this.verificationData = PurchaseVerificationData(
-            localVerificationData: base64EncodedReceipt,
-            serverVerificationData: base64EncodedReceipt,
-            source: IAPSource.AppStore),
-        this.transactionDate = transaction.transactionTimeStamp != null
-            ? (transaction.transactionTimeStamp! * 1000).toInt().toString()
-            : null,
-        this.skPaymentTransaction = transaction,
-        this.billingClientPurchase = null,
-        _platform = _kPlatformIOS {
-    status = SKTransactionStatusConverter()
-        .toPurchaseStatus(transaction.transactionState);
-    if (status == PurchaseStatus.error) {
-      error = IAPError(
-        source: IAPSource.AppStore,
-        code: kPurchaseErrorCode,
-        message: transaction.error?.domain ?? '',
-        details: transaction.error?.userInfo,
-      );
-    }
-  }
-
-  /// Generate a [PurchaseDetails] object based on an Android [Purchase] object.
-  PurchaseDetails.fromPurchase(PurchaseWrapper purchase)
-      : this.purchaseID = purchase.orderId,
-        this.productID = purchase.sku,
-        this.verificationData = PurchaseVerificationData(
-            localVerificationData: purchase.originalJson,
-            serverVerificationData: purchase.purchaseToken,
-            source: IAPSource.GooglePlay),
-        this.transactionDate = purchase.purchaseTime.toString(),
-        this.skPaymentTransaction = null,
-        this.billingClientPurchase = purchase,
-        _platform = _kPlatformAndroid {
-    status = PurchaseStateConverter().toPurchaseStatus(purchase.purchaseState);
-    if (status == PurchaseStatus.error) {
-      error = IAPError(
-        source: IAPSource.GooglePlay,
-        code: kPurchaseErrorCode,
-        message: '',
-      );
-    }
-  }
-}
-
-/// The response object for fetching the past purchases.
-///
-/// An instance of this class is returned in [InAppPurchaseConnection.queryPastPurchases].
-class QueryPurchaseDetailsResponse {
-  /// Creates a new [QueryPurchaseDetailsResponse] object with the provider information.
-  QueryPurchaseDetailsResponse({required this.pastPurchases, this.error});
-
-  /// A list of successfully fetched past purchases.
-  ///
-  /// If there are no past purchases, or there is an [error] fetching past purchases,
-  /// this variable is an empty List.
-  /// You should verify the purchase data using [PurchaseDetails.verificationData] before using the [PurchaseDetails] object.
-  final List<PurchaseDetails> pastPurchases;
-
-  /// The error when fetching past purchases.
-  ///
-  /// If the fetch is successful, the value is `null`.
-  final IAPError? error;
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/README.md b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/README.md
deleted file mode 100644
index bd8e5b5..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# store_kit_wrappers
-
-This exposes Dart endpoints through to the
-[StoreKit](https://developer.apple.com/documentation/storekit) APIs. Can be used
-as an alternative to [in_app_purchase](../in_app_purchase/README.md).
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart
deleted file mode 100644
index 5a44389..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.dart
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:in_app_purchase/store_kit_wrappers.dart';
-import 'package:json_annotation/json_annotation.dart';
-import 'package:in_app_purchase/in_app_purchase.dart';
-
-part 'enum_converters.g.dart';
-
-/// Serializer for [SKPaymentTransactionStateWrapper].
-///
-/// Use these in `@JsonSerializable()` classes by annotating them with
-/// `@SKTransactionStatusConverter()`.
-class SKTransactionStatusConverter
-    implements JsonConverter<SKPaymentTransactionStateWrapper, int?> {
-  /// Default const constructor.
-  const SKTransactionStatusConverter();
-
-  @override
-  SKPaymentTransactionStateWrapper fromJson(int? json) {
-    if (json == null) {
-      return SKPaymentTransactionStateWrapper.unspecified;
-    }
-    return _$enumDecode<SKPaymentTransactionStateWrapper, dynamic>(
-        _$SKPaymentTransactionStateWrapperEnumMap
-            .cast<SKPaymentTransactionStateWrapper, dynamic>(),
-        json);
-  }
-
-  /// Converts an [SKPaymentTransactionStateWrapper] to a [PurchaseStatus].
-  PurchaseStatus toPurchaseStatus(SKPaymentTransactionStateWrapper object) {
-    switch (object) {
-      case SKPaymentTransactionStateWrapper.purchasing:
-      case SKPaymentTransactionStateWrapper.deferred:
-        return PurchaseStatus.pending;
-      case SKPaymentTransactionStateWrapper.purchased:
-      case SKPaymentTransactionStateWrapper.restored:
-        return PurchaseStatus.purchased;
-      case SKPaymentTransactionStateWrapper.failed:
-      case SKPaymentTransactionStateWrapper.unspecified:
-        return PurchaseStatus.error;
-    }
-  }
-
-  @override
-  int toJson(SKPaymentTransactionStateWrapper object) =>
-      _$SKPaymentTransactionStateWrapperEnumMap[object]!;
-}
-
-/// Serializer for [SKSubscriptionPeriodUnit].
-///
-/// Use these in `@JsonSerializable()` classes by annotating them with
-/// `@SKSubscriptionPeriodUnitConverter()`.
-class SKSubscriptionPeriodUnitConverter
-    implements JsonConverter<SKSubscriptionPeriodUnit, int?> {
-  /// Default const constructor.
-  const SKSubscriptionPeriodUnitConverter();
-
-  @override
-  SKSubscriptionPeriodUnit fromJson(int? json) {
-    if (json == null) {
-      return SKSubscriptionPeriodUnit.day;
-    }
-    return _$enumDecode<SKSubscriptionPeriodUnit, dynamic>(
-        _$SKSubscriptionPeriodUnitEnumMap
-            .cast<SKSubscriptionPeriodUnit, dynamic>(),
-        json);
-  }
-
-  @override
-  int toJson(SKSubscriptionPeriodUnit object) =>
-      _$SKSubscriptionPeriodUnitEnumMap[object]!;
-}
-
-/// Serializer for [SKProductDiscountPaymentMode].
-///
-/// Use these in `@JsonSerializable()` classes by annotating them with
-/// `@SKProductDiscountPaymentModeConverter()`.
-class SKProductDiscountPaymentModeConverter
-    implements JsonConverter<SKProductDiscountPaymentMode, int?> {
-  /// Default const constructor.
-  const SKProductDiscountPaymentModeConverter();
-
-  @override
-  SKProductDiscountPaymentMode fromJson(int? json) {
-    if (json == null) {
-      return SKProductDiscountPaymentMode.payAsYouGo;
-    }
-    return _$enumDecode<SKProductDiscountPaymentMode, dynamic>(
-        _$SKProductDiscountPaymentModeEnumMap
-            .cast<SKProductDiscountPaymentMode, dynamic>(),
-        json);
-  }
-
-  @override
-  int toJson(SKProductDiscountPaymentMode object) =>
-      _$SKProductDiscountPaymentModeEnumMap[object]!;
-}
-
-// Define a class so we generate serializer helper methods for the enums
-@JsonSerializable()
-class _SerializedEnums {
-  late SKPaymentTransactionStateWrapper response;
-  late SKSubscriptionPeriodUnit unit;
-  late SKProductDiscountPaymentMode discountPaymentMode;
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart
deleted file mode 100644
index b003f43..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/enum_converters.g.dart
+++ /dev/null
@@ -1,73 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'enum_converters.dart';
-
-// **************************************************************************
-// JsonSerializableGenerator
-// **************************************************************************
-
-_SerializedEnums _$_SerializedEnumsFromJson(Map json) {
-  return _SerializedEnums()
-    ..response = _$enumDecode(
-        _$SKPaymentTransactionStateWrapperEnumMap, json['response'])
-    ..unit = _$enumDecode(_$SKSubscriptionPeriodUnitEnumMap, json['unit'])
-    ..discountPaymentMode = _$enumDecode(
-        _$SKProductDiscountPaymentModeEnumMap, json['discountPaymentMode']);
-}
-
-Map<String, dynamic> _$_SerializedEnumsToJson(_SerializedEnums instance) =>
-    <String, dynamic>{
-      'response': _$SKPaymentTransactionStateWrapperEnumMap[instance.response],
-      'unit': _$SKSubscriptionPeriodUnitEnumMap[instance.unit],
-      'discountPaymentMode':
-          _$SKProductDiscountPaymentModeEnumMap[instance.discountPaymentMode],
-    };
-
-K _$enumDecode<K, V>(
-  Map<K, V> enumValues,
-  Object? source, {
-  K? unknownValue,
-}) {
-  if (source == null) {
-    throw ArgumentError(
-      'A value must be provided. Supported values: '
-      '${enumValues.values.join(', ')}',
-    );
-  }
-
-  return enumValues.entries.singleWhere(
-    (e) => e.value == source,
-    orElse: () {
-      if (unknownValue == null) {
-        throw ArgumentError(
-          '`$source` is not one of the supported values: '
-          '${enumValues.values.join(', ')}',
-        );
-      }
-      return MapEntry(unknownValue, enumValues.values.first);
-    },
-  ).key;
-}
-
-const _$SKPaymentTransactionStateWrapperEnumMap = {
-  SKPaymentTransactionStateWrapper.purchasing: 0,
-  SKPaymentTransactionStateWrapper.purchased: 1,
-  SKPaymentTransactionStateWrapper.failed: 2,
-  SKPaymentTransactionStateWrapper.restored: 3,
-  SKPaymentTransactionStateWrapper.deferred: 4,
-  SKPaymentTransactionStateWrapper.unspecified: -1,
-};
-
-const _$SKSubscriptionPeriodUnitEnumMap = {
-  SKSubscriptionPeriodUnit.day: 0,
-  SKSubscriptionPeriodUnit.week: 1,
-  SKSubscriptionPeriodUnit.month: 2,
-  SKSubscriptionPeriodUnit.year: 3,
-};
-
-const _$SKProductDiscountPaymentModeEnumMap = {
-  SKProductDiscountPaymentMode.payAsYouGo: 0,
-  SKProductDiscountPaymentMode.payUpFront: 1,
-  SKProductDiscountPaymentMode.freeTrail: 2,
-  SKProductDiscountPaymentMode.unspecified: -1,
-};
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart
deleted file mode 100644
index 2ba61b0..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart
+++ /dev/null
@@ -1,379 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:ui' show hashValues;
-import 'dart:async';
-import 'package:collection/collection.dart';
-import 'package:in_app_purchase/src/channel.dart';
-import 'package:json_annotation/json_annotation.dart';
-import 'package:flutter/services.dart';
-import 'sk_payment_transaction_wrappers.dart';
-import 'sk_product_wrapper.dart';
-
-part 'sk_payment_queue_wrapper.g.dart';
-
-/// A wrapper around
-/// [`SKPaymentQueue`](https://developer.apple.com/documentation/storekit/skpaymentqueue?language=objc).
-///
-/// The payment queue contains payment related operations. It communicates with
-/// the App Store and presents a user interface for the user to process and
-/// authorize payments.
-///
-/// Full information on using `SKPaymentQueue` and processing purchases is
-/// available at the [In-App Purchase Programming
-/// Guide](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction.html#//apple_ref/doc/uid/TP40008267).
-class SKPaymentQueueWrapper {
-  SKTransactionObserverWrapper? _observer;
-
-  /// Returns the default payment queue.
-  ///
-  /// We do not support instantiating a custom payment queue, hence the
-  /// singleton. However, you can override the observer.
-  factory SKPaymentQueueWrapper() {
-    return _singleton;
-  }
-
-  static final SKPaymentQueueWrapper _singleton = SKPaymentQueueWrapper._();
-
-  SKPaymentQueueWrapper._();
-
-  /// Calls [`-[SKPaymentQueue transactions]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506026-transactions?language=objc)
-  Future<List<SKPaymentTransactionWrapper>> transactions() async {
-    return _getTransactionList((await channel
-        .invokeListMethod<dynamic>('-[SKPaymentQueue transactions]'))!);
-  }
-
-  /// Calls [`-[SKPaymentQueue canMakePayments:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506139-canmakepayments?language=objc).
-  static Future<bool> canMakePayments() async =>
-      (await channel
-          .invokeMethod<bool>('-[SKPaymentQueue canMakePayments:]')) ??
-      false;
-
-  /// Sets an observer to listen to all incoming transaction events.
-  ///
-  /// This should be called and set as soon as the app launches in order to
-  /// avoid missing any purchase updates from the App Store. See the
-  /// documentation on StoreKit's [`-[SKPaymentQueue
-  /// addTransactionObserver:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506042-addtransactionobserver?language=objc).
-  void setTransactionObserver(SKTransactionObserverWrapper observer) {
-    _observer = observer;
-    channel.setMethodCallHandler(_handleObserverCallbacks);
-  }
-
-  /// Posts a payment to the queue.
-  ///
-  /// This sends a purchase request to the App Store for confirmation.
-  /// Transaction updates will be delivered to the set
-  /// [SkTransactionObserverWrapper].
-  ///
-  /// A couple preconditions need to be met before calling this method.
-  ///
-  ///   - At least one [SKTransactionObserverWrapper] should have been added to
-  ///     the payment queue using [addTransactionObserver].
-  ///   - The [payment.productIdentifier] needs to have been previously fetched
-  ///     using [SKRequestMaker.startProductRequest] so that a valid `SKProduct`
-  ///     has been cached in the platform side already. Because of this
-  ///     [payment.productIdentifier] cannot be hardcoded.
-  ///
-  /// This method calls StoreKit's [`-[SKPaymentQueue addPayment:]`]
-  /// (https://developer.apple.com/documentation/storekit/skpaymentqueue/1506036-addpayment?preferredLanguage=occ).
-  ///
-  /// Also see [sandbox
-  /// testing](https://developer.apple.com/apple-pay/sandbox-testing/).
-  Future<void> addPayment(SKPaymentWrapper payment) async {
-    assert(_observer != null,
-        '[in_app_purchase]: Trying to add a payment without an observer. One must be set using `SkPaymentQueueWrapper.setTransactionObserver` before the app launches.');
-    final Map<String, dynamic> requestMap = payment.toMap();
-    await channel.invokeMethod<void>(
-      '-[InAppPurchasePlugin addPayment:result:]',
-      requestMap,
-    );
-  }
-
-  /// Finishes a transaction and removes it from the queue.
-  ///
-  /// This method should be called after the given [transaction] has been
-  /// succesfully processed and its content has been delivered to the user.
-  /// Transaction status updates are propagated to [SkTransactionObserver].
-  ///
-  /// This will throw a Platform exception if [transaction.transactionState] is
-  /// [SKPaymentTransactionStateWrapper.purchasing].
-  ///
-  /// This method calls StoreKit's [`-[SKPaymentQueue
-  /// finishTransaction:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506003-finishtransaction?language=objc).
-  Future<void> finishTransaction(
-      SKPaymentTransactionWrapper transaction) async {
-    Map<String, String?> requestMap = transaction.toFinishMap();
-    await channel.invokeMethod<void>(
-      '-[InAppPurchasePlugin finishTransaction:result:]',
-      requestMap,
-    );
-  }
-
-  /// Restore previously purchased transactions.
-  ///
-  /// Use this to load previously purchased content on a new device.
-  ///
-  /// This call triggers purchase updates on the set
-  /// [SKTransactionObserverWrapper] for previously made transactions. This will
-  /// invoke [SKTransactionObserverWrapper.restoreCompletedTransactions],
-  /// [SKTransactionObserverWrapper.paymentQueueRestoreCompletedTransactionsFinished],
-  /// and [SKTransactionObserverWrapper.updatedTransaction]. These restored
-  /// transactions need to be marked complete with [finishTransaction] once the
-  /// content is delivered, like any other transaction.
-  ///
-  /// The `applicationUserName` should match the original
-  /// [SKPaymentWrapper.applicationUsername] used in [addPayment].
-  /// If no `applicationUserName` was used, `applicationUserName` should be null.
-  ///
-  /// This method either triggers [`-[SKPayment
-  /// restoreCompletedTransactions]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506123-restorecompletedtransactions?language=objc)
-  /// or [`-[SKPayment restoreCompletedTransactionsWithApplicationUsername:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1505992-restorecompletedtransactionswith?language=objc)
-  /// depending on whether the `applicationUserName` is set.
-  Future<void> restoreTransactions({String? applicationUserName}) async {
-    await channel.invokeMethod<void>(
-        '-[InAppPurchasePlugin restoreTransactions:result:]',
-        applicationUserName);
-  }
-
-  /// Present Code Redemption Sheet
-  ///
-  /// Use this to allow Users to enter and redeem Codes
-  ///
-  /// This method triggers [`-[SKPayment
-  /// presentCodeRedemptionSheet]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/3566726-presentcoderedemptionsheet?language=objc)
-  Future<void> presentCodeRedemptionSheet() async {
-    await channel.invokeMethod<void>(
-        '-[InAppPurchasePlugin presentCodeRedemptionSheet:result:]');
-  }
-
-  // Triage a method channel call from the platform and triggers the correct observer method.
-  Future<void> _handleObserverCallbacks(MethodCall call) async {
-    assert(_observer != null,
-        '[in_app_purchase]: (Fatal)The observer has not been set but we received a purchase transaction notification. Please ensure the observer has been set using `setTransactionObserver`. Make sure the observer is added right at the App Launch.');
-    final SKTransactionObserverWrapper observer = _observer!;
-    switch (call.method) {
-      case 'updatedTransactions':
-        {
-          final List<SKPaymentTransactionWrapper> transactions =
-              _getTransactionList(call.arguments);
-          return Future<void>(() {
-            observer.updatedTransactions(transactions: transactions);
-          });
-        }
-      case 'removedTransactions':
-        {
-          final List<SKPaymentTransactionWrapper> transactions =
-              _getTransactionList(call.arguments);
-          return Future<void>(() {
-            observer.removedTransactions(transactions: transactions);
-          });
-        }
-      case 'restoreCompletedTransactionsFailed':
-        {
-          SKError error = SKError.fromJson(call.arguments);
-          return Future<void>(() {
-            observer.restoreCompletedTransactionsFailed(error: error);
-          });
-        }
-      case 'paymentQueueRestoreCompletedTransactionsFinished':
-        {
-          return Future<void>(() {
-            observer.paymentQueueRestoreCompletedTransactionsFinished();
-          });
-        }
-      case 'shouldAddStorePayment':
-        {
-          SKPaymentWrapper payment =
-              SKPaymentWrapper.fromJson(call.arguments['payment']);
-          SKProductWrapper product =
-              SKProductWrapper.fromJson(call.arguments['product']);
-          return Future<void>(() {
-            if (observer.shouldAddStorePayment(
-                    payment: payment, product: product) ==
-                true) {
-              SKPaymentQueueWrapper().addPayment(payment);
-            }
-          });
-        }
-      default:
-        break;
-    }
-    throw PlatformException(
-        code: 'no_such_callback',
-        message: 'Did not recognize the observer callback ${call.method}.');
-  }
-
-  // Get transaction wrapper object list from arguments.
-  List<SKPaymentTransactionWrapper> _getTransactionList(
-      List<dynamic> transactionsData) {
-    return transactionsData.map<SKPaymentTransactionWrapper>((dynamic map) {
-      return SKPaymentTransactionWrapper.fromJson(
-          Map.castFrom<dynamic, dynamic, String, dynamic>(map));
-    }).toList();
-  }
-}
-
-/// Dart wrapper around StoreKit's
-/// [NSError](https://developer.apple.com/documentation/foundation/nserror?language=objc).
-@JsonSerializable()
-class SKError {
-  /// Creates a new [SKError] object with the provided information.
-  SKError({required this.code, required this.domain, required this.userInfo});
-
-  /// Constructs an instance of this from a key-value map of data.
-  ///
-  /// The map needs to have named string keys with values matching the names and
-  /// types of all of the members on this class. The `map` parameter must not be
-  /// null.
-  factory SKError.fromJson(Map<String, dynamic> map) {
-    return _$SKErrorFromJson(map);
-  }
-
-  /// Error [code](https://developer.apple.com/documentation/foundation/1448136-nserror_codes)
-  /// as defined in the Cocoa Framework.
-  @JsonKey(defaultValue: 0)
-  final int code;
-
-  /// Error
-  /// [domain](https://developer.apple.com/documentation/foundation/nscocoaerrordomain?language=objc)
-  /// as defined in the Cocoa Framework.
-  @JsonKey(defaultValue: '')
-  final String domain;
-
-  /// A map that contains more detailed information about the error.
-  ///
-  /// Any key of the map must be a valid [NSErrorUserInfoKey](https://developer.apple.com/documentation/foundation/nserroruserinfokey?language=objc).
-  @JsonKey(defaultValue: <String, dynamic>{})
-  final Map<String, dynamic> userInfo;
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) {
-      return true;
-    }
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-    final SKError typedOther = other as SKError;
-    return typedOther.code == code &&
-        typedOther.domain == domain &&
-        DeepCollectionEquality.unordered()
-            .equals(typedOther.userInfo, userInfo);
-  }
-
-  @override
-  int get hashCode => hashValues(this.code, this.domain, this.userInfo);
-}
-
-/// Dart wrapper around StoreKit's
-/// [SKPayment](https://developer.apple.com/documentation/storekit/skpayment?language=objc).
-///
-/// Used as the parameter to initiate a payment. In general, a developer should
-/// not need to create the payment object explicitly; instead, use
-/// [SKPaymentQueueWrapper.addPayment] directly with a product identifier to
-/// initiate a payment.
-@JsonSerializable()
-class SKPaymentWrapper {
-  /// Creates a new [SKPaymentWrapper] with the provided information.
-  SKPaymentWrapper(
-      {required this.productIdentifier,
-      this.applicationUsername,
-      this.requestData,
-      this.quantity = 1,
-      this.simulatesAskToBuyInSandbox = false});
-
-  /// Constructs an instance of this from a key value map of data.
-  ///
-  /// The map needs to have named string keys with values matching the names and
-  /// types of all of the members on this class. The `map` parameter must not be
-  /// null.
-  factory SKPaymentWrapper.fromJson(Map<String, dynamic> map) {
-    assert(map != null);
-    return _$SKPaymentWrapperFromJson(map);
-  }
-
-  /// Creates a Map object describes the payment object.
-  Map<String, dynamic> toMap() {
-    return {
-      'productIdentifier': productIdentifier,
-      'applicationUsername': applicationUsername,
-      'requestData': requestData,
-      'quantity': quantity,
-      'simulatesAskToBuyInSandbox': simulatesAskToBuyInSandbox
-    };
-  }
-
-  /// The id for the product that the payment is for.
-  @JsonKey(defaultValue: '')
-  final String productIdentifier;
-
-  /// An opaque id for the user's account.
-  ///
-  /// Used to help the store detect irregular activity. See
-  /// [applicationUsername](https://developer.apple.com/documentation/storekit/skpayment/1506116-applicationusername?language=objc)
-  /// for more details. For example, you can use a one-way hash of the user’s
-  /// account name on your server. Don’t use the Apple ID for your developer
-  /// account, the user’s Apple ID, or the user’s plaintext account name on
-  /// your server.
-  final String? applicationUsername;
-
-  /// Reserved for future use.
-  ///
-  /// The value must be null before sending the payment. If the value is not
-  /// null, the payment will be rejected.
-  ///
-  // The iOS Platform provided this property but it is reserved for future use.
-  // We also provide this property to match the iOS platform. Converted to
-  // String from NSData from ios platform using UTF8Encoding. The / default is
-  // null.
-  final String? requestData;
-
-  /// The amount of the product this payment is for.
-  ///
-  /// The default is 1. The minimum is 1. The maximum is 10.
-  ///
-  /// If the object is invalid, the value could be 0.
-  @JsonKey(defaultValue: 0)
-  final int quantity;
-
-  /// Produces an "ask to buy" flow in the sandbox.
-  ///
-  /// Setting it to `true` will cause a transaction to be in the state [SKPaymentTransactionStateWrapper.deferred],
-  /// which produce an "ask to buy" prompt that interrupts the the payment flow.
-  ///
-  /// Default is `false`.
-  ///
-  /// See https://developer.apple.com/in-app-purchase/ for a guide on Sandbox
-  /// testing.
-  @JsonKey(defaultValue: false)
-  final bool simulatesAskToBuyInSandbox;
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) {
-      return true;
-    }
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-    final SKPaymentWrapper typedOther = other as SKPaymentWrapper;
-    return typedOther.productIdentifier == productIdentifier &&
-        typedOther.applicationUsername == applicationUsername &&
-        typedOther.quantity == quantity &&
-        typedOther.simulatesAskToBuyInSandbox == simulatesAskToBuyInSandbox &&
-        typedOther.requestData == requestData;
-  }
-
-  @override
-  int get hashCode => hashValues(
-      this.productIdentifier,
-      this.applicationUsername,
-      this.quantity,
-      this.simulatesAskToBuyInSandbox,
-      this.requestData);
-
-  @override
-  String toString() => _$SKPaymentWrapperToJson(this).toString();
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart
deleted file mode 100644
index 2b88659..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.g.dart
+++ /dev/null
@@ -1,44 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'sk_payment_queue_wrapper.dart';
-
-// **************************************************************************
-// JsonSerializableGenerator
-// **************************************************************************
-
-SKError _$SKErrorFromJson(Map json) {
-  return SKError(
-    code: json['code'] as int? ?? 0,
-    domain: json['domain'] as String? ?? '',
-    userInfo: (json['userInfo'] as Map?)?.map(
-          (k, e) => MapEntry(k as String, e),
-        ) ??
-        {},
-  );
-}
-
-Map<String, dynamic> _$SKErrorToJson(SKError instance) => <String, dynamic>{
-      'code': instance.code,
-      'domain': instance.domain,
-      'userInfo': instance.userInfo,
-    };
-
-SKPaymentWrapper _$SKPaymentWrapperFromJson(Map json) {
-  return SKPaymentWrapper(
-    productIdentifier: json['productIdentifier'] as String? ?? '',
-    applicationUsername: json['applicationUsername'] as String?,
-    requestData: json['requestData'] as String?,
-    quantity: json['quantity'] as int? ?? 0,
-    simulatesAskToBuyInSandbox:
-        json['simulatesAskToBuyInSandbox'] as bool? ?? false,
-  );
-}
-
-Map<String, dynamic> _$SKPaymentWrapperToJson(SKPaymentWrapper instance) =>
-    <String, dynamic>{
-      'productIdentifier': instance.productIdentifier,
-      'applicationUsername': instance.applicationUsername,
-      'requestData': instance.requestData,
-      'quantity': instance.quantity,
-      'simulatesAskToBuyInSandbox': instance.simulatesAskToBuyInSandbox,
-    };
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart
deleted file mode 100644
index 01cd6db..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.dart
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:ui' show hashValues;
-import 'package:json_annotation/json_annotation.dart';
-import 'sk_product_wrapper.dart';
-import 'sk_payment_queue_wrapper.dart';
-import 'enum_converters.dart';
-
-part 'sk_payment_transaction_wrappers.g.dart';
-
-/// Callback handlers for transaction status changes.
-///
-/// Must be subclassed. Must be instantiated and added to the
-/// [SKPaymentQueueWrapper] via [SKPaymentQueueWrapper.setTransactionObserver]
-/// at app launch.
-///
-/// This class is a Dart wrapper around [SKTransactionObserver](https://developer.apple.com/documentation/storekit/skpaymenttransactionobserver?language=objc).
-abstract class SKTransactionObserverWrapper {
-  /// Triggered when any transactions are updated.
-  void updatedTransactions(
-      {required List<SKPaymentTransactionWrapper> transactions});
-
-  /// Triggered when any transactions are removed from the payment queue.
-  void removedTransactions(
-      {required List<SKPaymentTransactionWrapper> transactions});
-
-  /// Triggered when there is an error while restoring transactions.
-  void restoreCompletedTransactionsFailed({required SKError error});
-
-  /// Triggered when payment queue has finished sending restored transactions.
-  void paymentQueueRestoreCompletedTransactionsFinished();
-
-  /// Triggered when a user initiates an in-app purchase from App Store.
-  ///
-  /// Return `true` to continue the transaction in your app. If you have
-  /// multiple [SKTransactionObserverWrapper]s, the transaction will continue if
-  /// any [SKTransactionObserverWrapper] returns `true`. Return `false` to defer
-  /// or cancel the transaction. For example, you may need to defer a
-  /// transaction if the user is in the middle of onboarding. You can also
-  /// continue the transaction later by calling [addPayment] with the
-  /// `payment` param from this method.
-  bool shouldAddStorePayment(
-      {required SKPaymentWrapper payment, required SKProductWrapper product});
-}
-
-/// The state of a transaction.
-///
-/// Dart wrapper around StoreKit's
-/// [SKPaymentTransactionState](https://developer.apple.com/documentation/storekit/skpaymenttransactionstate?language=objc).
-enum SKPaymentTransactionStateWrapper {
-  /// Indicates the transaction is being processed in App Store.
-  ///
-  /// You should update your UI to indicate that you are waiting for the
-  /// transaction to update to another state. Never complete a transaction that
-  /// is still in a purchasing state.
-  @JsonValue(0)
-  purchasing,
-
-  /// The user's payment has been succesfully processed.
-  ///
-  /// You should provide the user the content that they purchased.
-  @JsonValue(1)
-  purchased,
-
-  /// The transaction failed.
-  ///
-  /// Check the [SKPaymentTransactionWrapper.error] property from
-  /// [SKPaymentTransactionWrapper] for details.
-  @JsonValue(2)
-  failed,
-
-  /// This transaction is restoring content previously purchased by the user.
-  ///
-  /// The previous transaction information can be obtained in
-  /// [SKPaymentTransactionWrapper.originalTransaction] from
-  /// [SKPaymentTransactionWrapper].
-  @JsonValue(3)
-  restored,
-
-  /// The transaction is in the queue but pending external action. Wait for
-  /// another callback to get the final state.
-  ///
-  /// You should update your UI to indicate that you are waiting for the
-  /// transaction to update to another state.
-  @JsonValue(4)
-  deferred,
-
-  /// Indicates the transaction is in an unspecified state.
-  @JsonValue(-1)
-  unspecified,
-}
-
-/// Created when a payment is added to the [SKPaymentQueueWrapper].
-///
-/// Transactions are delivered to your app when a payment is finished
-/// processing. Completed transactions provide a receipt and a transaction
-/// identifier that the app can use to save a permanent record of the processed
-/// payment.
-///
-/// Dart wrapper around StoreKit's
-/// [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction?language=objc).
-@JsonSerializable()
-class SKPaymentTransactionWrapper {
-  /// Creates a new [SKPaymentTransactionWrapper] with the provided information.
-  SKPaymentTransactionWrapper({
-    required this.payment,
-    required this.transactionState,
-    this.originalTransaction,
-    this.transactionTimeStamp,
-    this.transactionIdentifier,
-    this.error,
-  });
-
-  /// Constructs an instance of this from a key value map of data.
-  ///
-  /// The map needs to have named string keys with values matching the names and
-  /// types of all of the members on this class. The `map` parameter must not be
-  /// null.
-  factory SKPaymentTransactionWrapper.fromJson(Map<String, dynamic> map) {
-    return _$SKPaymentTransactionWrapperFromJson(map);
-  }
-
-  /// Current transaction state.
-  @SKTransactionStatusConverter()
-  final SKPaymentTransactionStateWrapper transactionState;
-
-  /// The payment that has been created and added to the payment queue which
-  /// generated this transaction.
-  final SKPaymentWrapper payment;
-
-  /// The original Transaction.
-  ///
-  /// Only available if the [transactionState] is [SKPaymentTransactionStateWrapper.restored].
-  /// Otherwise the value is `null`.
-  ///
-  /// When the [transactionState]
-  /// is [SKPaymentTransactionStateWrapper.restored], the current transaction
-  /// object holds a new [transactionIdentifier].
-  final SKPaymentTransactionWrapper? originalTransaction;
-
-  /// The timestamp of the transaction.
-  ///
-  /// Seconds since epoch. It is only defined when the [transactionState] is
-  /// [SKPaymentTransactionStateWrapper.purchased] or
-  /// [SKPaymentTransactionStateWrapper.restored].
-  /// Otherwise, the value is `null`.
-  final double? transactionTimeStamp;
-
-  /// The unique string identifer of the transaction.
-  ///
-  /// It is only defined when the [transactionState] is
-  /// [SKPaymentTransactionStateWrapper.purchased] or
-  /// [SKPaymentTransactionStateWrapper.restored]. You may wish to record this
-  /// string as part of an audit trail for App Store purchases. The value of
-  /// this string corresponds to the same property in the receipt.
-  ///
-  /// The value is `null` if it is an unsuccessful transaction.
-  final String? transactionIdentifier;
-
-  /// The error object
-  ///
-  /// Only available if the [transactionState] is
-  /// [SKPaymentTransactionStateWrapper.failed].
-  final SKError? error;
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) {
-      return true;
-    }
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-    final SKPaymentTransactionWrapper typedOther =
-        other as SKPaymentTransactionWrapper;
-    return typedOther.payment == payment &&
-        typedOther.transactionState == transactionState &&
-        typedOther.originalTransaction == originalTransaction &&
-        typedOther.transactionTimeStamp == transactionTimeStamp &&
-        typedOther.transactionIdentifier == transactionIdentifier &&
-        typedOther.error == error;
-  }
-
-  @override
-  int get hashCode => hashValues(
-      this.payment,
-      this.transactionState,
-      this.originalTransaction,
-      this.transactionTimeStamp,
-      this.transactionIdentifier,
-      this.error);
-
-  @override
-  String toString() => _$SKPaymentTransactionWrapperToJson(this).toString();
-
-  /// The payload that is used to finish this transaction.
-  Map<String, String?> toFinishMap() => <String, String?>{
-        "transactionIdentifier": this.transactionIdentifier,
-        "productIdentifier": this.payment.productIdentifier,
-      };
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart
deleted file mode 100644
index 4c7af21..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_transaction_wrappers.g.dart
+++ /dev/null
@@ -1,37 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'sk_payment_transaction_wrappers.dart';
-
-// **************************************************************************
-// JsonSerializableGenerator
-// **************************************************************************
-
-SKPaymentTransactionWrapper _$SKPaymentTransactionWrapperFromJson(Map json) {
-  return SKPaymentTransactionWrapper(
-    payment: SKPaymentWrapper.fromJson(
-        Map<String, dynamic>.from(json['payment'] as Map)),
-    transactionState: const SKTransactionStatusConverter()
-        .fromJson(json['transactionState'] as int?),
-    originalTransaction: json['originalTransaction'] == null
-        ? null
-        : SKPaymentTransactionWrapper.fromJson(
-            Map<String, dynamic>.from(json['originalTransaction'] as Map)),
-    transactionTimeStamp: (json['transactionTimeStamp'] as num?)?.toDouble(),
-    transactionIdentifier: json['transactionIdentifier'] as String?,
-    error: json['error'] == null
-        ? null
-        : SKError.fromJson(Map<String, dynamic>.from(json['error'] as Map)),
-  );
-}
-
-Map<String, dynamic> _$SKPaymentTransactionWrapperToJson(
-        SKPaymentTransactionWrapper instance) =>
-    <String, dynamic>{
-      'transactionState': const SKTransactionStatusConverter()
-          .toJson(instance.transactionState),
-      'payment': instance.payment,
-      'originalTransaction': instance.originalTransaction,
-      'transactionTimeStamp': instance.transactionTimeStamp,
-      'transactionIdentifier': instance.transactionIdentifier,
-      'error': instance.error,
-    };
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart
deleted file mode 100644
index ef0e667..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.dart
+++ /dev/null
@@ -1,374 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:ui' show hashValues;
-import 'package:collection/collection.dart';
-import 'package:json_annotation/json_annotation.dart';
-import 'enum_converters.dart';
-
-// WARNING: Changes to `@JsonSerializable` classes need to be reflected in the
-// below generated file. Run `flutter packages pub run build_runner watch` to
-// rebuild and watch for further changes.
-part 'sk_product_wrapper.g.dart';
-
-/// Dart wrapper around StoreKit's [SKProductsResponse](https://developer.apple.com/documentation/storekit/skproductsresponse?language=objc).
-///
-/// Represents the response object returned by [SKRequestMaker.startProductRequest].
-/// Contains information about a list of products and a list of invalid product identifiers.
-@JsonSerializable()
-class SkProductResponseWrapper {
-  /// Creates an [SkProductResponseWrapper] with the given product details.
-  SkProductResponseWrapper(
-      {required this.products, required this.invalidProductIdentifiers});
-
-  /// Constructing an instance from a map from the Objective-C layer.
-  ///
-  /// This method should only be used with `map` values returned by [SKRequestMaker.startProductRequest].
-  factory SkProductResponseWrapper.fromJson(Map<String, dynamic> map) {
-    return _$SkProductResponseWrapperFromJson(map);
-  }
-
-  /// Stores all matching successfully found products.
-  ///
-  /// One product in this list matches one valid product identifier passed to the [SKRequestMaker.startProductRequest].
-  /// Will be empty if the [SKRequestMaker.startProductRequest] method does not pass any correct product identifier.
-  @JsonKey(defaultValue: <SKProductWrapper>[])
-  final List<SKProductWrapper> products;
-
-  /// Stores product identifiers in the `productIdentifiers` from [SKRequestMaker.startProductRequest] that are not recognized by the App Store.
-  ///
-  /// The App Store will not recognize a product identifier unless certain criteria are met. A detailed list of the criteria can be
-  /// found here https://developer.apple.com/documentation/storekit/skproductsresponse/1505985-invalidproductidentifiers?language=objc.
-  /// Will be empty if all the product identifiers are valid.
-  @JsonKey(defaultValue: <String>[])
-  final List<String> invalidProductIdentifiers;
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) {
-      return true;
-    }
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-    final SkProductResponseWrapper typedOther =
-        other as SkProductResponseWrapper;
-    return DeepCollectionEquality().equals(typedOther.products, products) &&
-        DeepCollectionEquality().equals(
-            typedOther.invalidProductIdentifiers, invalidProductIdentifiers);
-  }
-
-  @override
-  int get hashCode => hashValues(this.products, this.invalidProductIdentifiers);
-}
-
-/// Dart wrapper around StoreKit's [SKProductPeriodUnit](https://developer.apple.com/documentation/storekit/skproductperiodunit?language=objc).
-///
-/// Used as a property in the [SKProductSubscriptionPeriodWrapper]. Minimum is a day and maximum is a year.
-// The values of the enum options are matching the [SKProductPeriodUnit]'s values. Should there be an update or addition
-// in the [SKProductPeriodUnit], this need to be updated to match.
-enum SKSubscriptionPeriodUnit {
-  /// An interval lasting one day.
-  @JsonValue(0)
-  day,
-
-  /// An interval lasting one month.
-  @JsonValue(1)
-
-  /// An interval lasting one week.
-  week,
-  @JsonValue(2)
-
-  /// An interval lasting one month.
-  month,
-
-  /// An interval lasting one year.
-  @JsonValue(3)
-  year,
-}
-
-/// Dart wrapper around StoreKit's [SKProductSubscriptionPeriod](https://developer.apple.com/documentation/storekit/skproductsubscriptionperiod?language=objc).
-///
-/// A period is defined by a [numberOfUnits] and a [unit], e.g for a 3 months period [numberOfUnits] is 3 and [unit] is a month.
-/// It is used as a property in [SKProductDiscountWrapper] and [SKProductWrapper].
-@JsonSerializable()
-class SKProductSubscriptionPeriodWrapper {
-  /// Creates an [SKProductSubscriptionPeriodWrapper] for a `numberOfUnits`x`unit` period.
-  SKProductSubscriptionPeriodWrapper(
-      {required this.numberOfUnits, required this.unit});
-
-  /// Constructing an instance from a map from the Objective-C layer.
-  ///
-  /// This method should only be used with `map` values returned by [SKProductDiscountWrapper.fromJson] or [SKProductWrapper.fromJson].
-  factory SKProductSubscriptionPeriodWrapper.fromJson(
-      Map<String, dynamic>? map) {
-    if (map == null) {
-      return SKProductSubscriptionPeriodWrapper(
-          numberOfUnits: 0, unit: SKSubscriptionPeriodUnit.day);
-    }
-    return _$SKProductSubscriptionPeriodWrapperFromJson(map);
-  }
-
-  /// The number of [unit] units in this period.
-  ///
-  /// Must be greater than 0 if the object is valid.
-  @JsonKey(defaultValue: 0)
-  final int numberOfUnits;
-
-  /// The time unit used to specify the length of this period.
-  @SKSubscriptionPeriodUnitConverter()
-  final SKSubscriptionPeriodUnit unit;
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) {
-      return true;
-    }
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-    final SKProductSubscriptionPeriodWrapper typedOther =
-        other as SKProductSubscriptionPeriodWrapper;
-    return typedOther.numberOfUnits == numberOfUnits && typedOther.unit == unit;
-  }
-
-  @override
-  int get hashCode => hashValues(this.numberOfUnits, this.unit);
-}
-
-/// Dart wrapper around StoreKit's [SKProductDiscountPaymentMode](https://developer.apple.com/documentation/storekit/skproductdiscountpaymentmode?language=objc).
-///
-/// This is used as a property in the [SKProductDiscountWrapper].
-// The values of the enum options are matching the [SKProductDiscountPaymentMode]'s values. Should there be an update or addition
-// in the [SKProductDiscountPaymentMode], this need to be updated to match.
-enum SKProductDiscountPaymentMode {
-  /// Allows user to pay the discounted price at each payment period.
-  @JsonValue(0)
-  payAsYouGo,
-
-  /// Allows user to pay the discounted price upfront and receive the product for the rest of time that was paid for.
-  @JsonValue(1)
-  payUpFront,
-
-  /// User pays nothing during the discounted period.
-  @JsonValue(2)
-  freeTrail,
-
-  /// Unspecified mode.
-  @JsonValue(-1)
-  unspecified,
-}
-
-/// Dart wrapper around StoreKit's [SKProductDiscount](https://developer.apple.com/documentation/storekit/skproductdiscount?language=objc).
-///
-/// It is used as a property in [SKProductWrapper].
-@JsonSerializable()
-class SKProductDiscountWrapper {
-  /// Creates an [SKProductDiscountWrapper] with the given discount details.
-  SKProductDiscountWrapper(
-      {required this.price,
-      required this.priceLocale,
-      required this.numberOfPeriods,
-      required this.paymentMode,
-      required this.subscriptionPeriod});
-
-  /// Constructing an instance from a map from the Objective-C layer.
-  ///
-  /// This method should only be used with `map` values returned by [SKProductWrapper.fromJson].
-  factory SKProductDiscountWrapper.fromJson(Map<String, dynamic> map) {
-    return _$SKProductDiscountWrapperFromJson(map);
-  }
-
-  /// The discounted price, in the currency that is defined in [priceLocale].
-  @JsonKey(defaultValue: '')
-  final String price;
-
-  /// Includes locale information about the price, e.g. `$` as the currency symbol for US locale.
-  final SKPriceLocaleWrapper priceLocale;
-
-  /// The object represent the discount period length.
-  ///
-  /// The value must be >= 0 if the object is valid.
-  @JsonKey(defaultValue: 0)
-  final int numberOfPeriods;
-
-  /// The object indicates how the discount price is charged.
-  @SKProductDiscountPaymentModeConverter()
-  final SKProductDiscountPaymentMode paymentMode;
-
-  /// The object represents the duration of single subscription period for the discount.
-  ///
-  /// The [subscriptionPeriod] of the discount is independent of the product's [subscriptionPeriod],
-  /// and their units and duration do not have to be matched.
-  final SKProductSubscriptionPeriodWrapper subscriptionPeriod;
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) {
-      return true;
-    }
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-    final SKProductDiscountWrapper typedOther =
-        other as SKProductDiscountWrapper;
-    return typedOther.price == price &&
-        typedOther.priceLocale == priceLocale &&
-        typedOther.numberOfPeriods == numberOfPeriods &&
-        typedOther.paymentMode == paymentMode &&
-        typedOther.subscriptionPeriod == subscriptionPeriod;
-  }
-
-  @override
-  int get hashCode => hashValues(this.price, this.priceLocale,
-      this.numberOfPeriods, this.paymentMode, this.subscriptionPeriod);
-}
-
-/// Dart wrapper around StoreKit's [SKProduct](https://developer.apple.com/documentation/storekit/skproduct?language=objc).
-///
-/// A list of [SKProductWrapper] is returned in the [SKRequestMaker.startProductRequest] method, and
-/// should be stored for use when making a payment.
-@JsonSerializable()
-class SKProductWrapper {
-  /// Creates an [SKProductWrapper] with the given product details.
-  SKProductWrapper({
-    required this.productIdentifier,
-    required this.localizedTitle,
-    required this.localizedDescription,
-    required this.priceLocale,
-    this.subscriptionGroupIdentifier,
-    required this.price,
-    this.subscriptionPeriod,
-    this.introductoryPrice,
-  });
-
-  /// Constructing an instance from a map from the Objective-C layer.
-  ///
-  /// This method should only be used with `map` values returned by [SkProductResponseWrapper.fromJson].
-  factory SKProductWrapper.fromJson(Map<String, dynamic> map) {
-    return _$SKProductWrapperFromJson(map);
-  }
-
-  /// The unique identifier of the product.
-  @JsonKey(defaultValue: '')
-  final String productIdentifier;
-
-  /// The localizedTitle of the product.
-  ///
-  /// It is localized based on the current locale.
-  @JsonKey(defaultValue: '')
-  final String localizedTitle;
-
-  /// The localized description of the product.
-  ///
-  /// It is localized based on the current locale.
-  @JsonKey(defaultValue: '')
-  final String localizedDescription;
-
-  /// Includes locale information about the price, e.g. `$` as the currency symbol for US locale.
-  final SKPriceLocaleWrapper priceLocale;
-
-  /// The subscription group identifier.
-  ///
-  /// If the product is not a subscription, the value is `null`.
-  ///
-  /// A subscription group is a collection of subscription products.
-  /// Check [SubscriptionGroup](https://developer.apple.com/app-store/subscriptions/) for more details about subscription group.
-  final String? subscriptionGroupIdentifier;
-
-  /// The price of the product, in the currency that is defined in [priceLocale].
-  @JsonKey(defaultValue: '')
-  final String price;
-
-  /// The object represents the subscription period of the product.
-  ///
-  /// Can be [null] is the product is not a subscription.
-  final SKProductSubscriptionPeriodWrapper? subscriptionPeriod;
-
-  /// The object represents the duration of single subscription period.
-  ///
-  /// This is only available if you set up the introductory price in the App Store Connect, otherwise the value is `null`.
-  /// Programmer is also responsible to determine if the user is eligible to receive it. See https://developer.apple.com/documentation/storekit/in-app_purchase/offering_introductory_pricing_in_your_app?language=objc
-  /// for more details.
-  /// The [subscriptionPeriod] of the discount is independent of the product's [subscriptionPeriod],
-  /// and their units and duration do not have to be matched.
-  final SKProductDiscountWrapper? introductoryPrice;
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) {
-      return true;
-    }
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-    final SKProductWrapper typedOther = other as SKProductWrapper;
-    return typedOther.productIdentifier == productIdentifier &&
-        typedOther.localizedTitle == localizedTitle &&
-        typedOther.localizedDescription == localizedDescription &&
-        typedOther.priceLocale == priceLocale &&
-        typedOther.subscriptionGroupIdentifier == subscriptionGroupIdentifier &&
-        typedOther.price == price &&
-        typedOther.subscriptionPeriod == subscriptionPeriod &&
-        typedOther.introductoryPrice == introductoryPrice;
-  }
-
-  @override
-  int get hashCode => hashValues(
-      this.productIdentifier,
-      this.localizedTitle,
-      this.localizedDescription,
-      this.priceLocale,
-      this.subscriptionGroupIdentifier,
-      this.price,
-      this.subscriptionPeriod,
-      this.introductoryPrice);
-}
-
-/// Object that indicates the locale of the price
-///
-/// It is a thin wrapper of [NSLocale](https://developer.apple.com/documentation/foundation/nslocale?language=objc).
-// TODO(cyanglaz): NSLocale is a complex object, want to see the actual need of getting this expanded.
-//                 Matching android to only get the currencySymbol for now.
-//                 https://github.com/flutter/flutter/issues/26610
-@JsonSerializable()
-class SKPriceLocaleWrapper {
-  /// Creates a new price locale for `currencySymbol` and `currencyCode`.
-  SKPriceLocaleWrapper(
-      {required this.currencySymbol, required this.currencyCode});
-
-  /// Constructing an instance from a map from the Objective-C layer.
-  ///
-  /// This method should only be used with `map` values returned by [SKProductWrapper.fromJson] and [SKProductDiscountWrapper.fromJson].
-  factory SKPriceLocaleWrapper.fromJson(Map<String, dynamic>? map) {
-    if (map == null) {
-      return SKPriceLocaleWrapper(currencyCode: '', currencySymbol: '');
-    }
-    return _$SKPriceLocaleWrapperFromJson(map);
-  }
-
-  ///The currency symbol for the locale, e.g. $ for US locale.
-  @JsonKey(defaultValue: '')
-  final String currencySymbol;
-
-  ///The currency code for the locale, e.g. USD for US locale.
-  @JsonKey(defaultValue: '')
-  final String currencyCode;
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(other, this)) {
-      return true;
-    }
-    if (other.runtimeType != runtimeType) {
-      return false;
-    }
-    final SKPriceLocaleWrapper typedOther = other as SKPriceLocaleWrapper;
-    return typedOther.currencySymbol == currencySymbol &&
-        typedOther.currencyCode == currencyCode;
-  }
-
-  @override
-  int get hashCode => hashValues(this.currencySymbol, this.currencyCode);
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart
deleted file mode 100644
index 8c2eed3..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_product_wrapper.g.dart
+++ /dev/null
@@ -1,123 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-part of 'sk_product_wrapper.dart';
-
-// **************************************************************************
-// JsonSerializableGenerator
-// **************************************************************************
-
-SkProductResponseWrapper _$SkProductResponseWrapperFromJson(Map json) {
-  return SkProductResponseWrapper(
-    products: (json['products'] as List<dynamic>?)
-            ?.map((e) =>
-                SKProductWrapper.fromJson(Map<String, dynamic>.from(e as Map)))
-            .toList() ??
-        [],
-    invalidProductIdentifiers:
-        (json['invalidProductIdentifiers'] as List<dynamic>?)
-                ?.map((e) => e as String)
-                .toList() ??
-            [],
-  );
-}
-
-Map<String, dynamic> _$SkProductResponseWrapperToJson(
-        SkProductResponseWrapper instance) =>
-    <String, dynamic>{
-      'products': instance.products,
-      'invalidProductIdentifiers': instance.invalidProductIdentifiers,
-    };
-
-SKProductSubscriptionPeriodWrapper _$SKProductSubscriptionPeriodWrapperFromJson(
-    Map json) {
-  return SKProductSubscriptionPeriodWrapper(
-    numberOfUnits: json['numberOfUnits'] as int? ?? 0,
-    unit: const SKSubscriptionPeriodUnitConverter()
-        .fromJson(json['unit'] as int?),
-  );
-}
-
-Map<String, dynamic> _$SKProductSubscriptionPeriodWrapperToJson(
-        SKProductSubscriptionPeriodWrapper instance) =>
-    <String, dynamic>{
-      'numberOfUnits': instance.numberOfUnits,
-      'unit': const SKSubscriptionPeriodUnitConverter().toJson(instance.unit),
-    };
-
-SKProductDiscountWrapper _$SKProductDiscountWrapperFromJson(Map json) {
-  return SKProductDiscountWrapper(
-    price: json['price'] as String? ?? '',
-    priceLocale:
-        SKPriceLocaleWrapper.fromJson((json['priceLocale'] as Map?)?.map(
-      (k, e) => MapEntry(k as String, e),
-    )),
-    numberOfPeriods: json['numberOfPeriods'] as int? ?? 0,
-    paymentMode: const SKProductDiscountPaymentModeConverter()
-        .fromJson(json['paymentMode'] as int?),
-    subscriptionPeriod: SKProductSubscriptionPeriodWrapper.fromJson(
-        (json['subscriptionPeriod'] as Map?)?.map(
-      (k, e) => MapEntry(k as String, e),
-    )),
-  );
-}
-
-Map<String, dynamic> _$SKProductDiscountWrapperToJson(
-        SKProductDiscountWrapper instance) =>
-    <String, dynamic>{
-      'price': instance.price,
-      'priceLocale': instance.priceLocale,
-      'numberOfPeriods': instance.numberOfPeriods,
-      'paymentMode': const SKProductDiscountPaymentModeConverter()
-          .toJson(instance.paymentMode),
-      'subscriptionPeriod': instance.subscriptionPeriod,
-    };
-
-SKProductWrapper _$SKProductWrapperFromJson(Map json) {
-  return SKProductWrapper(
-    productIdentifier: json['productIdentifier'] as String? ?? '',
-    localizedTitle: json['localizedTitle'] as String? ?? '',
-    localizedDescription: json['localizedDescription'] as String? ?? '',
-    priceLocale:
-        SKPriceLocaleWrapper.fromJson((json['priceLocale'] as Map?)?.map(
-      (k, e) => MapEntry(k as String, e),
-    )),
-    subscriptionGroupIdentifier: json['subscriptionGroupIdentifier'] as String?,
-    price: json['price'] as String? ?? '',
-    subscriptionPeriod: json['subscriptionPeriod'] == null
-        ? null
-        : SKProductSubscriptionPeriodWrapper.fromJson(
-            (json['subscriptionPeriod'] as Map?)?.map(
-            (k, e) => MapEntry(k as String, e),
-          )),
-    introductoryPrice: json['introductoryPrice'] == null
-        ? null
-        : SKProductDiscountWrapper.fromJson(
-            Map<String, dynamic>.from(json['introductoryPrice'] as Map)),
-  );
-}
-
-Map<String, dynamic> _$SKProductWrapperToJson(SKProductWrapper instance) =>
-    <String, dynamic>{
-      'productIdentifier': instance.productIdentifier,
-      'localizedTitle': instance.localizedTitle,
-      'localizedDescription': instance.localizedDescription,
-      'priceLocale': instance.priceLocale,
-      'subscriptionGroupIdentifier': instance.subscriptionGroupIdentifier,
-      'price': instance.price,
-      'subscriptionPeriod': instance.subscriptionPeriod,
-      'introductoryPrice': instance.introductoryPrice,
-    };
-
-SKPriceLocaleWrapper _$SKPriceLocaleWrapperFromJson(Map json) {
-  return SKPriceLocaleWrapper(
-    currencySymbol: json['currencySymbol'] as String? ?? '',
-    currencyCode: json['currencyCode'] as String? ?? '',
-  );
-}
-
-Map<String, dynamic> _$SKPriceLocaleWrapperToJson(
-        SKPriceLocaleWrapper instance) =>
-    <String, dynamic>{
-      'currencySymbol': instance.currencySymbol,
-      'currencyCode': instance.currencyCode,
-    };
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart
deleted file mode 100644
index 429cbf0..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_receipt_manager.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-import 'package:in_app_purchase/src/channel.dart';
-
-///This class contains static methods to manage StoreKit receipts.
-class SKReceiptManager {
-  /// Retrieve the receipt data from your application's main bundle.
-  ///
-  /// The receipt data will be based64 encoded. The structure of the payload is defined using ASN.1.
-  /// You can use the receipt data retrieved by this method to validate users' purchases.
-  /// There are 2 ways to do so. Either validate locally or validate with App Store.
-  /// For more details on how to validate the receipt data, you can refer to Apple's document about [`About Receipt Validation`](https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Introduction.html#//apple_ref/doc/uid/TP40010573-CH105-SW1).
-  /// If the receipt is invalid or missing, you can use [SKRequestMaker.startRefreshReceiptRequest] to request a new receipt.
-  static Future<String> retrieveReceiptData() async {
-    return (await channel.invokeMethod<String>(
-            '-[InAppPurchasePlugin retrieveReceiptData:result:]')) ??
-        '';
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart b/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart
deleted file mode 100644
index 88f3ac5..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/src/store_kit_wrappers/sk_request_maker.dart
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-import 'package:flutter/services.dart';
-import 'package:in_app_purchase/src/channel.dart';
-import 'sk_product_wrapper.dart';
-
-/// A request maker that handles all the requests made by SKRequest subclasses.
-///
-/// There are multiple [SKRequest](https://developer.apple.com/documentation/storekit/skrequest?language=objc) subclasses handling different requests in the `StoreKit` with multiple delegate methods,
-/// we consolidated all the `SKRequest` subclasses into this class to make requests in a more straightforward way.
-/// The request maker will create a SKRequest object, immediately starting it, and completing the future successfully or throw an exception depending on what happened to the request.
-class SKRequestMaker {
-  /// Fetches product information for a list of given product identifiers.
-  ///
-  /// The `productIdentifiers` should contain legitimate product identifiers that you declared for the products in the iTunes Connect. Invalid identifiers
-  /// will be stored and returned in [SkProductResponseWrapper.invalidProductIdentifiers]. Duplicate values in `productIdentifiers` will be omitted.
-  /// If `productIdentifiers` is null, an `storekit_invalid_argument` error will be returned. If `productIdentifiers` is empty, a [SkProductResponseWrapper]
-  /// will still be returned with [SkProductResponseWrapper.products] being null.
-  ///
-  /// [SkProductResponseWrapper] is returned if there is no error during the request.
-  /// A [PlatformException] is thrown if the platform code making the request fails.
-  Future<SkProductResponseWrapper> startProductRequest(
-      List<String> productIdentifiers) async {
-    final Map<String, dynamic>? productResponseMap =
-        await channel.invokeMapMethod<String, dynamic>(
-      '-[InAppPurchasePlugin startProductRequest:result:]',
-      productIdentifiers,
-    );
-    if (productResponseMap == null) {
-      throw PlatformException(
-        code: 'storekit_no_response',
-        message: 'StoreKit: Failed to get response from platform.',
-      );
-    }
-    return SkProductResponseWrapper.fromJson(productResponseMap);
-  }
-
-  /// Uses [SKReceiptRefreshRequest](https://developer.apple.com/documentation/storekit/skreceiptrefreshrequest?language=objc) to request a new receipt.
-  ///
-  /// If the receipt is invalid or missing, you can use this API to request a new receipt.
-  /// The [receiptProperties] is optional and it exists only for [sandbox testing](https://developer.apple.com/apple-pay/sandbox-testing/). In the production app, call this API without pass in the [receiptProperties] parameter.
-  /// To test in the sandbox, you can request a receipt with any combination of properties to test the state transitions related to [`Volume Purchase Plan`](https://www.apple.com/business/site/docs/VPP_Business_Guide.pdf) receipts.
-  /// The valid keys in the receiptProperties are below (All of them are of type bool):
-  /// * isExpired: whether the receipt is expired.
-  /// * isRevoked: whether the receipt has been revoked.
-  /// * isVolumePurchase: whether the receipt is a Volume Purchase Plan receipt.
-  Future<void> startRefreshReceiptRequest(
-      {Map<String, dynamic>? receiptProperties}) {
-    return channel.invokeMethod<void>(
-      '-[InAppPurchasePlugin refreshReceipt:result:]',
-      receiptProperties,
-    );
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/lib/store_kit_wrappers.dart b/packages/in_app_purchase/in_app_purchase/lib/store_kit_wrappers.dart
deleted file mode 100644
index b687d23..0000000
--- a/packages/in_app_purchase/in_app_purchase/lib/store_kit_wrappers.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-export 'src/store_kit_wrappers/sk_payment_queue_wrapper.dart';
-export 'src/store_kit_wrappers/sk_payment_transaction_wrappers.dart';
-export 'src/store_kit_wrappers/sk_product_wrapper.dart';
-export 'src/store_kit_wrappers/sk_receipt_manager.dart';
-export 'src/store_kit_wrappers/sk_request_maker.dart';
diff --git a/packages/in_app_purchase/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/in_app_purchase/pubspec.yaml
index 8033aa8..4afceef 100644
--- a/packages/in_app_purchase/in_app_purchase/pubspec.yaml
+++ b/packages/in_app_purchase/in_app_purchase/pubspec.yaml
@@ -1,25 +1,18 @@
 name: in_app_purchase
 description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play.
 homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase
-version: 0.5.2
-
-# TODO(mvanbeusekom): Remove when in_app_purchase_platform_interface is published
-publish_to: 'none'
+version: 0.6.0
 
 dependencies:
   flutter:
     sdk: flutter
-  json_annotation: ^4.0.0
-  meta: ^1.3.0
-  collection: ^1.15.0
+  
+  in_app_purchase_platform_interface: ^1.0.0
+  in_app_purchase_android: ^0.1.0
+  in_app_purchase_ios: ^0.1.0 
 
-  # TODO(mvanbeusekom): Replace with pub.dev version when in_app_purchase_platform_interface is published
-  in_app_purchase_platform_interface:
-    path: ../in_app_purchase_platform_interface
 
 dev_dependencies:
-  build_runner: ^1.11.1
-  json_serializable: ^4.0.0
   flutter_test:
     sdk: flutter
   flutter_driver:
@@ -28,15 +21,16 @@
   integration_test:
     sdk: flutter
   pedantic: ^1.10.0
+  plugin_platform_interface: ^2.0.0
+
 
 flutter:
   plugin:
     platforms:
       android:
-        package: io.flutter.plugins.inapppurchase
-        pluginClass: InAppPurchasePlugin
+        default_package: in_app_purchase_android
       ios:
-        pluginClass: InAppPurchasePlugin
+        default_package: in_app_purchase_ios
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart
deleted file mode 100644
index 9a5d262..0000000
--- a/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/billing_client_wrapper_test.dart
+++ /dev/null
@@ -1,547 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter_test/flutter_test.dart';
-import 'package:flutter/services.dart';
-
-import 'package:in_app_purchase/billing_client_wrappers.dart';
-import 'package:in_app_purchase/src/billing_client_wrappers/enum_converters.dart';
-import 'package:in_app_purchase/src/channel.dart';
-import '../stub_in_app_purchase_platform.dart';
-import 'sku_details_wrapper_test.dart';
-import 'purchase_wrapper_test.dart';
-
-void main() {
-  TestWidgetsFlutterBinding.ensureInitialized();
-
-  final StubInAppPurchasePlatform stubPlatform = StubInAppPurchasePlatform();
-  late BillingClient billingClient;
-
-  setUpAll(() =>
-      channel.setMockMethodCallHandler(stubPlatform.fakeMethodCallHandler));
-
-  setUp(() {
-    billingClient = BillingClient((PurchasesResultWrapper _) {});
-    billingClient.enablePendingPurchases();
-    stubPlatform.reset();
-  });
-
-  group('isReady', () {
-    test('true', () async {
-      stubPlatform.addResponse(name: 'BillingClient#isReady()', value: true);
-      expect(await billingClient.isReady(), isTrue);
-    });
-
-    test('false', () async {
-      stubPlatform.addResponse(name: 'BillingClient#isReady()', value: false);
-      expect(await billingClient.isReady(), isFalse);
-    });
-  });
-
-  // Make sure that the enum values are supported and that the converter call
-  // does not fail
-  test('response states', () async {
-    BillingResponseConverter converter = BillingResponseConverter();
-    converter.fromJson(-3);
-    converter.fromJson(-2);
-    converter.fromJson(-1);
-    converter.fromJson(0);
-    converter.fromJson(1);
-    converter.fromJson(2);
-    converter.fromJson(3);
-    converter.fromJson(4);
-    converter.fromJson(5);
-    converter.fromJson(6);
-    converter.fromJson(7);
-    converter.fromJson(8);
-  });
-
-  group('startConnection', () {
-    final String methodName =
-        'BillingClient#startConnection(BillingClientStateListener)';
-    test('returns BillingResultWrapper', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.developerError;
-      stubPlatform.addResponse(
-        name: methodName,
-        value: <String, dynamic>{
-          'responseCode': BillingResponseConverter().toJson(responseCode),
-          'debugMessage': debugMessage,
-        },
-      );
-
-      BillingResultWrapper billingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      expect(
-          await billingClient.startConnection(
-              onBillingServiceDisconnected: () {}),
-          equals(billingResult));
-    });
-
-    test('passes handle to onBillingServiceDisconnected', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.developerError;
-      stubPlatform.addResponse(
-        name: methodName,
-        value: <String, dynamic>{
-          'responseCode': BillingResponseConverter().toJson(responseCode),
-          'debugMessage': debugMessage,
-        },
-      );
-      await billingClient.startConnection(onBillingServiceDisconnected: () {});
-      final MethodCall call = stubPlatform.previousCallMatching(methodName);
-      expect(
-          call.arguments,
-          equals(
-              <dynamic, dynamic>{'handle': 0, 'enablePendingPurchases': true}));
-    });
-
-    test('handles method channel returning null', () async {
-      stubPlatform.addResponse(
-        name: methodName,
-        value: null,
-      );
-
-      expect(
-          await billingClient.startConnection(
-              onBillingServiceDisconnected: () {}),
-          equals(BillingResultWrapper(
-              responseCode: BillingResponse.error,
-              debugMessage: kInvalidBillingResultErrorMessage)));
-    });
-  });
-
-  test('endConnection', () async {
-    final String endConnectionName = 'BillingClient#endConnection()';
-    expect(stubPlatform.countPreviousCalls(endConnectionName), equals(0));
-    stubPlatform.addResponse(name: endConnectionName, value: null);
-    await billingClient.endConnection();
-    expect(stubPlatform.countPreviousCalls(endConnectionName), equals(1));
-  });
-
-  group('querySkuDetails', () {
-    final String queryMethodName =
-        'BillingClient#querySkuDetailsAsync(SkuDetailsParams, SkuDetailsResponseListener)';
-
-    test('handles empty skuDetails', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.developerError;
-      stubPlatform.addResponse(name: queryMethodName, value: <dynamic, dynamic>{
-        'billingResult': <String, dynamic>{
-          'responseCode': BillingResponseConverter().toJson(responseCode),
-          'debugMessage': debugMessage,
-        },
-        'skuDetailsList': <Map<String, dynamic>>[]
-      });
-
-      final SkuDetailsResponseWrapper response = await billingClient
-          .querySkuDetails(
-              skuType: SkuType.inapp, skusList: <String>['invalid']);
-
-      BillingResultWrapper billingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      expect(response.billingResult, equals(billingResult));
-      expect(response.skuDetailsList, isEmpty);
-    });
-
-    test('returns SkuDetailsResponseWrapper', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.ok;
-      stubPlatform.addResponse(name: queryMethodName, value: <String, dynamic>{
-        'billingResult': <String, dynamic>{
-          'responseCode': BillingResponseConverter().toJson(responseCode),
-          'debugMessage': debugMessage,
-        },
-        'skuDetailsList': <Map<String, dynamic>>[buildSkuMap(dummySkuDetails)]
-      });
-
-      final SkuDetailsResponseWrapper response = await billingClient
-          .querySkuDetails(
-              skuType: SkuType.inapp, skusList: <String>['invalid']);
-
-      BillingResultWrapper billingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      expect(response.billingResult, equals(billingResult));
-      expect(response.skuDetailsList, contains(dummySkuDetails));
-    });
-
-    test('handles null method channel response', () async {
-      stubPlatform.addResponse(name: queryMethodName, value: null);
-
-      final SkuDetailsResponseWrapper response = await billingClient
-          .querySkuDetails(
-              skuType: SkuType.inapp, skusList: <String>['invalid']);
-
-      BillingResultWrapper billingResult = BillingResultWrapper(
-          responseCode: BillingResponse.error,
-          debugMessage: kInvalidBillingResultErrorMessage);
-      expect(response.billingResult, equals(billingResult));
-      expect(response.skuDetailsList, isEmpty);
-    });
-  });
-
-  group('launchBillingFlow', () {
-    final String launchMethodName =
-        'BillingClient#launchBillingFlow(Activity, BillingFlowParams)';
-
-    test('serializes and deserializes data', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-        name: launchMethodName,
-        value: buildBillingResultMap(expectedBillingResult),
-      );
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-      final String accountId = "hashedAccountId";
-      final String profileId = "hashedProfileId";
-
-      expect(
-          await billingClient.launchBillingFlow(
-              sku: skuDetails.sku,
-              accountId: accountId,
-              obfuscatedProfileId: profileId),
-          equals(expectedBillingResult));
-      Map<dynamic, dynamic> arguments =
-          stubPlatform.previousCallMatching(launchMethodName).arguments;
-      expect(arguments['sku'], equals(skuDetails.sku));
-      expect(arguments['accountId'], equals(accountId));
-      expect(arguments['obfuscatedProfileId'], equals(profileId));
-    });
-
-    test(
-        'Change subscription throws assertion error `oldSku` and `purchaseToken` has different nullability',
-        () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-        name: launchMethodName,
-        value: buildBillingResultMap(expectedBillingResult),
-      );
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-      final String accountId = 'hashedAccountId';
-      final String profileId = 'hashedProfileId';
-
-      expect(
-          billingClient.launchBillingFlow(
-              sku: skuDetails.sku,
-              accountId: accountId,
-              obfuscatedProfileId: profileId,
-              oldSku: dummyOldPurchase.sku,
-              purchaseToken: null),
-          throwsAssertionError);
-
-      expect(
-          billingClient.launchBillingFlow(
-              sku: skuDetails.sku,
-              accountId: accountId,
-              obfuscatedProfileId: profileId,
-              oldSku: null,
-              purchaseToken: dummyOldPurchase.purchaseToken),
-          throwsAssertionError);
-    });
-
-    test(
-        'serializes and deserializes data on change subscription without proration',
-        () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-        name: launchMethodName,
-        value: buildBillingResultMap(expectedBillingResult),
-      );
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-      final String accountId = 'hashedAccountId';
-      final String profileId = 'hashedProfileId';
-
-      expect(
-          await billingClient.launchBillingFlow(
-              sku: skuDetails.sku,
-              accountId: accountId,
-              obfuscatedProfileId: profileId,
-              oldSku: dummyOldPurchase.sku,
-              purchaseToken: dummyOldPurchase.purchaseToken),
-          equals(expectedBillingResult));
-      Map<dynamic, dynamic> arguments =
-          stubPlatform.previousCallMatching(launchMethodName).arguments;
-      expect(arguments['sku'], equals(skuDetails.sku));
-      expect(arguments['accountId'], equals(accountId));
-      expect(arguments['oldSku'], equals(dummyOldPurchase.sku));
-      expect(
-          arguments['purchaseToken'], equals(dummyOldPurchase.purchaseToken));
-      expect(arguments['obfuscatedProfileId'], equals(profileId));
-    });
-
-    test(
-        'serializes and deserializes data on change subscription with proration',
-        () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-        name: launchMethodName,
-        value: buildBillingResultMap(expectedBillingResult),
-      );
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-      final String accountId = 'hashedAccountId';
-      final String profileId = 'hashedProfileId';
-      final prorationMode = ProrationMode.immediateAndChargeProratedPrice;
-
-      expect(
-          await billingClient.launchBillingFlow(
-              sku: skuDetails.sku,
-              accountId: accountId,
-              obfuscatedProfileId: profileId,
-              oldSku: dummyOldPurchase.sku,
-              prorationMode: prorationMode,
-              purchaseToken: dummyOldPurchase.purchaseToken),
-          equals(expectedBillingResult));
-      Map<dynamic, dynamic> arguments =
-          stubPlatform.previousCallMatching(launchMethodName).arguments;
-      expect(arguments['sku'], equals(skuDetails.sku));
-      expect(arguments['accountId'], equals(accountId));
-      expect(arguments['oldSku'], equals(dummyOldPurchase.sku));
-      expect(arguments['obfuscatedProfileId'], equals(profileId));
-      expect(
-          arguments['purchaseToken'], equals(dummyOldPurchase.purchaseToken));
-      expect(arguments['prorationMode'],
-          ProrationModeConverter().toJson(prorationMode));
-    });
-
-    test('handles null accountId', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-        name: launchMethodName,
-        value: buildBillingResultMap(expectedBillingResult),
-      );
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-
-      expect(await billingClient.launchBillingFlow(sku: skuDetails.sku),
-          equals(expectedBillingResult));
-      Map<dynamic, dynamic> arguments =
-          stubPlatform.previousCallMatching(launchMethodName).arguments;
-      expect(arguments['sku'], equals(skuDetails.sku));
-      expect(arguments['accountId'], isNull);
-    });
-
-    test('handles method channel returning null', () async {
-      stubPlatform.addResponse(
-        name: launchMethodName,
-        value: null,
-      );
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-      expect(
-          await billingClient.launchBillingFlow(sku: skuDetails.sku),
-          equals(BillingResultWrapper(
-              responseCode: BillingResponse.error,
-              debugMessage: kInvalidBillingResultErrorMessage)));
-    });
-  });
-
-  group('queryPurchases', () {
-    const String queryPurchasesMethodName =
-        'BillingClient#queryPurchases(String)';
-
-    test('serializes and deserializes data', () async {
-      final BillingResponse expectedCode = BillingResponse.ok;
-      final List<PurchaseWrapper> expectedList = <PurchaseWrapper>[
-        dummyPurchase
-      ];
-      const String debugMessage = 'dummy message';
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform
-          .addResponse(name: queryPurchasesMethodName, value: <String, dynamic>{
-        'billingResult': buildBillingResultMap(expectedBillingResult),
-        'responseCode': BillingResponseConverter().toJson(expectedCode),
-        'purchasesList': expectedList
-            .map((PurchaseWrapper purchase) => buildPurchaseMap(purchase))
-            .toList(),
-      });
-
-      final PurchasesResultWrapper response =
-          await billingClient.queryPurchases(SkuType.inapp);
-
-      expect(response.billingResult, equals(expectedBillingResult));
-      expect(response.responseCode, equals(expectedCode));
-      expect(response.purchasesList, equals(expectedList));
-    });
-
-    test('handles empty purchases', () async {
-      final BillingResponse expectedCode = BillingResponse.userCanceled;
-      const String debugMessage = 'dummy message';
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform
-          .addResponse(name: queryPurchasesMethodName, value: <String, dynamic>{
-        'billingResult': buildBillingResultMap(expectedBillingResult),
-        'responseCode': BillingResponseConverter().toJson(expectedCode),
-        'purchasesList': [],
-      });
-
-      final PurchasesResultWrapper response =
-          await billingClient.queryPurchases(SkuType.inapp);
-
-      expect(response.billingResult, equals(expectedBillingResult));
-      expect(response.responseCode, equals(expectedCode));
-      expect(response.purchasesList, isEmpty);
-    });
-
-    test('handles method channel returning null', () async {
-      stubPlatform.addResponse(
-        name: queryPurchasesMethodName,
-        value: null,
-      );
-      final PurchasesResultWrapper response =
-          await billingClient.queryPurchases(SkuType.inapp);
-
-      expect(
-          response.billingResult,
-          equals(BillingResultWrapper(
-              responseCode: BillingResponse.error,
-              debugMessage: kInvalidBillingResultErrorMessage)));
-      expect(response.responseCode, BillingResponse.error);
-      expect(response.purchasesList, isEmpty);
-    });
-  });
-
-  group('queryPurchaseHistory', () {
-    const String queryPurchaseHistoryMethodName =
-        'BillingClient#queryPurchaseHistoryAsync(String, PurchaseHistoryResponseListener)';
-
-    test('serializes and deserializes data', () async {
-      final BillingResponse expectedCode = BillingResponse.ok;
-      final List<PurchaseHistoryRecordWrapper> expectedList =
-          <PurchaseHistoryRecordWrapper>[
-        dummyPurchaseHistoryRecord,
-      ];
-      const String debugMessage = 'dummy message';
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-          name: queryPurchaseHistoryMethodName,
-          value: <String, dynamic>{
-            'billingResult': buildBillingResultMap(expectedBillingResult),
-            'purchaseHistoryRecordList': expectedList
-                .map((PurchaseHistoryRecordWrapper purchaseHistoryRecord) =>
-                    buildPurchaseHistoryRecordMap(purchaseHistoryRecord))
-                .toList(),
-          });
-
-      final PurchasesHistoryResult response =
-          await billingClient.queryPurchaseHistory(SkuType.inapp);
-      expect(response.billingResult, equals(expectedBillingResult));
-      expect(response.purchaseHistoryRecordList, equals(expectedList));
-    });
-
-    test('handles empty purchases', () async {
-      final BillingResponse expectedCode = BillingResponse.userCanceled;
-      const String debugMessage = 'dummy message';
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(name: queryPurchaseHistoryMethodName, value: {
-        'billingResult': buildBillingResultMap(expectedBillingResult),
-        'purchaseHistoryRecordList': [],
-      });
-
-      final PurchasesHistoryResult response =
-          await billingClient.queryPurchaseHistory(SkuType.inapp);
-
-      expect(response.billingResult, equals(expectedBillingResult));
-      expect(response.purchaseHistoryRecordList, isEmpty);
-    });
-
-    test('handles method channel returning null', () async {
-      stubPlatform.addResponse(
-        name: queryPurchaseHistoryMethodName,
-        value: null,
-      );
-      final PurchasesHistoryResult response =
-          await billingClient.queryPurchaseHistory(SkuType.inapp);
-
-      expect(
-          response.billingResult,
-          equals(BillingResultWrapper(
-              responseCode: BillingResponse.error,
-              debugMessage: kInvalidBillingResultErrorMessage)));
-      expect(response.purchaseHistoryRecordList, isEmpty);
-    });
-  });
-
-  group('consume purchases', () {
-    const String consumeMethodName =
-        'BillingClient#consumeAsync(String, ConsumeResponseListener)';
-    test('consume purchase async success', () async {
-      final BillingResponse expectedCode = BillingResponse.ok;
-      const String debugMessage = 'dummy message';
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-          name: consumeMethodName,
-          value: buildBillingResultMap(expectedBillingResult));
-
-      final BillingResultWrapper billingResult =
-          await billingClient.consumeAsync('dummy token');
-
-      expect(billingResult, equals(expectedBillingResult));
-    });
-
-    test('handles method channel returning null', () async {
-      stubPlatform.addResponse(
-        name: consumeMethodName,
-        value: null,
-      );
-      final BillingResultWrapper billingResult =
-          await billingClient.consumeAsync('dummy token');
-
-      expect(
-          billingResult,
-          equals(BillingResultWrapper(
-              responseCode: BillingResponse.error,
-              debugMessage: kInvalidBillingResultErrorMessage)));
-    });
-  });
-
-  group('acknowledge purchases', () {
-    const String acknowledgeMethodName =
-        'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
-    test('acknowledge purchase success', () async {
-      final BillingResponse expectedCode = BillingResponse.ok;
-      const String debugMessage = 'dummy message';
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-          name: acknowledgeMethodName,
-          value: buildBillingResultMap(expectedBillingResult));
-
-      final BillingResultWrapper billingResult =
-          await billingClient.acknowledgePurchase('dummy token');
-
-      expect(billingResult, equals(expectedBillingResult));
-    });
-    test('handles method channel returning null', () async {
-      stubPlatform.addResponse(
-        name: acknowledgeMethodName,
-        value: null,
-      );
-      final BillingResultWrapper billingResult =
-          await billingClient.acknowledgePurchase('dummy token');
-
-      expect(
-          billingResult,
-          equals(BillingResultWrapper(
-              responseCode: BillingResponse.error,
-              debugMessage: kInvalidBillingResultErrorMessage)));
-    });
-  });
-}
diff --git a/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart
deleted file mode 100644
index b675526..0000000
--- a/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/purchase_wrapper_test.dart
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart';
-import 'package:test/test.dart';
-import 'package:in_app_purchase/billing_client_wrappers.dart';
-import 'package:in_app_purchase/src/billing_client_wrappers/enum_converters.dart';
-import 'package:in_app_purchase/src/in_app_purchase/in_app_purchase_connection.dart';
-
-final PurchaseWrapper dummyPurchase = PurchaseWrapper(
-  orderId: 'orderId',
-  packageName: 'packageName',
-  purchaseTime: 0,
-  signature: 'signature',
-  sku: 'sku',
-  purchaseToken: 'purchaseToken',
-  isAutoRenewing: false,
-  originalJson: '',
-  developerPayload: 'dummy payload',
-  isAcknowledged: true,
-  purchaseState: PurchaseStateWrapper.purchased,
-);
-
-final PurchaseWrapper dummyUnacknowledgedPurchase = PurchaseWrapper(
-  orderId: 'orderId',
-  packageName: 'packageName',
-  purchaseTime: 0,
-  signature: 'signature',
-  sku: 'sku',
-  purchaseToken: 'purchaseToken',
-  isAutoRenewing: false,
-  originalJson: '',
-  developerPayload: 'dummy payload',
-  isAcknowledged: false,
-  purchaseState: PurchaseStateWrapper.purchased,
-);
-
-final PurchaseHistoryRecordWrapper dummyPurchaseHistoryRecord =
-    PurchaseHistoryRecordWrapper(
-  purchaseTime: 0,
-  signature: 'signature',
-  sku: 'sku',
-  purchaseToken: 'purchaseToken',
-  originalJson: '',
-  developerPayload: 'dummy payload',
-);
-
-final PurchaseWrapper dummyOldPurchase = PurchaseWrapper(
-  orderId: 'oldOrderId',
-  packageName: 'oldPackageName',
-  purchaseTime: 0,
-  signature: 'oldSignature',
-  sku: 'oldSku',
-  purchaseToken: 'oldPurchaseToken',
-  isAutoRenewing: false,
-  originalJson: '',
-  developerPayload: 'old dummy payload',
-  isAcknowledged: true,
-  purchaseState: PurchaseStateWrapper.purchased,
-);
-
-void main() {
-  group('PurchaseWrapper', () {
-    test('converts from map', () {
-      final PurchaseWrapper expected = dummyPurchase;
-      final PurchaseWrapper parsed =
-          PurchaseWrapper.fromJson(buildPurchaseMap(expected));
-
-      expect(parsed, equals(expected));
-    });
-
-    test('toPurchaseDetails() should return correct PurchaseDetail object', () {
-      final PurchaseDetails details =
-          PurchaseDetails.fromPurchase(dummyPurchase);
-      expect(details.purchaseID, dummyPurchase.orderId);
-      expect(details.productID, dummyPurchase.sku);
-      expect(details.transactionDate, dummyPurchase.purchaseTime.toString());
-      expect(details.verificationData, isNotNull);
-      expect(details.verificationData.source, IAPSource.GooglePlay);
-      expect(details.verificationData.localVerificationData,
-          dummyPurchase.originalJson);
-      expect(details.verificationData.serverVerificationData,
-          dummyPurchase.purchaseToken);
-      expect(details.skPaymentTransaction, null);
-      expect(details.billingClientPurchase, dummyPurchase);
-      expect(details.pendingCompletePurchase, true);
-    });
-  });
-
-  group('PurchaseHistoryRecordWrapper', () {
-    test('converts from map', () {
-      final PurchaseHistoryRecordWrapper expected = dummyPurchaseHistoryRecord;
-      final PurchaseHistoryRecordWrapper parsed =
-          PurchaseHistoryRecordWrapper.fromJson(
-              buildPurchaseHistoryRecordMap(expected));
-
-      expect(parsed, equals(expected));
-    });
-  });
-
-  group('PurchasesResultWrapper', () {
-    test('parsed from map', () {
-      final BillingResponse responseCode = BillingResponse.ok;
-      final List<PurchaseWrapper> purchases = <PurchaseWrapper>[
-        dummyPurchase,
-        dummyPurchase
-      ];
-      const String debugMessage = 'dummy Message';
-      final BillingResultWrapper billingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      final PurchasesResultWrapper expected = PurchasesResultWrapper(
-          billingResult: billingResult,
-          responseCode: responseCode,
-          purchasesList: purchases);
-      final PurchasesResultWrapper parsed =
-          PurchasesResultWrapper.fromJson(<String, dynamic>{
-        'billingResult': buildBillingResultMap(billingResult),
-        'responseCode': BillingResponseConverter().toJson(responseCode),
-        'purchasesList': <Map<String, dynamic>>[
-          buildPurchaseMap(dummyPurchase),
-          buildPurchaseMap(dummyPurchase)
-        ]
-      });
-      expect(parsed.billingResult, equals(expected.billingResult));
-      expect(parsed.responseCode, equals(expected.responseCode));
-      expect(parsed.purchasesList, containsAll(expected.purchasesList));
-    });
-
-    test('parsed from empty map', () {
-      final PurchasesResultWrapper parsed =
-          PurchasesResultWrapper.fromJson(<String, dynamic>{});
-      expect(
-          parsed.billingResult,
-          equals(BillingResultWrapper(
-              responseCode: BillingResponse.error,
-              debugMessage: kInvalidBillingResultErrorMessage)));
-      expect(parsed.responseCode, BillingResponse.error);
-      expect(parsed.purchasesList, isEmpty);
-    });
-  });
-
-  group('PurchasesHistoryResult', () {
-    test('parsed from map', () {
-      final BillingResponse responseCode = BillingResponse.ok;
-      final List<PurchaseHistoryRecordWrapper> purchaseHistoryRecordList =
-          <PurchaseHistoryRecordWrapper>[
-        dummyPurchaseHistoryRecord,
-        dummyPurchaseHistoryRecord
-      ];
-      const String debugMessage = 'dummy Message';
-      final BillingResultWrapper billingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      final PurchasesHistoryResult expected = PurchasesHistoryResult(
-          billingResult: billingResult,
-          purchaseHistoryRecordList: purchaseHistoryRecordList);
-      final PurchasesHistoryResult parsed =
-          PurchasesHistoryResult.fromJson(<String, dynamic>{
-        'billingResult': buildBillingResultMap(billingResult),
-        'purchaseHistoryRecordList': <Map<String, dynamic>>[
-          buildPurchaseHistoryRecordMap(dummyPurchaseHistoryRecord),
-          buildPurchaseHistoryRecordMap(dummyPurchaseHistoryRecord)
-        ]
-      });
-      expect(parsed.billingResult, equals(billingResult));
-      expect(parsed.purchaseHistoryRecordList,
-          containsAll(expected.purchaseHistoryRecordList));
-    });
-
-    test('parsed from empty map', () {
-      final PurchasesHistoryResult parsed =
-          PurchasesHistoryResult.fromJson(<String, dynamic>{});
-      expect(
-          parsed.billingResult,
-          equals(BillingResultWrapper(
-              responseCode: BillingResponse.error,
-              debugMessage: kInvalidBillingResultErrorMessage)));
-      expect(parsed.purchaseHistoryRecordList, isEmpty);
-    });
-  });
-}
-
-Map<String, dynamic> buildPurchaseMap(PurchaseWrapper original) {
-  return <String, dynamic>{
-    'orderId': original.orderId,
-    'packageName': original.packageName,
-    'purchaseTime': original.purchaseTime,
-    'signature': original.signature,
-    'sku': original.sku,
-    'purchaseToken': original.purchaseToken,
-    'isAutoRenewing': original.isAutoRenewing,
-    'originalJson': original.originalJson,
-    'developerPayload': original.developerPayload,
-    'purchaseState': PurchaseStateConverter().toJson(original.purchaseState),
-    'isAcknowledged': original.isAcknowledged,
-  };
-}
-
-Map<String, dynamic> buildPurchaseHistoryRecordMap(
-    PurchaseHistoryRecordWrapper original) {
-  return <String, dynamic>{
-    'purchaseTime': original.purchaseTime,
-    'signature': original.signature,
-    'sku': original.sku,
-    'purchaseToken': original.purchaseToken,
-    'originalJson': original.originalJson,
-    'developerPayload': original.developerPayload,
-  };
-}
-
-Map<String, dynamic> buildBillingResultMap(BillingResultWrapper original) {
-  return <String, dynamic>{
-    'responseCode': BillingResponseConverter().toJson(original.responseCode),
-    'debugMessage': original.debugMessage,
-  };
-}
diff --git a/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart
deleted file mode 100644
index 74af472..0000000
--- a/packages/in_app_purchase/in_app_purchase/test/billing_client_wrappers/sku_details_wrapper_test.dart
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:test/test.dart';
-import 'package:in_app_purchase/billing_client_wrappers.dart';
-import 'package:in_app_purchase/src/in_app_purchase/product_details.dart';
-import 'package:in_app_purchase/src/billing_client_wrappers/enum_converters.dart';
-
-final SkuDetailsWrapper dummySkuDetails = SkuDetailsWrapper(
-  description: 'description',
-  freeTrialPeriod: 'freeTrialPeriod',
-  introductoryPrice: 'introductoryPrice',
-  introductoryPriceMicros: 'introductoryPriceMicros',
-  introductoryPriceCycles: 1,
-  introductoryPricePeriod: 'introductoryPricePeriod',
-  price: 'price',
-  priceAmountMicros: 1000,
-  priceCurrencyCode: 'priceCurrencyCode',
-  sku: 'sku',
-  subscriptionPeriod: 'subscriptionPeriod',
-  title: 'title',
-  type: SkuType.inapp,
-  originalPrice: 'originalPrice',
-  originalPriceAmountMicros: 1000,
-);
-
-void main() {
-  group('SkuDetailsWrapper', () {
-    test('converts from map', () {
-      final SkuDetailsWrapper expected = dummySkuDetails;
-      final SkuDetailsWrapper parsed =
-          SkuDetailsWrapper.fromJson(buildSkuMap(expected));
-
-      expect(parsed, equals(expected));
-    });
-  });
-
-  group('SkuDetailsResponseWrapper', () {
-    test('parsed from map', () {
-      final BillingResponse responseCode = BillingResponse.ok;
-      const String debugMessage = 'dummy message';
-      final List<SkuDetailsWrapper> skusDetails = <SkuDetailsWrapper>[
-        dummySkuDetails,
-        dummySkuDetails
-      ];
-      BillingResultWrapper result = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      final SkuDetailsResponseWrapper expected = SkuDetailsResponseWrapper(
-          billingResult: result, skuDetailsList: skusDetails);
-
-      final SkuDetailsResponseWrapper parsed =
-          SkuDetailsResponseWrapper.fromJson(<String, dynamic>{
-        'billingResult': <String, dynamic>{
-          'responseCode': BillingResponseConverter().toJson(responseCode),
-          'debugMessage': debugMessage,
-        },
-        'skuDetailsList': <Map<String, dynamic>>[
-          buildSkuMap(dummySkuDetails),
-          buildSkuMap(dummySkuDetails)
-        ]
-      });
-
-      expect(parsed.billingResult, equals(expected.billingResult));
-      expect(parsed.skuDetailsList, containsAll(expected.skuDetailsList));
-    });
-
-    test('toProductDetails() should return correct Product object', () {
-      final SkuDetailsWrapper wrapper =
-          SkuDetailsWrapper.fromJson(buildSkuMap(dummySkuDetails));
-      final ProductDetails product = ProductDetails.fromSkuDetails(wrapper);
-      expect(product.title, wrapper.title);
-      expect(product.description, wrapper.description);
-      expect(product.id, wrapper.sku);
-      expect(product.price, wrapper.price);
-      expect(product.skuDetail, wrapper);
-      expect(product.skProduct, null);
-    });
-
-    test('handles empty list of skuDetails', () {
-      final BillingResponse responseCode = BillingResponse.error;
-      const String debugMessage = 'dummy message';
-      final List<SkuDetailsWrapper> skusDetails = <SkuDetailsWrapper>[];
-      BillingResultWrapper billingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      final SkuDetailsResponseWrapper expected = SkuDetailsResponseWrapper(
-          billingResult: billingResult, skuDetailsList: skusDetails);
-
-      final SkuDetailsResponseWrapper parsed =
-          SkuDetailsResponseWrapper.fromJson(<String, dynamic>{
-        'billingResult': <String, dynamic>{
-          'responseCode': BillingResponseConverter().toJson(responseCode),
-          'debugMessage': debugMessage,
-        },
-        'skuDetailsList': <Map<String, dynamic>>[]
-      });
-
-      expect(parsed.billingResult, equals(expected.billingResult));
-      expect(parsed.skuDetailsList, containsAll(expected.skuDetailsList));
-    });
-
-    test('fromJson creates an object with default values', () {
-      final SkuDetailsResponseWrapper skuDetails =
-          SkuDetailsResponseWrapper.fromJson(<String, dynamic>{});
-      expect(
-          skuDetails.billingResult,
-          equals(BillingResultWrapper(
-              responseCode: BillingResponse.error,
-              debugMessage: kInvalidBillingResultErrorMessage)));
-      expect(skuDetails.skuDetailsList, isEmpty);
-    });
-  });
-
-  group('BillingResultWrapper', () {
-    test('fromJson on empty map creates an object with default values', () {
-      final BillingResultWrapper billingResult =
-          BillingResultWrapper.fromJson(<String, dynamic>{});
-      expect(billingResult.debugMessage, kInvalidBillingResultErrorMessage);
-      expect(billingResult.responseCode, BillingResponse.error);
-    });
-
-    test('fromJson on null creates an object with default values', () {
-      final BillingResultWrapper billingResult =
-          BillingResultWrapper.fromJson(null);
-      expect(billingResult.debugMessage, kInvalidBillingResultErrorMessage);
-      expect(billingResult.responseCode, BillingResponse.error);
-    });
-  });
-}
-
-Map<String, dynamic> buildSkuMap(SkuDetailsWrapper original) {
-  return <String, dynamic>{
-    'description': original.description,
-    'freeTrialPeriod': original.freeTrialPeriod,
-    'introductoryPrice': original.introductoryPrice,
-    'introductoryPriceMicros': original.introductoryPriceMicros,
-    'introductoryPriceCycles': original.introductoryPriceCycles,
-    'introductoryPricePeriod': original.introductoryPricePeriod,
-    'price': original.price,
-    'priceAmountMicros': original.priceAmountMicros,
-    'priceCurrencyCode': original.priceCurrencyCode,
-    'sku': original.sku,
-    'subscriptionPeriod': original.subscriptionPeriod,
-    'title': original.title,
-    'type': original.type.toString().substring(8),
-    'originalPrice': original.originalPrice,
-    'originalPriceAmountMicros': original.originalPriceAmountMicros,
-  };
-}
diff --git a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart
deleted file mode 100644
index c112829..0000000
--- a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart
+++ /dev/null
@@ -1,483 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:flutter/services.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart';
-
-import 'package:in_app_purchase/src/channel.dart';
-import 'package:in_app_purchase/src/in_app_purchase/app_store_connection.dart';
-import 'package:in_app_purchase/src/in_app_purchase/in_app_purchase_connection.dart';
-import 'package:in_app_purchase/src/in_app_purchase/product_details.dart';
-import 'package:in_app_purchase/store_kit_wrappers.dart';
-import '../billing_client_wrappers/purchase_wrapper_test.dart';
-import '../store_kit_wrappers/sk_test_stub_objects.dart';
-
-void main() {
-  TestWidgetsFlutterBinding.ensureInitialized();
-
-  final FakeIOSPlatform fakeIOSPlatform = FakeIOSPlatform();
-
-  setUpAll(() {
-    SystemChannels.platform
-        .setMockMethodCallHandler(fakeIOSPlatform.onMethodCall);
-  });
-
-  setUp(() => fakeIOSPlatform.reset());
-
-  tearDown(() => fakeIOSPlatform.reset());
-
-  group('isAvailable', () {
-    test('true', () async {
-      expect(await AppStoreConnection.instance.isAvailable(), isTrue);
-    });
-  });
-
-  group('query product list', () {
-    test('should get product list and correct invalid identifiers', () async {
-      final AppStoreConnection connection = AppStoreConnection();
-      final ProductDetailsResponse response = await connection
-          .queryProductDetails(<String>['123', '456', '789'].toSet());
-      List<ProductDetails> products = response.productDetails;
-      expect(products.first.id, '123');
-      expect(products[1].id, '456');
-      expect(response.notFoundIDs, ['789']);
-      expect(response.error, isNull);
-    });
-
-    test(
-        'if query products throws error, should get error object in the response',
-        () async {
-      fakeIOSPlatform.queryProductException = PlatformException(
-          code: 'error_code',
-          message: 'error_message',
-          details: {'info': 'error_info'});
-      final AppStoreConnection connection = AppStoreConnection();
-      final ProductDetailsResponse response = await connection
-          .queryProductDetails(<String>['123', '456', '789'].toSet());
-      expect(response.productDetails, []);
-      expect(response.notFoundIDs, ['123', '456', '789']);
-      expect(response.error, isNotNull);
-      expect(response.error!.source, IAPSource.AppStore);
-      expect(response.error!.code, 'error_code');
-      expect(response.error!.message, 'error_message');
-      expect(response.error!.details, {'info': 'error_info'});
-    });
-  });
-
-  group('query purchases list', () {
-    test('should get purchase list', () async {
-      QueryPurchaseDetailsResponse response =
-          await AppStoreConnection.instance.queryPastPurchases();
-      expect(response.pastPurchases.length, 2);
-      expect(response.pastPurchases.first.purchaseID,
-          fakeIOSPlatform.transactions.first.transactionIdentifier);
-      expect(response.pastPurchases.last.purchaseID,
-          fakeIOSPlatform.transactions.last.transactionIdentifier);
-      expect(response.pastPurchases.first.purchaseID,
-          fakeIOSPlatform.transactions.first.transactionIdentifier);
-      expect(response.pastPurchases.last.purchaseID,
-          fakeIOSPlatform.transactions.last.transactionIdentifier);
-      expect(response.pastPurchases, isNotEmpty);
-      expect(response.pastPurchases.first.verificationData, isNotNull);
-      expect(
-          response.pastPurchases.first.verificationData.localVerificationData,
-          'dummy base64data');
-      expect(
-          response.pastPurchases.first.verificationData.serverVerificationData,
-          'dummy base64data');
-      expect(response.error, isNull);
-    });
-
-    test('queryPastPurchases should not block transaction updates', () async {
-      fakeIOSPlatform.transactions
-          .add(fakeIOSPlatform.createPurchasedTransaction('foo', 'bar'));
-      Completer completer = Completer();
-      Stream<List<PurchaseDetails>> stream =
-          AppStoreConnection.instance.purchaseUpdatedStream;
-
-      late StreamSubscription subscription;
-      subscription = stream.listen((purchaseDetailsList) {
-        if (purchaseDetailsList.first.status == PurchaseStatus.purchased) {
-          completer.complete(purchaseDetailsList);
-          subscription.cancel();
-        }
-      });
-      QueryPurchaseDetailsResponse response =
-          await AppStoreConnection.instance.queryPastPurchases();
-      List<PurchaseDetails> result = await completer.future;
-      expect(result.length, 1);
-      expect(result.first.productID, 'foo');
-      expect(response.error, isNull);
-    });
-
-    test('should get empty result if there is no restored transactions',
-        () async {
-      fakeIOSPlatform.testRestoredTransactionsNull = true;
-      QueryPurchaseDetailsResponse response =
-          await AppStoreConnection.instance.queryPastPurchases();
-      expect(response.pastPurchases, isEmpty);
-      expect(response.error, isNull);
-      fakeIOSPlatform.testRestoredTransactionsNull = false;
-    });
-
-    test('test restore error', () async {
-      fakeIOSPlatform.testRestoredError = SKError(
-          code: 123,
-          domain: 'error_test',
-          userInfo: {'message': 'errorMessage'});
-      QueryPurchaseDetailsResponse response =
-          await AppStoreConnection.instance.queryPastPurchases();
-      expect(response.pastPurchases, isEmpty);
-      expect(response.error, isNotNull);
-      expect(response.error!.source, IAPSource.AppStore);
-      expect(response.error!.message, 'error_test');
-      expect(response.error!.details, {'message': 'errorMessage'});
-    });
-
-    test('receipt error should populate null to verificationData.data',
-        () async {
-      fakeIOSPlatform.receiptData = null;
-      QueryPurchaseDetailsResponse response =
-          await AppStoreConnection.instance.queryPastPurchases();
-      expect(
-          response.pastPurchases.first.verificationData.localVerificationData,
-          isEmpty);
-      expect(
-          response.pastPurchases.first.verificationData.serverVerificationData,
-          isEmpty);
-    });
-  });
-
-  group('refresh receipt data', () {
-    test('should refresh receipt data', () async {
-      PurchaseVerificationData? receiptData =
-          await AppStoreConnection.instance.refreshPurchaseVerificationData();
-      expect(receiptData, isNotNull);
-      expect(receiptData!.source, IAPSource.AppStore);
-      expect(receiptData.localVerificationData, 'refreshed receipt data');
-      expect(receiptData.serverVerificationData, 'refreshed receipt data');
-    });
-  });
-
-  group('make payment', () {
-    test(
-        'buying non consumable, should get purchase objects in the purchase update callback',
-        () async {
-      List<PurchaseDetails> details = [];
-      Completer completer = Completer();
-      Stream<List<PurchaseDetails>> stream =
-          AppStoreConnection.instance.purchaseUpdatedStream;
-
-      late StreamSubscription subscription;
-      subscription = stream.listen((purchaseDetailsList) {
-        details.addAll(purchaseDetailsList);
-        if (purchaseDetailsList.first.status == PurchaseStatus.purchased) {
-          completer.complete(details);
-          subscription.cancel();
-        }
-      });
-      final PurchaseParam purchaseParam = PurchaseParam(
-          productDetails: ProductDetails.fromSKProduct(dummyProductWrapper),
-          applicationUserName: 'appName');
-      await AppStoreConnection.instance
-          .buyNonConsumable(purchaseParam: purchaseParam);
-
-      List<PurchaseDetails> result = await completer.future;
-      expect(result.length, 2);
-      expect(result.first.productID, dummyProductWrapper.productIdentifier);
-    });
-
-    test(
-        'buying consumable, should get purchase objects in the purchase update callback',
-        () async {
-      List<PurchaseDetails> details = [];
-      Completer completer = Completer();
-      Stream<List<PurchaseDetails>> stream =
-          AppStoreConnection.instance.purchaseUpdatedStream;
-
-      late StreamSubscription subscription;
-      subscription = stream.listen((purchaseDetailsList) {
-        details.addAll(purchaseDetailsList);
-        if (purchaseDetailsList.first.status == PurchaseStatus.purchased) {
-          completer.complete(details);
-          subscription.cancel();
-        }
-      });
-      final PurchaseParam purchaseParam = PurchaseParam(
-          productDetails: ProductDetails.fromSKProduct(dummyProductWrapper),
-          applicationUserName: 'appName');
-      await AppStoreConnection.instance
-          .buyConsumable(purchaseParam: purchaseParam);
-
-      List<PurchaseDetails> result = await completer.future;
-      expect(result.length, 2);
-      expect(result.first.productID, dummyProductWrapper.productIdentifier);
-    });
-
-    test('buying consumable, should throw when autoConsume is false', () async {
-      final PurchaseParam purchaseParam = PurchaseParam(
-          productDetails: ProductDetails.fromSKProduct(dummyProductWrapper),
-          applicationUserName: 'appName');
-      expect(
-          () => AppStoreConnection.instance
-              .buyConsumable(purchaseParam: purchaseParam, autoConsume: false),
-          throwsA(isInstanceOf<AssertionError>()));
-    });
-
-    test('should get failed purchase status', () async {
-      fakeIOSPlatform.testTransactionFail = true;
-      List<PurchaseDetails> details = [];
-      Completer completer = Completer();
-      late IAPError error;
-
-      Stream<List<PurchaseDetails>> stream =
-          AppStoreConnection.instance.purchaseUpdatedStream;
-      late StreamSubscription subscription;
-      subscription = stream.listen((purchaseDetailsList) {
-        details.addAll(purchaseDetailsList);
-        purchaseDetailsList.forEach((purchaseDetails) {
-          if (purchaseDetails.status == PurchaseStatus.error) {
-            error = purchaseDetails.error!;
-            completer.complete(error);
-            subscription.cancel();
-          }
-        });
-      });
-      final PurchaseParam purchaseParam = PurchaseParam(
-          productDetails: ProductDetails.fromSKProduct(dummyProductWrapper),
-          applicationUserName: 'appName');
-      await AppStoreConnection.instance
-          .buyNonConsumable(purchaseParam: purchaseParam);
-
-      IAPError completerError = await completer.future;
-      expect(completerError.code, 'purchase_error');
-      expect(completerError.source, IAPSource.AppStore);
-      expect(completerError.message, 'ios_domain');
-      expect(completerError.details, {'message': 'an error message'});
-    });
-  });
-
-  group('complete purchase', () {
-    test('should complete purchase', () async {
-      List<PurchaseDetails> details = [];
-      Completer completer = Completer();
-      Stream<List<PurchaseDetails>> stream =
-          AppStoreConnection.instance.purchaseUpdatedStream;
-      late StreamSubscription subscription;
-      subscription = stream.listen((purchaseDetailsList) {
-        details.addAll(purchaseDetailsList);
-        purchaseDetailsList.forEach((purchaseDetails) {
-          if (purchaseDetails.pendingCompletePurchase) {
-            AppStoreConnection.instance.completePurchase(purchaseDetails);
-            completer.complete(details);
-            subscription.cancel();
-          }
-        });
-      });
-      final PurchaseParam purchaseParam = PurchaseParam(
-          productDetails: ProductDetails.fromSKProduct(dummyProductWrapper),
-          applicationUserName: 'appName');
-      await AppStoreConnection.instance
-          .buyNonConsumable(purchaseParam: purchaseParam);
-      List<PurchaseDetails> result = await completer.future;
-      expect(result.length, 2);
-      expect(result.first.productID, dummyProductWrapper.productIdentifier);
-      expect(fakeIOSPlatform.finishedTransactions.length, 1);
-    });
-  });
-
-  group('consume purchase', () {
-    test('should throw when calling consume purchase on iOS', () async {
-      expect(
-        () => AppStoreConnection.instance
-            .consumePurchase(PurchaseDetails.fromPurchase(dummyPurchase)),
-        throwsA(
-          isA<UnsupportedError>().having(
-            (error) => error.message,
-            'message',
-            'consume purchase is not available on iOS',
-          ),
-        ),
-      );
-    });
-  });
-
-  group('present code redemption sheet', () {
-    test('null', () async {
-      expect(
-          await AppStoreConnection.instance.presentCodeRedemptionSheet(), null);
-    });
-  });
-}
-
-class FakeIOSPlatform {
-  FakeIOSPlatform() {
-    channel.setMockMethodCallHandler(onMethodCall);
-  }
-
-  // pre-configured store informations
-  String? receiptData;
-  late Set<String> validProductIDs;
-  late Map<String, SKProductWrapper> validProducts;
-  late List<SKPaymentTransactionWrapper> transactions;
-  late List<SKPaymentTransactionWrapper> finishedTransactions;
-  late bool testRestoredTransactionsNull;
-  late bool testTransactionFail;
-  PlatformException? queryProductException;
-  PlatformException? restoreException;
-  SKError? testRestoredError;
-
-  void reset() {
-    transactions = [];
-    receiptData = 'dummy base64data';
-    validProductIDs = ['123', '456'].toSet();
-    validProducts = Map();
-    for (String validID in validProductIDs) {
-      Map<String, dynamic> productWrapperMap =
-          buildProductMap(dummyProductWrapper);
-      productWrapperMap['productIdentifier'] = validID;
-      validProducts[validID] = SKProductWrapper.fromJson(productWrapperMap);
-    }
-
-    SKPaymentTransactionWrapper tran1 = SKPaymentTransactionWrapper(
-      transactionIdentifier: '123',
-      payment: dummyPayment,
-      originalTransaction: dummyTransaction,
-      transactionTimeStamp: 123123123.022,
-      transactionState: SKPaymentTransactionStateWrapper.restored,
-      error: null,
-    );
-    SKPaymentTransactionWrapper tran2 = SKPaymentTransactionWrapper(
-      transactionIdentifier: '1234',
-      payment: dummyPayment,
-      originalTransaction: dummyTransaction,
-      transactionTimeStamp: 123123123.022,
-      transactionState: SKPaymentTransactionStateWrapper.restored,
-      error: null,
-    );
-
-    transactions.addAll([tran1, tran2]);
-    finishedTransactions = [];
-    testRestoredTransactionsNull = false;
-    testTransactionFail = false;
-    queryProductException = null;
-    restoreException = null;
-    testRestoredError = null;
-  }
-
-  SKPaymentTransactionWrapper createPendingTransaction(String id) {
-    return SKPaymentTransactionWrapper(
-        transactionIdentifier: '',
-        payment: SKPaymentWrapper(productIdentifier: id),
-        transactionState: SKPaymentTransactionStateWrapper.purchasing,
-        transactionTimeStamp: 123123.121,
-        error: null,
-        originalTransaction: null);
-  }
-
-  SKPaymentTransactionWrapper createPurchasedTransaction(
-      String productId, String transactionId) {
-    return SKPaymentTransactionWrapper(
-        payment: SKPaymentWrapper(productIdentifier: productId),
-        transactionState: SKPaymentTransactionStateWrapper.purchased,
-        transactionTimeStamp: 123123.121,
-        transactionIdentifier: transactionId,
-        error: null,
-        originalTransaction: null);
-  }
-
-  SKPaymentTransactionWrapper createFailedTransaction(String productId) {
-    return SKPaymentTransactionWrapper(
-        transactionIdentifier: '',
-        payment: SKPaymentWrapper(productIdentifier: productId),
-        transactionState: SKPaymentTransactionStateWrapper.failed,
-        transactionTimeStamp: 123123.121,
-        error: SKError(
-            code: 0,
-            domain: 'ios_domain',
-            userInfo: {'message': 'an error message'}),
-        originalTransaction: null);
-  }
-
-  Future<dynamic> onMethodCall(MethodCall call) {
-    switch (call.method) {
-      case '-[SKPaymentQueue canMakePayments:]':
-        return Future<bool>.value(true);
-      case '-[InAppPurchasePlugin startProductRequest:result:]':
-        if (queryProductException != null) {
-          throw queryProductException!;
-        }
-        List<String> productIDS =
-            List.castFrom<dynamic, String>(call.arguments);
-        assert(productIDS is List<String>, 'invalid argument type');
-        List<String> invalidFound = [];
-        List<SKProductWrapper> products = [];
-        for (String productID in productIDS) {
-          if (!validProductIDs.contains(productID)) {
-            invalidFound.add(productID);
-          } else {
-            products.add(validProducts[productID]!);
-          }
-        }
-        SkProductResponseWrapper response = SkProductResponseWrapper(
-            products: products, invalidProductIdentifiers: invalidFound);
-        return Future<Map<String, dynamic>>.value(
-            buildProductResponseMap(response));
-      case '-[InAppPurchasePlugin restoreTransactions:result:]':
-        if (restoreException != null) {
-          throw restoreException!;
-        }
-        if (testRestoredError != null) {
-          AppStoreConnection.observer
-              .restoreCompletedTransactionsFailed(error: testRestoredError!);
-          return Future<void>.sync(() {});
-        }
-        if (!testRestoredTransactionsNull) {
-          AppStoreConnection.observer
-              .updatedTransactions(transactions: transactions);
-        }
-        AppStoreConnection.observer
-            .paymentQueueRestoreCompletedTransactionsFinished();
-        return Future<void>.sync(() {});
-      case '-[InAppPurchasePlugin retrieveReceiptData:result:]':
-        if (receiptData != null) {
-          return Future<void>.value(receiptData);
-        } else {
-          throw PlatformException(code: 'no_receipt_data');
-        }
-      case '-[InAppPurchasePlugin refreshReceipt:result:]':
-        receiptData = 'refreshed receipt data';
-        return Future<void>.sync(() {});
-      case '-[InAppPurchasePlugin addPayment:result:]':
-        String id = call.arguments['productIdentifier'];
-        SKPaymentTransactionWrapper transaction = createPendingTransaction(id);
-        AppStoreConnection.observer
-            .updatedTransactions(transactions: [transaction]);
-        sleep(const Duration(milliseconds: 30));
-        if (testTransactionFail) {
-          SKPaymentTransactionWrapper transaction_failed =
-              createFailedTransaction(id);
-          AppStoreConnection.observer
-              .updatedTransactions(transactions: [transaction_failed]);
-        } else {
-          SKPaymentTransactionWrapper transaction_finished =
-              createPurchasedTransaction(
-                  id, transaction.transactionIdentifier ?? '');
-          AppStoreConnection.observer
-              .updatedTransactions(transactions: [transaction_finished]);
-        }
-        break;
-      case '-[InAppPurchasePlugin finishTransaction:result:]':
-        finishedTransactions.add(createPurchasedTransaction(
-            call.arguments["productIdentifier"],
-            call.arguments["transactionIdentifier"]));
-        break;
-    }
-    return Future<void>.sync(() {});
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart
deleted file mode 100644
index 25feb89..0000000
--- a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/google_play_connection_test.dart
+++ /dev/null
@@ -1,649 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-
-import 'package:flutter/services.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart';
-
-import 'package:flutter/widgets.dart' as widgets;
-import 'package:in_app_purchase/billing_client_wrappers.dart';
-import 'package:in_app_purchase/src/billing_client_wrappers/enum_converters.dart';
-import 'package:in_app_purchase/src/in_app_purchase/google_play_connection.dart';
-import 'package:in_app_purchase/src/in_app_purchase/in_app_purchase_connection.dart';
-import 'package:in_app_purchase/src/channel.dart';
-import '../stub_in_app_purchase_platform.dart';
-import 'package:in_app_purchase/src/in_app_purchase/product_details.dart';
-import '../billing_client_wrappers/sku_details_wrapper_test.dart';
-import '../billing_client_wrappers/purchase_wrapper_test.dart';
-
-void main() {
-  TestWidgetsFlutterBinding.ensureInitialized();
-
-  final StubInAppPurchasePlatform stubPlatform = StubInAppPurchasePlatform();
-  late GooglePlayConnection connection;
-  const String startConnectionCall =
-      'BillingClient#startConnection(BillingClientStateListener)';
-  const String endConnectionCall = 'BillingClient#endConnection()';
-
-  setUpAll(() {
-    channel.setMockMethodCallHandler(stubPlatform.fakeMethodCallHandler);
-  });
-
-  setUp(() {
-    widgets.WidgetsFlutterBinding.ensureInitialized();
-    const String debugMessage = 'dummy message';
-    final BillingResponse responseCode = BillingResponse.ok;
-    final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-        responseCode: responseCode, debugMessage: debugMessage);
-    stubPlatform.addResponse(
-        name: startConnectionCall,
-        value: buildBillingResultMap(expectedBillingResult));
-    stubPlatform.addResponse(name: endConnectionCall, value: null);
-    InAppPurchaseConnection.enablePendingPurchases();
-    connection = GooglePlayConnection.instance;
-  });
-
-  tearDown(() {
-    stubPlatform.reset();
-    GooglePlayConnection.reset();
-  });
-
-  group('connection management', () {
-    test('connects on initialization', () {
-      expect(stubPlatform.countPreviousCalls(startConnectionCall), equals(1));
-    });
-  });
-
-  group('isAvailable', () {
-    test('true', () async {
-      stubPlatform.addResponse(name: 'BillingClient#isReady()', value: true);
-      expect(await connection.isAvailable(), isTrue);
-    });
-
-    test('false', () async {
-      stubPlatform.addResponse(name: 'BillingClient#isReady()', value: false);
-      expect(await connection.isAvailable(), isFalse);
-    });
-  });
-
-  group('querySkuDetails', () {
-    final String queryMethodName =
-        'BillingClient#querySkuDetailsAsync(SkuDetailsParams, SkuDetailsResponseListener)';
-
-    test('handles empty skuDetails', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(name: queryMethodName, value: <String, dynamic>{
-        'billingResult': buildBillingResultMap(expectedBillingResult),
-        'skuDetailsList': [],
-      });
-
-      final ProductDetailsResponse response =
-          await connection.queryProductDetails(<String>[''].toSet());
-      expect(response.productDetails, isEmpty);
-    });
-
-    test('should get correct product details', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(name: queryMethodName, value: <String, dynamic>{
-        'billingResult': buildBillingResultMap(expectedBillingResult),
-        'skuDetailsList': <Map<String, dynamic>>[buildSkuMap(dummySkuDetails)]
-      });
-      // Since queryProductDetails makes 2 platform method calls (one for each SkuType), the result will contain 2 dummyWrapper instead
-      // of 1.
-      final ProductDetailsResponse response =
-          await connection.queryProductDetails(<String>['valid'].toSet());
-      expect(response.productDetails.first.title, dummySkuDetails.title);
-      expect(response.productDetails.first.description,
-          dummySkuDetails.description);
-      expect(response.productDetails.first.price, dummySkuDetails.price);
-    });
-
-    test('should get the correct notFoundIDs', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(name: queryMethodName, value: <String, dynamic>{
-        'billingResult': buildBillingResultMap(expectedBillingResult),
-        'skuDetailsList': <Map<String, dynamic>>[buildSkuMap(dummySkuDetails)]
-      });
-      // Since queryProductDetails makes 2 platform method calls (one for each SkuType), the result will contain 2 dummyWrapper instead
-      // of 1.
-      final ProductDetailsResponse response =
-          await connection.queryProductDetails(<String>['invalid'].toSet());
-      expect(response.notFoundIDs.first, 'invalid');
-    });
-
-    test(
-        'should have error stored in the response when platform exception is thrown',
-        () async {
-      final BillingResponse responseCode = BillingResponse.ok;
-      stubPlatform.addResponse(
-          name: queryMethodName,
-          value: <String, dynamic>{
-            'responseCode': BillingResponseConverter().toJson(responseCode),
-            'skuDetailsList': <Map<String, dynamic>>[
-              buildSkuMap(dummySkuDetails)
-            ]
-          },
-          additionalStepBeforeReturn: (_) {
-            throw PlatformException(
-              code: 'error_code',
-              message: 'error_message',
-              details: {'info': 'error_info'},
-            );
-          });
-      // Since queryProductDetails makes 2 platform method calls (one for each SkuType), the result will contain 2 dummyWrapper instead
-      // of 1.
-      final ProductDetailsResponse response =
-          await connection.queryProductDetails(<String>['invalid'].toSet());
-      expect(response.notFoundIDs, ['invalid']);
-      expect(response.productDetails, isEmpty);
-      expect(response.error, isNotNull);
-      expect(response.error!.source, IAPSource.GooglePlay);
-      expect(response.error!.code, 'error_code');
-      expect(response.error!.message, 'error_message');
-      expect(response.error!.details, {'info': 'error_info'});
-    });
-  });
-
-  group('queryPurchaseDetails', () {
-    const String queryMethodName = 'BillingClient#queryPurchases(String)';
-    test('handles error', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.developerError;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-
-      stubPlatform.addResponse(name: queryMethodName, value: <dynamic, dynamic>{
-        'billingResult': buildBillingResultMap(expectedBillingResult),
-        'responseCode': BillingResponseConverter().toJson(responseCode),
-        'purchasesList': <Map<String, dynamic>>[]
-      });
-      final QueryPurchaseDetailsResponse response =
-          await connection.queryPastPurchases();
-      expect(response.pastPurchases, isEmpty);
-      expect(response.error, isNotNull);
-      expect(
-          response.error!.message, BillingResponse.developerError.toString());
-      expect(response.error!.source, IAPSource.GooglePlay);
-    });
-
-    test('returns SkuDetailsResponseWrapper', () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse responseCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-
-      stubPlatform.addResponse(name: queryMethodName, value: <String, dynamic>{
-        'billingResult': buildBillingResultMap(expectedBillingResult),
-        'responseCode': BillingResponseConverter().toJson(responseCode),
-        'purchasesList': <Map<String, dynamic>>[
-          buildPurchaseMap(dummyPurchase),
-        ]
-      });
-
-      // Since queryPastPurchases makes 2 platform method calls (one for each SkuType), the result will contain 2 dummyWrapper instead
-      // of 1.
-      final QueryPurchaseDetailsResponse response =
-          await connection.queryPastPurchases();
-      expect(response.error, isNull);
-      expect(response.pastPurchases.first.purchaseID, dummyPurchase.orderId);
-    });
-
-    test('should store platform exception in the response', () async {
-      const String debugMessage = 'dummy message';
-
-      final BillingResponse responseCode = BillingResponse.developerError;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: responseCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-          name: queryMethodName,
-          value: <dynamic, dynamic>{
-            'responseCode': BillingResponseConverter().toJson(responseCode),
-            'billingResult': buildBillingResultMap(expectedBillingResult),
-            'purchasesList': <Map<String, dynamic>>[]
-          },
-          additionalStepBeforeReturn: (_) {
-            throw PlatformException(
-              code: 'error_code',
-              message: 'error_message',
-              details: {'info': 'error_info'},
-            );
-          });
-      final QueryPurchaseDetailsResponse response =
-          await connection.queryPastPurchases();
-      expect(response.pastPurchases, isEmpty);
-      expect(response.error, isNotNull);
-      expect(response.error!.code, 'error_code');
-      expect(response.error!.message, 'error_message');
-      expect(response.error!.details, {'info': 'error_info'});
-    });
-  });
-
-  group('refresh receipt data', () {
-    test('should throw on android', () {
-      expect(GooglePlayConnection.instance.refreshPurchaseVerificationData(),
-          throwsUnsupportedError);
-    });
-  });
-
-  group('present code redemption sheet', () {
-    test('should throw on android', () {
-      expect(GooglePlayConnection.instance.presentCodeRedemptionSheet(),
-          throwsUnsupportedError);
-    });
-  });
-
-  group('make payment', () {
-    final String launchMethodName =
-        'BillingClient#launchBillingFlow(Activity, BillingFlowParams)';
-    const String consumeMethodName =
-        'BillingClient#consumeAsync(String, ConsumeResponseListener)';
-    test('buy non consumable, serializes and deserializes data', () async {
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-      final String accountId = "hashedAccountId";
-      const String debugMessage = 'dummy message';
-      final BillingResponse sentCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: sentCode, debugMessage: debugMessage);
-
-      stubPlatform.addResponse(
-          name: launchMethodName,
-          value: buildBillingResultMap(expectedBillingResult),
-          additionalStepBeforeReturn: (_) {
-            // Mock java update purchase callback.
-            MethodCall call = MethodCall(kOnPurchasesUpdated, {
-              'billingResult': buildBillingResultMap(expectedBillingResult),
-              'responseCode': BillingResponseConverter().toJson(sentCode),
-              'purchasesList': [
-                {
-                  'orderId': 'orderID1',
-                  'sku': skuDetails.sku,
-                  'isAutoRenewing': false,
-                  'packageName': "package",
-                  'purchaseTime': 1231231231,
-                  'purchaseToken': "token",
-                  'signature': 'sign',
-                  'originalJson': 'json',
-                  'developerPayload': 'dummy payload',
-                  'isAcknowledged': true,
-                  'purchaseState': 1,
-                }
-              ]
-            });
-            connection.billingClient.callHandler(call);
-          });
-      Completer completer = Completer();
-      PurchaseDetails purchaseDetails;
-      Stream purchaseStream =
-          GooglePlayConnection.instance.purchaseUpdatedStream;
-      late StreamSubscription subscription;
-      subscription = purchaseStream.listen((_) {
-        purchaseDetails = _.first;
-        completer.complete(purchaseDetails);
-        subscription.cancel();
-      }, onDone: () {});
-      final PurchaseParam purchaseParam = PurchaseParam(
-          productDetails: ProductDetails.fromSkuDetails(skuDetails),
-          applicationUserName: accountId);
-      final bool launchResult = await GooglePlayConnection.instance
-          .buyNonConsumable(purchaseParam: purchaseParam);
-
-      PurchaseDetails result = await completer.future;
-      expect(launchResult, isTrue);
-      expect(result.purchaseID, 'orderID1');
-      expect(result.status, PurchaseStatus.purchased);
-      expect(result.productID, dummySkuDetails.sku);
-    });
-
-    test('handles an error with an empty purchases list', () async {
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-      final String accountId = "hashedAccountId";
-      const String debugMessage = 'dummy message';
-      final BillingResponse sentCode = BillingResponse.error;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: sentCode, debugMessage: debugMessage);
-
-      stubPlatform.addResponse(
-          name: launchMethodName,
-          value: buildBillingResultMap(expectedBillingResult),
-          additionalStepBeforeReturn: (_) {
-            // Mock java update purchase callback.
-            MethodCall call = MethodCall(kOnPurchasesUpdated, {
-              'billingResult': buildBillingResultMap(expectedBillingResult),
-              'responseCode': BillingResponseConverter().toJson(sentCode),
-              'purchasesList': []
-            });
-            connection.billingClient.callHandler(call);
-          });
-      Completer completer = Completer();
-      PurchaseDetails purchaseDetails;
-      Stream purchaseStream =
-          GooglePlayConnection.instance.purchaseUpdatedStream;
-      late StreamSubscription subscription;
-      subscription = purchaseStream.listen((_) {
-        purchaseDetails = _.first;
-        completer.complete(purchaseDetails);
-        subscription.cancel();
-      }, onDone: () {});
-      final PurchaseParam purchaseParam = PurchaseParam(
-          productDetails: ProductDetails.fromSkuDetails(skuDetails),
-          applicationUserName: accountId);
-      await GooglePlayConnection.instance
-          .buyNonConsumable(purchaseParam: purchaseParam);
-      PurchaseDetails result = await completer.future;
-
-      expect(result.error, isNotNull);
-      expect(result.error!.source, IAPSource.GooglePlay);
-      expect(result.status, PurchaseStatus.error);
-      expect(result.purchaseID, isEmpty);
-    });
-
-    test('buy consumable with auto consume, serializes and deserializes data',
-        () async {
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-      final String accountId = "hashedAccountId";
-      const String debugMessage = 'dummy message';
-      final BillingResponse sentCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: sentCode, debugMessage: debugMessage);
-
-      stubPlatform.addResponse(
-          name: launchMethodName,
-          value: buildBillingResultMap(expectedBillingResult),
-          additionalStepBeforeReturn: (_) {
-            // Mock java update purchase callback.
-            MethodCall call = MethodCall(kOnPurchasesUpdated, {
-              'billingResult': buildBillingResultMap(expectedBillingResult),
-              'responseCode': BillingResponseConverter().toJson(sentCode),
-              'purchasesList': [
-                {
-                  'orderId': 'orderID1',
-                  'sku': skuDetails.sku,
-                  'isAutoRenewing': false,
-                  'packageName': "package",
-                  'purchaseTime': 1231231231,
-                  'purchaseToken': "token",
-                  'signature': 'sign',
-                  'originalJson': 'json',
-                  'developerPayload': 'dummy payload',
-                  'isAcknowledged': true,
-                  'purchaseState': 1,
-                }
-              ]
-            });
-            connection.billingClient.callHandler(call);
-          });
-      Completer consumeCompleter = Completer();
-      // adding call back for consume purchase
-      final BillingResponse expectedCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResultForConsume =
-          BillingResultWrapper(
-              responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-          name: consumeMethodName,
-          value: buildBillingResultMap(expectedBillingResultForConsume),
-          additionalStepBeforeReturn: (dynamic args) {
-            String purchaseToken = args['purchaseToken'];
-            consumeCompleter.complete((purchaseToken));
-          });
-
-      Completer completer = Completer();
-      PurchaseDetails purchaseDetails;
-      Stream purchaseStream =
-          GooglePlayConnection.instance.purchaseUpdatedStream;
-      late StreamSubscription subscription;
-      subscription = purchaseStream.listen((_) {
-        purchaseDetails = _.first;
-        completer.complete(purchaseDetails);
-        subscription.cancel();
-      }, onDone: () {});
-      final PurchaseParam purchaseParam = PurchaseParam(
-          productDetails: ProductDetails.fromSkuDetails(skuDetails),
-          applicationUserName: accountId);
-      final bool launchResult = await GooglePlayConnection.instance
-          .buyConsumable(purchaseParam: purchaseParam);
-
-      // Verify that the result has succeeded
-      PurchaseDetails result = await completer.future;
-      expect(launchResult, isTrue);
-      expect(result.billingClientPurchase, isNotNull);
-      expect(result.billingClientPurchase!.purchaseToken,
-          await consumeCompleter.future);
-      expect(result.status, PurchaseStatus.purchased);
-      expect(result.error, isNull);
-    });
-
-    test('buyNonConsumable propagates failures to launch the billing flow',
-        () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse sentCode = BillingResponse.error;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: sentCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-          name: launchMethodName,
-          value: buildBillingResultMap(expectedBillingResult));
-
-      final bool result = await GooglePlayConnection.instance.buyNonConsumable(
-          purchaseParam: PurchaseParam(
-              productDetails: ProductDetails.fromSkuDetails(dummySkuDetails)));
-
-      // Verify that the failure has been converted and returned
-      expect(result, isFalse);
-    });
-
-    test('buyConsumable propagates failures to launch the billing flow',
-        () async {
-      const String debugMessage = 'dummy message';
-      final BillingResponse sentCode = BillingResponse.developerError;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: sentCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-        name: launchMethodName,
-        value: buildBillingResultMap(expectedBillingResult),
-      );
-
-      final bool result = await GooglePlayConnection.instance.buyConsumable(
-          purchaseParam: PurchaseParam(
-              productDetails: ProductDetails.fromSkuDetails(dummySkuDetails)));
-
-      // Verify that the failure has been converted and returned
-      expect(result, isFalse);
-    });
-
-    test('adds consumption failures to PurchaseDetails objects', () async {
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-      final String accountId = "hashedAccountId";
-      const String debugMessage = 'dummy message';
-      final BillingResponse sentCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: sentCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-          name: launchMethodName,
-          value: buildBillingResultMap(expectedBillingResult),
-          additionalStepBeforeReturn: (_) {
-            // Mock java update purchase callback.
-            MethodCall call = MethodCall(kOnPurchasesUpdated, {
-              'billingResult': buildBillingResultMap(expectedBillingResult),
-              'responseCode': BillingResponseConverter().toJson(sentCode),
-              'purchasesList': [
-                {
-                  'orderId': 'orderID1',
-                  'sku': skuDetails.sku,
-                  'isAutoRenewing': false,
-                  'packageName': "package",
-                  'purchaseTime': 1231231231,
-                  'purchaseToken': "token",
-                  'signature': 'sign',
-                  'originalJson': 'json',
-                  'developerPayload': 'dummy payload',
-                  'isAcknowledged': true,
-                  'purchaseState': 1,
-                }
-              ]
-            });
-            connection.billingClient.callHandler(call);
-          });
-      Completer consumeCompleter = Completer();
-      // adding call back for consume purchase
-      final BillingResponse expectedCode = BillingResponse.error;
-      final BillingResultWrapper expectedBillingResultForConsume =
-          BillingResultWrapper(
-              responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-          name: consumeMethodName,
-          value: buildBillingResultMap(expectedBillingResultForConsume),
-          additionalStepBeforeReturn: (dynamic args) {
-            String purchaseToken = args['purchaseToken'];
-            consumeCompleter.complete(purchaseToken);
-          });
-
-      Completer completer = Completer();
-      PurchaseDetails purchaseDetails;
-      Stream purchaseStream =
-          GooglePlayConnection.instance.purchaseUpdatedStream;
-      late StreamSubscription subscription;
-      subscription = purchaseStream.listen((_) {
-        purchaseDetails = _.first;
-        completer.complete(purchaseDetails);
-        subscription.cancel();
-      }, onDone: () {});
-      final PurchaseParam purchaseParam = PurchaseParam(
-          productDetails: ProductDetails.fromSkuDetails(skuDetails),
-          applicationUserName: accountId);
-      await GooglePlayConnection.instance
-          .buyConsumable(purchaseParam: purchaseParam);
-
-      // Verify that the result has an error for the failed consumption
-      PurchaseDetails result = await completer.future;
-      expect(result.billingClientPurchase, isNotNull);
-      expect(result.billingClientPurchase!.purchaseToken,
-          await consumeCompleter.future);
-      expect(result.status, PurchaseStatus.error);
-      expect(result.error, isNotNull);
-      expect(result.error!.code, kConsumptionFailedErrorCode);
-    });
-
-    test(
-        'buy consumable without auto consume, consume api should not receive calls',
-        () async {
-      final SkuDetailsWrapper skuDetails = dummySkuDetails;
-      final String accountId = "hashedAccountId";
-      const String debugMessage = 'dummy message';
-      final BillingResponse sentCode = BillingResponse.developerError;
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: sentCode, debugMessage: debugMessage);
-
-      stubPlatform.addResponse(
-          name: launchMethodName,
-          value: buildBillingResultMap(expectedBillingResult),
-          additionalStepBeforeReturn: (_) {
-            // Mock java update purchase callback.
-            MethodCall call = MethodCall(kOnPurchasesUpdated, {
-              'billingResult': buildBillingResultMap(expectedBillingResult),
-              'responseCode': BillingResponseConverter().toJson(sentCode),
-              'purchasesList': [
-                {
-                  'orderId': 'orderID1',
-                  'sku': skuDetails.sku,
-                  'isAutoRenewing': false,
-                  'packageName': "package",
-                  'purchaseTime': 1231231231,
-                  'purchaseToken': "token",
-                  'signature': 'sign',
-                  'originalJson': 'json',
-                  'developerPayload': 'dummy payload',
-                  'isAcknowledged': true,
-                  'purchaseState': 1,
-                }
-              ]
-            });
-            connection.billingClient.callHandler(call);
-          });
-      Completer consumeCompleter = Completer();
-      // adding call back for consume purchase
-      final BillingResponse expectedCode = BillingResponse.ok;
-      final BillingResultWrapper expectedBillingResultForConsume =
-          BillingResultWrapper(
-              responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-          name: consumeMethodName,
-          value: buildBillingResultMap(expectedBillingResultForConsume),
-          additionalStepBeforeReturn: (dynamic args) {
-            String purchaseToken = args['purchaseToken'];
-            consumeCompleter.complete((purchaseToken));
-          });
-
-      Stream purchaseStream =
-          GooglePlayConnection.instance.purchaseUpdatedStream;
-      late StreamSubscription subscription;
-      subscription = purchaseStream.listen((_) {
-        consumeCompleter.complete(null);
-        subscription.cancel();
-      }, onDone: () {});
-      final PurchaseParam purchaseParam = PurchaseParam(
-          productDetails: ProductDetails.fromSkuDetails(skuDetails),
-          applicationUserName: accountId);
-      await GooglePlayConnection.instance
-          .buyConsumable(purchaseParam: purchaseParam, autoConsume: false);
-      expect(null, await consumeCompleter.future);
-    });
-  });
-
-  group('consume purchases', () {
-    const String consumeMethodName =
-        'BillingClient#consumeAsync(String, ConsumeResponseListener)';
-    test('consume purchase async success', () async {
-      final BillingResponse expectedCode = BillingResponse.ok;
-      const String debugMessage = 'dummy message';
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-        name: consumeMethodName,
-        value: buildBillingResultMap(expectedBillingResult),
-      );
-      final BillingResultWrapper billingResultWrapper =
-          await GooglePlayConnection.instance
-              .consumePurchase(PurchaseDetails.fromPurchase(dummyPurchase));
-
-      expect(billingResultWrapper, equals(expectedBillingResult));
-    });
-  });
-
-  group('complete purchase', () {
-    const String completeMethodName =
-        'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
-    test('complete purchase success', () async {
-      final BillingResponse expectedCode = BillingResponse.ok;
-      const String debugMessage = 'dummy message';
-      final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
-          responseCode: expectedCode, debugMessage: debugMessage);
-      stubPlatform.addResponse(
-        name: completeMethodName,
-        value: buildBillingResultMap(expectedBillingResult),
-      );
-      PurchaseDetails purchaseDetails =
-          PurchaseDetails.fromPurchase(dummyUnacknowledgedPurchase);
-      Completer completer = Completer();
-      purchaseDetails.status = PurchaseStatus.purchased;
-      if (purchaseDetails.pendingCompletePurchase) {
-        final BillingResultWrapper billingResultWrapper =
-            await GooglePlayConnection.instance
-                .completePurchase(purchaseDetails);
-        expect(billingResultWrapper, equals(expectedBillingResult));
-        completer.complete(billingResultWrapper);
-      }
-      expect(await completer.future, equals(expectedBillingResult));
-    });
-  });
-}
diff --git a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/product_details_test.dart b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/product_details_test.dart
deleted file mode 100644
index a67baf8..0000000
--- a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_connection/product_details_test.dart
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter_test/flutter_test.dart';
-import 'package:in_app_purchase/in_app_purchase.dart';
-import 'package:in_app_purchase/src/store_kit_wrappers/sk_product_wrapper.dart';
-
-void main() {
-  group('Constructor Tests', () {
-    test(
-        'fromSkProduct should correctly parse data from a SKProductWrapper instance.',
-        () {
-      final SKProductWrapper dummyProductWrapper = SKProductWrapper(
-        productIdentifier: 'id',
-        localizedTitle: 'title',
-        localizedDescription: 'description',
-        priceLocale:
-            SKPriceLocaleWrapper(currencySymbol: '\$', currencyCode: 'USD'),
-        subscriptionGroupIdentifier: 'com.group',
-        price: '13.37',
-      );
-
-      ProductDetails productDetails =
-          ProductDetails.fromSKProduct(dummyProductWrapper);
-      expect(productDetails.id, equals(dummyProductWrapper.productIdentifier));
-      expect(productDetails.title, equals(dummyProductWrapper.localizedTitle));
-      expect(productDetails.description,
-          equals(dummyProductWrapper.localizedDescription));
-      expect(productDetails.rawPrice, equals(13.37));
-      expect(productDetails.currencyCode,
-          equals(dummyProductWrapper.priceLocale.currencyCode));
-      expect(productDetails.skProduct, equals(dummyProductWrapper));
-      expect(productDetails.skuDetail, isNull);
-    });
-
-    test(
-        'fromSkuDetails should correctly parse data from a SkuDetailsWrapper instance',
-        () {
-      final SkuDetailsWrapper dummyDetailWrapper = SkuDetailsWrapper(
-        description: 'description',
-        freeTrialPeriod: 'freeTrialPeriod',
-        introductoryPrice: 'introductoryPrice',
-        introductoryPriceMicros: 'introductoryPriceMicros',
-        introductoryPriceCycles: 1,
-        introductoryPricePeriod: 'introductoryPricePeriod',
-        price: '13.37',
-        priceAmountMicros: 13370000,
-        priceCurrencyCode: 'usd',
-        sku: 'sku',
-        subscriptionPeriod: 'subscriptionPeriod',
-        title: 'title',
-        type: SkuType.inapp,
-        originalPrice: 'originalPrice',
-        originalPriceAmountMicros: 1000,
-      );
-
-      ProductDetails productDetails =
-          ProductDetails.fromSkuDetails(dummyDetailWrapper);
-      expect(productDetails.id, equals(dummyDetailWrapper.sku));
-      expect(productDetails.title, equals(dummyDetailWrapper.title));
-      expect(
-          productDetails.description, equals(dummyDetailWrapper.description));
-      expect(productDetails.price, equals(dummyDetailWrapper.price));
-      expect(productDetails.rawPrice, equals(13.37));
-      expect(productDetails.currencyCode,
-          equals(dummyDetailWrapper.priceCurrencyCode));
-      expect(productDetails.skProduct, isNull);
-      expect(productDetails.skuDetail, equals(dummyDetailWrapper));
-    });
-  });
-}
diff --git a/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_test.dart b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_test.dart
new file mode 100644
index 0000000..494c314
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/test/in_app_purchase_test.dart
@@ -0,0 +1,170 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:in_app_purchase/in_app_purchase.dart';
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
+import 'package:plugin_platform_interface/plugin_platform_interface.dart';
+
+void main() {
+  group('InAppPurchase', () {
+    final ProductDetails productDetails = ProductDetails(
+      id: 'id',
+      title: 'title',
+      description: 'description',
+      price: 'price',
+      rawPrice: 0.0,
+      currencyCode: 'currencyCode',
+    );
+
+    final PurchaseDetails purchaseDetails = PurchaseDetails(
+      productID: 'productID',
+      verificationData: PurchaseVerificationData(
+        localVerificationData: 'localVerificationData',
+        serverVerificationData: 'serverVerificationData',
+        source: 'source',
+      ),
+      transactionDate: 'transactionDate',
+      status: PurchaseStatus.purchased,
+    );
+
+    late InAppPurchase inAppPurchase;
+    late MockInAppPurchasePlatform fakePlatform;
+
+    setUp(() {
+      debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
+
+      fakePlatform = MockInAppPurchasePlatform();
+      InAppPurchasePlatform.instance = fakePlatform;
+      inAppPurchase = InAppPurchase.instance;
+    });
+
+    tearDown(() {
+      // Restore the default target platform
+      debugDefaultTargetPlatformOverride = null;
+    });
+
+    test('isAvailable', () async {
+      final bool isAvailable = await inAppPurchase.isAvailable();
+      expect(isAvailable, true);
+      expect(fakePlatform.log, <Matcher>[
+        isMethodCall('isAvailable', arguments: null),
+      ]);
+    });
+
+    test('purchaseStream', () async {
+      final bool isEmptyStream = await inAppPurchase.purchaseStream.isEmpty;
+      expect(isEmptyStream, true);
+      expect(fakePlatform.log, <Matcher>[
+        isMethodCall('purchaseStream', arguments: null),
+      ]);
+    });
+
+    test('queryProductDetails', () async {
+      final ProductDetailsResponse response =
+          await inAppPurchase.queryProductDetails(Set<String>());
+      expect(response.notFoundIDs.isEmpty, true);
+      expect(response.productDetails.isEmpty, true);
+      expect(fakePlatform.log, <Matcher>[
+        isMethodCall('queryProductDetails', arguments: null),
+      ]);
+    });
+
+    test('buyNonConsumable', () async {
+      final bool result = await inAppPurchase.buyNonConsumable(
+        purchaseParam: PurchaseParam(
+          productDetails: productDetails,
+        ),
+      );
+
+      expect(result, true);
+      expect(fakePlatform.log, <Matcher>[
+        isMethodCall('buyNonConsumable', arguments: null),
+      ]);
+    });
+
+    test('buyConsumable', () async {
+      final bool result = await inAppPurchase.buyConsumable(
+        purchaseParam: PurchaseParam(
+          productDetails: productDetails,
+        ),
+      );
+
+      expect(result, true);
+      expect(fakePlatform.log, <Matcher>[
+        isMethodCall('buyConsumable', arguments: null),
+      ]);
+    });
+
+    test('completePurchase', () async {
+      await inAppPurchase.completePurchase(purchaseDetails);
+
+      expect(fakePlatform.log, <Matcher>[
+        isMethodCall('completePurchase', arguments: null),
+      ]);
+    });
+
+    test('restorePurchases', () async {
+      await inAppPurchase.restorePurchases();
+
+      expect(fakePlatform.log, <Matcher>[
+        isMethodCall('restorePurchases', arguments: null),
+      ]);
+    });
+  });
+}
+
+class MockInAppPurchasePlatform extends Fake
+    with MockPlatformInterfaceMixin
+    implements InAppPurchasePlatform {
+  final List<MethodCall> log = [];
+
+  @override
+  Future<bool> isAvailable() {
+    log.add(MethodCall('isAvailable'));
+    return Future.value(true);
+  }
+
+  @override
+  Stream<List<PurchaseDetails>> get purchaseStream {
+    log.add(MethodCall('purchaseStream'));
+    return Stream.empty();
+  }
+
+  @override
+  Future<ProductDetailsResponse> queryProductDetails(Set<String> identifiers) {
+    log.add(MethodCall('queryProductDetails'));
+    return Future.value(
+        ProductDetailsResponse(productDetails: [], notFoundIDs: []));
+  }
+
+  @override
+  Future<bool> buyNonConsumable({required PurchaseParam purchaseParam}) {
+    log.add(MethodCall('buyNonConsumable'));
+    return Future.value(true);
+  }
+
+  @override
+  Future<bool> buyConsumable({
+    required PurchaseParam purchaseParam,
+    bool autoConsume = true,
+  }) {
+    log.add(MethodCall('buyConsumable'));
+    return Future.value(true);
+  }
+
+  @override
+  Future<void> completePurchase(PurchaseDetails purchase) {
+    log.add(MethodCall('completePurchase'));
+    return Future.value(null);
+  }
+
+  @override
+  Future<void> restorePurchases({String? applicationUserName}) {
+    log.add(MethodCall('restorePurchases'));
+    return Future.value(null);
+  }
+}
diff --git a/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart b/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart
deleted file mode 100644
index 5bc3d92..0000000
--- a/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter/services.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'package:in_app_purchase/src/channel.dart';
-import 'package:in_app_purchase/store_kit_wrappers.dart';
-import 'sk_test_stub_objects.dart';
-
-void main() {
-  TestWidgetsFlutterBinding.ensureInitialized();
-
-  final FakeIOSPlatform fakeIOSPlatform = FakeIOSPlatform();
-
-  setUpAll(() {
-    SystemChannels.platform
-        .setMockMethodCallHandler(fakeIOSPlatform.onMethodCall);
-  });
-
-  setUp(() {});
-
-  tearDown(() {
-    fakeIOSPlatform.testReturnNull = false;
-  });
-
-  group('sk_request_maker', () {
-    test('get products method channel', () async {
-      SkProductResponseWrapper productResponseWrapper =
-          await SKRequestMaker().startProductRequest(['xxx']);
-      expect(
-        productResponseWrapper.products,
-        isNotEmpty,
-      );
-      expect(
-        productResponseWrapper.products.first.priceLocale.currencySymbol,
-        '\$',
-      );
-
-      expect(
-        productResponseWrapper.products.first.priceLocale.currencySymbol,
-        isNot('A'),
-      );
-      expect(
-        productResponseWrapper.products.first.priceLocale.currencyCode,
-        'USD',
-      );
-      expect(
-        productResponseWrapper.invalidProductIdentifiers,
-        isNotEmpty,
-      );
-
-      expect(
-        fakeIOSPlatform.startProductRequestParam,
-        ['xxx'],
-      );
-    });
-
-    test('get products method channel should throw exception', () async {
-      fakeIOSPlatform.getProductRequestFailTest = true;
-      expect(
-        SKRequestMaker().startProductRequest(<String>['xxx']),
-        throwsException,
-      );
-      fakeIOSPlatform.getProductRequestFailTest = false;
-    });
-
-    test('refreshed receipt', () async {
-      int receiptCountBefore = fakeIOSPlatform.refreshReceipt;
-      await SKRequestMaker().startRefreshReceiptRequest(
-          receiptProperties: <String, dynamic>{"isExpired": true});
-      expect(fakeIOSPlatform.refreshReceipt, receiptCountBefore + 1);
-      expect(fakeIOSPlatform.refreshReceiptParam,
-          <String, dynamic>{"isExpired": true});
-    });
-  });
-
-  group('sk_receipt_manager', () {
-    test('should get receipt (faking it by returning a `receipt data` string)',
-        () async {
-      String receiptData = await SKReceiptManager.retrieveReceiptData();
-      expect(receiptData, 'receipt data');
-    });
-  });
-
-  group('sk_payment_queue', () {
-    test('canMakePayment should return true', () async {
-      expect(await SKPaymentQueueWrapper.canMakePayments(), true);
-    });
-
-    test('canMakePayment returns false if method channel returns null',
-        () async {
-      fakeIOSPlatform.testReturnNull = true;
-      expect(await SKPaymentQueueWrapper.canMakePayments(), false);
-    });
-
-    test('transactions should return a valid list of transactions', () async {
-      expect(await SKPaymentQueueWrapper().transactions(), isNotEmpty);
-    });
-
-    test(
-        'throws if observer is not set for payment queue before adding payment',
-        () async {
-      expect(SKPaymentQueueWrapper().addPayment(dummyPayment),
-          throwsAssertionError);
-    });
-
-    test('should add payment to the payment queue', () async {
-      SKPaymentQueueWrapper queue = SKPaymentQueueWrapper();
-      TestPaymentTransactionObserver observer =
-          TestPaymentTransactionObserver();
-      queue.setTransactionObserver(observer);
-      await queue.addPayment(dummyPayment);
-      expect(fakeIOSPlatform.payments.first, equals(dummyPayment));
-    });
-
-    test('should finish transaction', () async {
-      SKPaymentQueueWrapper queue = SKPaymentQueueWrapper();
-      TestPaymentTransactionObserver observer =
-          TestPaymentTransactionObserver();
-      queue.setTransactionObserver(observer);
-      await queue.finishTransaction(dummyTransaction);
-      expect(fakeIOSPlatform.transactionsFinished.first,
-          equals(dummyTransaction.toFinishMap()));
-    });
-
-    test('should restore transaction', () async {
-      SKPaymentQueueWrapper queue = SKPaymentQueueWrapper();
-      TestPaymentTransactionObserver observer =
-          TestPaymentTransactionObserver();
-      queue.setTransactionObserver(observer);
-      await queue.restoreTransactions(applicationUserName: 'aUserID');
-      expect(fakeIOSPlatform.applicationNameHasTransactionRestored, 'aUserID');
-    });
-  });
-
-  group('Code Redemption Sheet', () {
-    test('presentCodeRedemptionSheet should not throw', () async {
-      expect(fakeIOSPlatform.presentCodeRedemption, false);
-      await SKPaymentQueueWrapper().presentCodeRedemptionSheet();
-      expect(fakeIOSPlatform.presentCodeRedemption, true);
-      fakeIOSPlatform.presentCodeRedemption = false;
-    });
-  });
-}
-
-class FakeIOSPlatform {
-  FakeIOSPlatform() {
-    channel.setMockMethodCallHandler(onMethodCall);
-  }
-  // get product request
-  List<dynamic> startProductRequestParam = [];
-  bool getProductRequestFailTest = false;
-  bool testReturnNull = false;
-
-  // refresh receipt request
-  int refreshReceipt = 0;
-  late Map<String, dynamic> refreshReceiptParam;
-
-  // payment queue
-  List<SKPaymentWrapper> payments = [];
-  List<Map<String, String>> transactionsFinished = [];
-  String applicationNameHasTransactionRestored = '';
-
-  // present Code Redemption
-  bool presentCodeRedemption = false;
-
-  Future<dynamic> onMethodCall(MethodCall call) {
-    switch (call.method) {
-      // request makers
-      case '-[InAppPurchasePlugin startProductRequest:result:]':
-        List<String> productIDS =
-            List.castFrom<dynamic, String>(call.arguments);
-        assert(productIDS is List<String>, 'invalid argument type');
-        startProductRequestParam = call.arguments;
-        if (getProductRequestFailTest) {
-          return Future<Map<String, dynamic>>.value(null);
-        }
-        return Future<Map<String, dynamic>>.value(
-            buildProductResponseMap(dummyProductResponseWrapper));
-      case '-[InAppPurchasePlugin refreshReceipt:result:]':
-        refreshReceipt++;
-        refreshReceiptParam =
-            Map.castFrom<dynamic, dynamic, String, dynamic>(call.arguments);
-        return Future<void>.sync(() {});
-      // receipt manager
-      case '-[InAppPurchasePlugin retrieveReceiptData:result:]':
-        return Future<String>.value('receipt data');
-      // payment queue
-      case '-[SKPaymentQueue canMakePayments:]':
-        if (testReturnNull) {
-          return Future<dynamic>.value(null);
-        }
-        return Future<bool>.value(true);
-      case '-[SKPaymentQueue transactions]':
-        return Future<List<dynamic>>.value(
-            [buildTransactionMap(dummyTransaction)]);
-      case '-[InAppPurchasePlugin addPayment:result:]':
-        payments.add(SKPaymentWrapper.fromJson(
-            Map<String, dynamic>.from(call.arguments)));
-        return Future<void>.sync(() {});
-      case '-[InAppPurchasePlugin finishTransaction:result:]':
-        transactionsFinished.add(Map<String, String>.from(call.arguments));
-        return Future<void>.sync(() {});
-      case '-[InAppPurchasePlugin restoreTransactions:result:]':
-        applicationNameHasTransactionRestored = call.arguments;
-        return Future<void>.sync(() {});
-      case '-[InAppPurchasePlugin presentCodeRedemptionSheet:result:]':
-        presentCodeRedemption = true;
-        return Future<void>.sync(() {});
-    }
-    return Future<void>.sync(() {});
-  }
-}
-
-class TestPaymentTransactionObserver extends SKTransactionObserverWrapper {
-  void updatedTransactions(
-      {required List<SKPaymentTransactionWrapper> transactions}) {}
-
-  void removedTransactions(
-      {required List<SKPaymentTransactionWrapper> transactions}) {}
-
-  void restoreCompletedTransactionsFailed({required SKError error}) {}
-
-  void paymentQueueRestoreCompletedTransactionsFinished() {}
-
-  bool shouldAddStorePayment(
-      {required SKPaymentWrapper payment, required SKProductWrapper product}) {
-    return true;
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart b/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart
deleted file mode 100644
index e2db6ba..0000000
--- a/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_product_test.dart
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:in_app_purchase/src/in_app_purchase/purchase_details.dart';
-import 'package:in_app_purchase/store_kit_wrappers.dart';
-import 'package:test/test.dart';
-import 'package:in_app_purchase/src/store_kit_wrappers/sk_product_wrapper.dart';
-import 'package:in_app_purchase/src/in_app_purchase/in_app_purchase_connection.dart';
-import 'package:in_app_purchase/src/in_app_purchase/product_details.dart';
-import 'sk_test_stub_objects.dart';
-
-void main() {
-  group('product related object wrapper test', () {
-    test(
-        'SKProductSubscriptionPeriodWrapper should have property values consistent with map',
-        () {
-      final SKProductSubscriptionPeriodWrapper wrapper =
-          SKProductSubscriptionPeriodWrapper.fromJson(
-              buildSubscriptionPeriodMap(dummySubscription)!);
-      expect(wrapper, equals(dummySubscription));
-    });
-
-    test(
-        'SKProductSubscriptionPeriodWrapper should have properties to be default values if map is empty',
-        () {
-      final SKProductSubscriptionPeriodWrapper wrapper =
-          SKProductSubscriptionPeriodWrapper.fromJson(<String, dynamic>{});
-      expect(wrapper.numberOfUnits, 0);
-      expect(wrapper.unit, SKSubscriptionPeriodUnit.day);
-    });
-
-    test(
-        'SKProductDiscountWrapper should have property values consistent with map',
-        () {
-      final SKProductDiscountWrapper wrapper =
-          SKProductDiscountWrapper.fromJson(buildDiscountMap(dummyDiscount));
-      expect(wrapper, equals(dummyDiscount));
-    });
-
-    test(
-        'SKProductDiscountWrapper should have properties to be default if map is empty',
-        () {
-      final SKProductDiscountWrapper wrapper =
-          SKProductDiscountWrapper.fromJson(<String, dynamic>{});
-      expect(wrapper.price, '');
-      expect(wrapper.priceLocale,
-          SKPriceLocaleWrapper(currencyCode: '', currencySymbol: ''));
-      expect(wrapper.numberOfPeriods, 0);
-      expect(wrapper.paymentMode, SKProductDiscountPaymentMode.payAsYouGo);
-      expect(
-          wrapper.subscriptionPeriod,
-          SKProductSubscriptionPeriodWrapper(
-              numberOfUnits: 0, unit: SKSubscriptionPeriodUnit.day));
-    });
-
-    test('SKProductWrapper should have property values consistent with map',
-        () {
-      final SKProductWrapper wrapper =
-          SKProductWrapper.fromJson(buildProductMap(dummyProductWrapper));
-      expect(wrapper, equals(dummyProductWrapper));
-    });
-
-    test(
-        'SKProductWrapper should have properties to be default if map is empty',
-        () {
-      final SKProductWrapper wrapper =
-          SKProductWrapper.fromJson(<String, dynamic>{});
-      expect(wrapper.productIdentifier, '');
-      expect(wrapper.localizedTitle, '');
-      expect(wrapper.localizedDescription, '');
-      expect(wrapper.priceLocale,
-          SKPriceLocaleWrapper(currencyCode: '', currencySymbol: ''));
-      expect(wrapper.subscriptionGroupIdentifier, null);
-      expect(wrapper.price, '');
-      expect(wrapper.subscriptionPeriod, null);
-    });
-
-    test('toProductDetails() should return correct Product object', () {
-      final SKProductWrapper wrapper =
-          SKProductWrapper.fromJson(buildProductMap(dummyProductWrapper));
-      final ProductDetails product = ProductDetails.fromSKProduct(wrapper);
-      expect(product.title, wrapper.localizedTitle);
-      expect(product.description, wrapper.localizedDescription);
-      expect(product.id, wrapper.productIdentifier);
-      expect(product.price,
-          wrapper.priceLocale.currencySymbol + wrapper.price.toString());
-      expect(product.skProduct, wrapper);
-      expect(product.skuDetail, null);
-    });
-
-    test('SKProductResponse wrapper should match', () {
-      final SkProductResponseWrapper wrapper =
-          SkProductResponseWrapper.fromJson(
-              buildProductResponseMap(dummyProductResponseWrapper));
-      expect(wrapper, equals(dummyProductResponseWrapper));
-    });
-    test('SKProductResponse wrapper should default to empty list', () {
-      final Map<String, List<dynamic>> productResponseMapEmptyList =
-          <String, List<dynamic>>{
-        'products': <Map<String, dynamic>>[],
-        'invalidProductIdentifiers': <String>[],
-      };
-      final SkProductResponseWrapper wrapper =
-          SkProductResponseWrapper.fromJson(productResponseMapEmptyList);
-      expect(wrapper.products.length, 0);
-      expect(wrapper.invalidProductIdentifiers.length, 0);
-    });
-
-    test('LocaleWrapper should have property values consistent with map', () {
-      final SKPriceLocaleWrapper wrapper =
-          SKPriceLocaleWrapper.fromJson(buildLocaleMap(dummyLocale));
-      expect(wrapper, equals(dummyLocale));
-    });
-  });
-
-  group('Payment queue related object tests', () {
-    test('Should construct correct SKPaymentWrapper from json', () {
-      SKPaymentWrapper payment =
-          SKPaymentWrapper.fromJson(dummyPayment.toMap());
-      expect(payment, equals(dummyPayment));
-    });
-
-    test('Should construct correct SKError from json', () {
-      SKError error = SKError.fromJson(buildErrorMap(dummyError));
-      expect(error, equals(dummyError));
-    });
-
-    test('Should construct correct SKTransactionWrapper from json', () {
-      SKPaymentTransactionWrapper transaction =
-          SKPaymentTransactionWrapper.fromJson(
-              buildTransactionMap(dummyTransaction));
-      expect(transaction, equals(dummyTransaction));
-    });
-
-    test('toPurchaseDetails() should return correct PurchaseDetail object', () {
-      PurchaseDetails details =
-          PurchaseDetails.fromSKTransaction(dummyTransaction, 'receipt data');
-      expect(dummyTransaction.transactionIdentifier, details.purchaseID);
-      expect(dummyTransaction.payment.productIdentifier, details.productID);
-      expect(dummyTransaction.transactionTimeStamp, isNotNull);
-      expect((dummyTransaction.transactionTimeStamp! * 1000).toInt().toString(),
-          details.transactionDate);
-      expect(details.verificationData.localVerificationData, 'receipt data');
-      expect(details.verificationData.serverVerificationData, 'receipt data');
-      expect(details.verificationData.source, IAPSource.AppStore);
-      expect(details.skPaymentTransaction, dummyTransaction);
-      expect(details.billingClientPurchase, null);
-      expect(details.pendingCompletePurchase, true);
-    });
-
-    test('SKPaymentTransactionWrapper.toFinishMap set correct value', () {
-      final SKPaymentTransactionWrapper transactionWrapper =
-          SKPaymentTransactionWrapper(
-              payment: dummyPayment,
-              transactionState: SKPaymentTransactionStateWrapper.failed,
-              transactionIdentifier: 'abcd');
-      final Map<String, String?> finishMap = transactionWrapper.toFinishMap();
-      expect(finishMap['transactionIdentifier'], 'abcd');
-      expect(finishMap['productIdentifier'], dummyPayment.productIdentifier);
-    });
-
-    test(
-        'SKPaymentTransactionWrapper.toFinishMap should set transactionIdentifier to null when necessary',
-        () {
-      final SKPaymentTransactionWrapper transactionWrapper =
-          SKPaymentTransactionWrapper(
-              payment: dummyPayment,
-              transactionState: SKPaymentTransactionStateWrapper.failed);
-      final Map<String, String?> finishMap = transactionWrapper.toFinishMap();
-      expect(finishMap['transactionIdentifier'], null);
-    });
-
-    test('Should generate correct map of the payment object', () {
-      Map map = dummyPayment.toMap();
-      expect(map['productIdentifier'], dummyPayment.productIdentifier);
-      expect(map['applicationUsername'], dummyPayment.applicationUsername);
-
-      expect(map['requestData'], dummyPayment.requestData);
-
-      expect(map['quantity'], dummyPayment.quantity);
-
-      expect(map['simulatesAskToBuyInSandbox'],
-          dummyPayment.simulatesAskToBuyInSandbox);
-    });
-  });
-}
diff --git a/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart b/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart
deleted file mode 100644
index 09c730e..0000000
--- a/packages/in_app_purchase/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:in_app_purchase/store_kit_wrappers.dart';
-
-final dummyPayment = SKPaymentWrapper(
-    productIdentifier: 'prod-id',
-    applicationUsername: 'app-user-name',
-    requestData: 'fake-data-utf8',
-    quantity: 2,
-    simulatesAskToBuyInSandbox: true);
-final SKError dummyError =
-    SKError(code: 111, domain: 'dummy-domain', userInfo: {'key': 'value'});
-
-final SKPaymentTransactionWrapper dummyOriginalTransaction =
-    SKPaymentTransactionWrapper(
-  transactionState: SKPaymentTransactionStateWrapper.purchased,
-  payment: dummyPayment,
-  originalTransaction: null,
-  transactionTimeStamp: 1231231231.00,
-  transactionIdentifier: '123123',
-  error: dummyError,
-);
-
-final SKPaymentTransactionWrapper dummyTransaction =
-    SKPaymentTransactionWrapper(
-  transactionState: SKPaymentTransactionStateWrapper.purchased,
-  payment: dummyPayment,
-  originalTransaction: dummyOriginalTransaction,
-  transactionTimeStamp: 1231231231.00,
-  transactionIdentifier: '123123',
-  error: dummyError,
-);
-
-final SKPriceLocaleWrapper dummyLocale =
-    SKPriceLocaleWrapper(currencySymbol: '\$', currencyCode: 'USD');
-
-final SKProductSubscriptionPeriodWrapper dummySubscription =
-    SKProductSubscriptionPeriodWrapper(
-  numberOfUnits: 1,
-  unit: SKSubscriptionPeriodUnit.month,
-);
-
-final SKProductDiscountWrapper dummyDiscount = SKProductDiscountWrapper(
-  price: '1.0',
-  priceLocale: dummyLocale,
-  numberOfPeriods: 1,
-  paymentMode: SKProductDiscountPaymentMode.payUpFront,
-  subscriptionPeriod: dummySubscription,
-);
-
-final SKProductWrapper dummyProductWrapper = SKProductWrapper(
-  productIdentifier: 'id',
-  localizedTitle: 'title',
-  localizedDescription: 'description',
-  priceLocale: dummyLocale,
-  subscriptionGroupIdentifier: 'com.group',
-  price: '1.0',
-  subscriptionPeriod: dummySubscription,
-  introductoryPrice: dummyDiscount,
-);
-
-final SkProductResponseWrapper dummyProductResponseWrapper =
-    SkProductResponseWrapper(
-  products: [dummyProductWrapper],
-  invalidProductIdentifiers: <String>['123'],
-);
-
-Map<String, dynamic> buildLocaleMap(SKPriceLocaleWrapper local) {
-  return {
-    'currencySymbol': local.currencySymbol,
-    'currencyCode': local.currencyCode
-  };
-}
-
-Map<String, dynamic>? buildSubscriptionPeriodMap(
-    SKProductSubscriptionPeriodWrapper? sub) {
-  if (sub == null) {
-    return null;
-  }
-  return {
-    'numberOfUnits': sub.numberOfUnits,
-    'unit': SKSubscriptionPeriodUnit.values.indexOf(sub.unit),
-  };
-}
-
-Map<String, dynamic> buildDiscountMap(SKProductDiscountWrapper discount) {
-  return {
-    'price': discount.price,
-    'priceLocale': buildLocaleMap(discount.priceLocale),
-    'numberOfPeriods': discount.numberOfPeriods,
-    'paymentMode':
-        SKProductDiscountPaymentMode.values.indexOf(discount.paymentMode),
-    'subscriptionPeriod':
-        buildSubscriptionPeriodMap(discount.subscriptionPeriod),
-  };
-}
-
-Map<String, dynamic> buildProductMap(SKProductWrapper product) {
-  return {
-    'productIdentifier': product.productIdentifier,
-    'localizedTitle': product.localizedTitle,
-    'localizedDescription': product.localizedDescription,
-    'priceLocale': buildLocaleMap(product.priceLocale),
-    'subscriptionGroupIdentifier': product.subscriptionGroupIdentifier,
-    'price': product.price,
-    'subscriptionPeriod':
-        buildSubscriptionPeriodMap(product.subscriptionPeriod),
-    'introductoryPrice': buildDiscountMap(product.introductoryPrice!),
-  };
-}
-
-Map<String, dynamic> buildProductResponseMap(
-    SkProductResponseWrapper response) {
-  List productsMap = response.products
-      .map((SKProductWrapper product) => buildProductMap(product))
-      .toList();
-  return {
-    'products': productsMap,
-    'invalidProductIdentifiers': response.invalidProductIdentifiers
-  };
-}
-
-Map<String, dynamic> buildErrorMap(SKError error) {
-  return {
-    'code': error.code,
-    'domain': error.domain,
-    'userInfo': error.userInfo,
-  };
-}
-
-Map<String, dynamic> buildTransactionMap(
-    SKPaymentTransactionWrapper transaction) {
-  Map<String, dynamic> map = <String, dynamic>{
-    'transactionState': SKPaymentTransactionStateWrapper.values
-        .indexOf(SKPaymentTransactionStateWrapper.purchased),
-    'payment': transaction.payment.toMap(),
-    'originalTransaction': transaction.originalTransaction == null
-        ? null
-        : buildTransactionMap(transaction.originalTransaction!),
-    'transactionTimeStamp': transaction.transactionTimeStamp,
-    'transactionIdentifier': transaction.transactionIdentifier,
-    'error': buildErrorMap(transaction.error!),
-  };
-  return map;
-}
diff --git a/packages/in_app_purchase/in_app_purchase/test/stub_in_app_purchase_platform.dart b/packages/in_app_purchase/in_app_purchase/test/stub_in_app_purchase_platform.dart
deleted file mode 100644
index 11a3426..0000000
--- a/packages/in_app_purchase/in_app_purchase/test/stub_in_app_purchase_platform.dart
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2013 The Flutter Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'dart:async';
-import 'package:flutter/services.dart';
-
-typedef void AdditionalSteps(dynamic args);
-
-class StubInAppPurchasePlatform {
-  Map<String, dynamic> _expectedCalls = <String, dynamic>{};
-  Map<String, AdditionalSteps?> _additionalSteps = <String, AdditionalSteps?>{};
-  void addResponse(
-      {required String name,
-      dynamic value,
-      AdditionalSteps? additionalStepBeforeReturn}) {
-    _additionalSteps[name] = additionalStepBeforeReturn;
-    _expectedCalls[name] = value;
-  }
-
-  List<MethodCall> _previousCalls = <MethodCall>[];
-  List<MethodCall> get previousCalls => _previousCalls;
-  MethodCall previousCallMatching(String name) =>
-      _previousCalls.firstWhere((MethodCall call) => call.method == name);
-  int countPreviousCalls(String name) =>
-      _previousCalls.where((MethodCall call) => call.method == name).length;
-
-  void reset() {
-    _expectedCalls.clear();
-    _previousCalls.clear();
-    _additionalSteps.clear();
-  }
-
-  Future<dynamic> fakeMethodCallHandler(MethodCall call) async {
-    _previousCalls.add(call);
-    if (_expectedCalls.containsKey(call.method)) {
-      if (_additionalSteps[call.method] != null) {
-        _additionalSteps[call.method]!(call.arguments);
-      }
-      return Future<dynamic>.sync(() => _expectedCalls[call.method]);
-    } else {
-      return Future<void>.sync(() => null);
-    }
-  }
-}
diff --git a/packages/in_app_purchase/in_app_purchase_android/README.md b/packages/in_app_purchase/in_app_purchase_android/README.md
index 41618fa..684dd66 100644
--- a/packages/in_app_purchase/in_app_purchase_android/README.md
+++ b/packages/in_app_purchase/in_app_purchase_android/README.md
@@ -31,8 +31,18 @@
   ...
 ```
 
-## TODO
-- [ ] Add an example application demonstrating the use of the [in_app_purchase_android] package (see also issue [flutter/flutter#81695](https://github.com/flutter/flutter/issues/81695)).
+## Contributing
+
+This plugin uses
+[json_serializable](https://pub.dev/packages/json_serializable) for the
+many data structs passed between the underlying platform layers and Dart. After
+editing any of the serialized data structs, rebuild the serializers by running
+`flutter packages pub run build_runner build --delete-conflicting-outputs`.
+`flutter packages pub run build_runner watch --delete-conflicting-outputs` will
+watch the filesystem for changes.
+
+If you would like to contribute to the plugin, check out our
+[contribution guide](https://github.com/flutter/plugins/blob/master/CONTRIBUTING.md).
 
 
 [1]: ../in_app_purchase/in_app_purchase
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ios/README.md b/packages/in_app_purchase/in_app_purchase_ios/README.md
index 3ab0338..46839b5 100644
--- a/packages/in_app_purchase/in_app_purchase_ios/README.md
+++ b/packages/in_app_purchase/in_app_purchase_ios/README.md
@@ -31,7 +31,18 @@
   ...
 ```
 
-## TODO
-- [ ] Add an example application demonstrating the use of the [in_app_purchase_ios] package (see also issue [flutter/flutter#81695](https://github.com/flutter/flutter/issues/81695)).
+## Contributing
+
+This plugin uses
+[json_serializable](https://pub.dev/packages/json_serializable) for the
+many data structs passed between the underlying platform layers and Dart. After
+editing any of the serialized data structs, rebuild the serializers by running
+`flutter packages pub run build_runner build --delete-conflicting-outputs`.
+`flutter packages pub run build_runner watch --delete-conflicting-outputs` will
+watch the filesystem for changes.
+
+If you would like to contribute to the plugin, check out our
+[contribution guide](https://github.com/flutter/plugins/blob/master/CONTRIBUTING.md).
+
 
 [1]: ../in_app_purchase/in_app_purchase
\ No newline at end of file