payment_sdk.dart 4.86 KB
import 'dart:async';

import 'package:Parlando/apis/api_order.dart';
import 'package:Parlando/membership/models/membership_entity.dart';
import 'package:common_utils/common_utils.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:in_app_purchase_android/in_app_purchase_android.dart';
import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart';

class PaymentSdk {
  var currentOrder;

  PaymentSdk._privateConstructor();

  static final PaymentSdk _instance = PaymentSdk._privateConstructor();

  static PaymentSdk get instance {
    return _instance;
  }

  static const Set<String> _kIds = <String>{'yearly_yiyan_vip', 'monthly_yiyan_vip'};

  StreamSubscription<List<PurchaseDetails>>? _subscription;
  List<ProductDetails> products = [];
  Function? onPaySuccess;
  Function? onPending;
  Function? onFailed;
  Function? onCancel;

  initState({
    Function? onPaySuccess,
    Function? onPending,
    Function? onFailed,
    Function? onCancel,
  }) {
    this.onPaySuccess = onPaySuccess;
    this.onPending = onPending;
    this.onFailed = onFailed;
    this.onCancel = onCancel;
    final Stream<List<PurchaseDetails>> purchaseUpdated = InAppPurchase.instance.purchaseStream;
    _subscription = purchaseUpdated.listen((purchaseDetailsList) {
      _listenToPurchaseUpdated(purchaseDetailsList);
    }, onDone: () {
      _subscription?.cancel();
    }, onError: (error) {
      // handle error here.
    });
  }

  Future<List<ProductDetails>> queryProducts() async {
    final bool available = await InAppPurchase.instance.isAvailable();
    if (!available) {
      return [];
    }
    final ProductDetailsResponse response = await InAppPurchase.instance.queryProductDetails(_kIds);
    return products = response.productDetails;
  }

  buy(ProductDetails details, MembershipDataGoodsList e) {
    OrderApi.request.createOrder(e.id.toString()).then((value) {
      var orderId = value?['data']?['data']?['order_sn'];
      if (TextUtil.isEmpty(orderId)) {
        onFailed?.call();
        return;
      }
      currentOrder = orderId;
      final PurchaseParam purchaseParam = PurchaseParam(productDetails: details, applicationUserName: orderId);
      if (_isConsumable(details)) {
        InAppPurchase.instance.buyConsumable(purchaseParam: purchaseParam);
      } else {
        InAppPurchase.instance.buyNonConsumable(purchaseParam: purchaseParam);
      }
    });
  }

  void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) async {
    for (var purchaseDetails in purchaseDetailsList) {
      if (purchaseDetails.status == PurchaseStatus.pending) {
        onPending?.call();
      } else {
        if (purchaseDetails.status == PurchaseStatus.error) {
          _handleError(purchaseDetails.error!);
        } else if (purchaseDetails.status == PurchaseStatus.purchased || purchaseDetails.status == PurchaseStatus.restored) {
          bool valid = await _verifyPurchase(purchaseDetails);
          if (valid) {
            _deliverProduct(purchaseDetails);
          } else {
            _handleInvalidPurchase(purchaseDetails);
          }
        } else {
          onCancel?.call();
        }
        if (purchaseDetails.pendingCompletePurchase) {
          await InAppPurchase.instance.completePurchase(purchaseDetails);
        }
      }
    }
  }

  _verifyPurchase(PurchaseDetails purchaseDetails) async {
    return true;
  }

  void _deliverProduct(PurchaseDetails purchaseDetails) {
    String type = "";
    Map<String, dynamic> otherField = {};
    if (purchaseDetails is GooglePlayPurchaseDetails) {
      currentOrder = purchaseDetails.billingClientPurchase.obfuscatedAccountId;
      type = "google";
      otherField["google"] = {
        "originalJson": purchaseDetails.billingClientPurchase.originalJson,
      };
    }
    if (purchaseDetails is AppStorePurchaseDetails) {
      type = "apple";
      otherField["apple"] = {
        "transactionIdentifier": purchaseDetails.skPaymentTransaction.transactionIdentifier,
        "originalTransactionIdentifier":
            purchaseDetails.skPaymentTransaction.originalTransaction?.transactionIdentifier ?? "",
      };
    }
    var serverVerifyStr = purchaseDetails.verificationData.serverVerificationData;
    var verifySource = purchaseDetails.verificationData.source;
    otherField["source"] = verifySource;
    OrderApi.request.verifyOrder(currentOrder, type, serverVerifyStr, others: otherField).then((value) {
      if (value != null) {}
      onPaySuccess?.call();
    });
  }

  void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
    onFailed?.call();
  }

  void _handleError(IAPError iapError) {
    onFailed?.call();
  }

  bool _isConsumable(ProductDetails details) {
    return false;
  }

  void restore() {
    InAppPurchase.instance.restorePurchases();
  }

  void dispose() {
    onPaySuccess = null;
    onPending = null;
    onFailed = null;
    onCancel = null;
    _subscription?.cancel();
  }
}