首页 > 解决方案 > 如何使用 Flutter 处理简单的应用内订阅?

问题描述

我正在使用 in_app_purchase 包,我想在 Flutter 中处理订阅。

只有 1 个订阅选项,它遵循一个非常常见的模式......我有一个部分检查用户 firebase 帐户“高级”字段是否为真。如果是,则显示该部分,如果为 false,则显示“立即订阅”按钮。

目前,在 Android 上,该按钮不显示。在 iOS 上,该按钮显示,但当我单击订阅时 - 它正确输出 PurchaseParams 但从未提示我付款。我正在使用沙盒帐户在物理设备上进行测试。

import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:wt_flutter/components/trips/blurred_category.dart';

import 'package:wt_flutter/services/globals.dart';
import 'package:wt_flutter/services/models.dart';

import 'package:wt_flutter/shared/loader.dart';
import 'package:wt_flutter/components/trips/initial_airport.dart';

final String proID = 'go_pro_annual';

class TripsScreen extends StatefulWidget {
  const TripsScreen({Key key}) : super(key: key);

  @override
  _TripsScreenState createState() => _TripsScreenState();
}

class _TripsScreenState extends State<TripsScreen> {
  // IAP Plugin Interface
  InAppPurchaseConnection _iap = InAppPurchaseConnection.instance;

  // Is the API available on the device
  bool _available = true;

  // Subscriptions for sale
  List<ProductDetails> _products = [];

  // Past purchases
  List<PurchaseDetails> _purchases = [];

  // Updates to purchases
  StreamSubscription _streamSubscription;

  @override
  void initState() {
    _initialize();
    super.initState();
  }

  @override
  void dispose() {
    _streamSubscription.cancel();
    super.dispose();
  }

  void _initialize() async {
    // Check availablility of In App Purchases
    _available = await _iap.isAvailable();

    if (_available) {
      await _getProducts();
      await _getPastPurchases();

      // List<Future futures = [_getProducts(), _getPastPurchases()];
      // await Future.wait(futures);
      _verifyPurchase();

      // Listen to new purchases
      _streamSubscription =
          _iap.purchaseUpdatedStream.listen((data) => setState(() {
                print('NEW PURCHASE');
                _purchases.addAll(data);
                _verifyPurchase();
              }));
    }
  }

  // Get all products available for sale
  Future<void> _getProducts() async {
    Set<String> ids = Set.from([proID]);
    ProductDetailsResponse response = await _iap.queryProductDetails(ids);

    setState(() {
      _products = response.productDetails;
    });
  }

  // Gets past purchases
  Future<void> _getPastPurchases() async {
    QueryPurchaseDetailsResponse response = await _iap.queryPastPurchases();

    for (PurchaseDetails purchase in response.pastPurchases) {
      if (Platform.isIOS) {
        _iap.completePurchase(purchase);
      }
    }

    // Or for consumables

    // TODO query the database for state of consumable products

    setState(() {
      _purchases = response.pastPurchases;
    });
  }

  // Returns purchase of specific product ID
  PurchaseDetails _hasPurchased(String productID) {
    return _purchases.firstWhere((purchase) => purchase.purchaseID == productID,
        orElse: () => null);
  }

  // Your own business logic to setup a consumable
  void _verifyPurchase() {
    PurchaseDetails purchase = _hasPurchased(proID);

    //TODO serverside verification & record subscription in the database

    if (purchase != null && purchase.status == PurchaseStatus.purchased) {
      print('Purchase verified');
    }
  }

  /// Purchase a product
  void _buyProduct(ProductDetails prod) {
    print(prod);
    try {
      final PurchaseParam purchaseParam = PurchaseParam(productDetails: prod);
      // For one time purchase
      print(purchaseParam.productDetails.id);
      print(purchaseParam.productDetails.price);
      print(purchaseParam.productDetails.title);
      _iap.buyNonConsumable(purchaseParam: purchaseParam);
      print('purchase successful');
    } catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    User user = Provider.of<User>(context);

    if (user.homeAirport != '') {
      return Scaffold(
        body: FutureBuilder(
          future: Global.tripsRef.getData(),
          builder: (BuildContext context, AsyncSnapshot snap) {
            if (snap.hasData) {
              return Center(
                child: Container(
                  color: Colors.white,
                  child: ListView(
                    physics: ClampingScrollPhysics(),
                    scrollDirection: Axis.vertical,
                    children: <Widget>[
                      Text('Wavetrotter Suggestions'),
                      TripList(),
                      for (var prod in _products)
                        _available && !user.premium
                            ? FlatButton(
                                child: Text('Subscribe'),
                                onPressed: () => _buyProduct(prod),
                                color: Colors.green,
                              )
                            : SizedBox(height: 0.0),
                      Text('Trips For You'),
                      !user.premium ? BlurredCategory() : TripList(),
                      Text('Biggest Swells'),
                      !user.premium ? BlurredCategory() : TripList(),
                      Text('No Wetsuit'),
                      !user.premium ? BlurredCategory() : TripList(),
                    ],
                  ),
                ),
              );
            } else {
              return LoadingScreen();
            }
          },
        ),
      );
    } else {
      return InitialAirport();
    }
  }
}

标签: firebaseflutterin-app-purchaseflutter-dependencies

解决方案


推荐阅读