0

我尝试将 in_app_purchase 与 Riverpod 一起使用。因此,我以 pub.dev 中的示例为例,并尝试使用 Riverpod 和 StateNotifier 来适应我的情况,但我有这个错误:LateInitializationError: Field '_instance@579396890' has not been initialized 我不知道如何修复它。

主要飞镖:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:inapppayement/subscription_provider.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(ProviderScope(child:MyApp()));
}

class MyApp extends ConsumerWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context, WidgetRef ref) {
      ref.read(inAppPurchaseProvider.notifier).init();
    late InAppPurchaseClass inApp=ref.watch(inAppPurchaseProvider);
    return MaterialApp(
      title: 'Flutter InAppPurchase TEST', 
      home:Scaffold(
        body: Center(
          child: (inApp.isAvailable) ? Column(
            children: [
              if (inApp.loading ) const LinearProgressIndicator()
              else if (inApp.purchasePending) const CircularProgressIndicator()
              else if (inApp.products.isNotEmpty)
              ListTile(
                leading: const Icon(Icons.attach_money),
                title: Text(inApp.products[0].title + " - " + inApp.products[0].price), 
                subtitle: Text(inApp.products[0].description),
                trailing: ElevatedButton( onPressed: () { ref.read(inAppPurchaseProvider.notifier).subscribe(product: inApp.products[0]);}, child: const Text('Subscribe'),
                ) 
              )
              else const Text("Erreur produit"),

              if (inApp.purchases.isNotEmpty) 
                ListView.builder(
                  itemCount:inApp.purchases.length,
                  itemBuilder: (context,index) {
                    return Text(inApp.purchases[index].status.toString()+" / Produit ID : "+inApp.purchases[index].productID+" / Date transaction : "+inApp.purchases[index].transactionDate!);
                  }
                ),
              if (inApp.error.isNotEmpty) Text(inApp.error),
            ],
          ) : const Text("The Store is not Available")
        )
      )
    );
  }
}

subscription_provider.dart :

import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:in_app_purchase/in_app_purchase.dart';

class InAppPurchaseClass {
  InAppPurchaseClass({required this.isAvailable,required this.products,required this.purchases,required this.purchasePending,required this.loading, required this.error});
  final bool isAvailable;
  final List<ProductDetails> products;
  final List<PurchaseDetails> purchases;
  final bool purchasePending;
  final bool loading;
  final String error;

  InAppPurchaseClass copyWith({bool? isAvailable,List<ProductDetails>? products,List<PurchaseDetails>? purchases,bool? purchasePending,bool? loading, String? error}) {
    return InAppPurchaseClass(isAvailable:isAvailable??this.isAvailable,products:products??this.products,purchases:purchases??this.purchases,purchasePending:purchasePending??this.purchasePending,loading:loading??this.loading,error:error??this.error);
  }
}

final inAppPurchaseProvider=StateNotifierProvider<InAppPurchaseNotifier,InAppPurchaseClass>((ref)=>InAppPurchaseNotifier(ref.read,InAppPurchase.instance));

class InAppPurchaseNotifier extends StateNotifier<InAppPurchaseClass> {
  InAppPurchaseNotifier(this.read, this._inAppPurchase) : super(InAppPurchaseClass(isAvailable: false,products:[],purchases:[],purchasePending:false,loading:true, error: ""));
  final Reader read;
  final InAppPurchase _inAppPurchase;
  late StreamSubscription<List<PurchaseDetails>>? _subscription;

  init() {
    final Stream<List<PurchaseDetails>> purchaseUpdated = _inAppPurchase.purchaseStream;
    _subscription= purchaseUpdated.listen((purchaseDetailsList) {
      state=state.copyWith(purchases:purchaseDetailsList);
   
      purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
        switch (purchaseDetails.status) {
          case PurchaseStatus.pending:
            state=state.copyWith(purchasePending:true);
            break;
          case PurchaseStatus.purchased:
          case PurchaseStatus.restored:
            break;    // Check if valid Purchase before break
          case PurchaseStatus.error:
            state=state.copyWith(error: purchaseDetails.error!.message);
            break;
          default:
            break;
        }

        if (purchaseDetails.pendingCompletePurchase) {
          await _inAppPurchase.completePurchase(purchaseDetails);
        }
    });
    }, onDone: () {_subscription!.cancel();
    }, onError: (error) {_subscription!.cancel();
  });

  updateStore();    // Load all to state product
}

  updateStore() async {
    state=state.copyWith(isAvailable: await _inAppPurchase.isAvailable());
    ProductDetailsResponse response= await _inAppPurchase.queryProductDetails(<String>{"prenium_plan"});  // ID Of Product
    state=state.copyWith(products:response.productDetails, loading: false);   
  }


  subscribe({required ProductDetails product}) {
    final PurchaseParam purchaseParam = PurchaseParam(productDetails: product);
    _inAppPurchase.buyNonConsumable(purchaseParam: purchaseParam);
  }

  @override
  dispose(){
    _subscription!.cancel();
    super.dispose();
  }
}
4

0 回答 0