Flutter应用内购买插件in_app_purchaser的使用

in_app_purchaser

在Flutter中实现应用内购买功能,可以使用in_app_purchaser插件。该插件支持多种支付网关,并提供了简洁的API来处理购买流程。

示例代码

以下是一个完整的示例,展示如何使用in_app_purchaser插件来实现应用内购买功能。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:in_app_purchaser/in_app_purchaser.dart';
import 'package:in_app_purchaser_revenue_cat_delegate/in_app_purchaser_revenue_cat_delegate.dart';

// 替换为您的Revenue Cat API密钥
const kQonversionApiKey = "";

void main() {
  runApp(
    PurchaseProvider(
      delegate: const RevenueCatDelegate(
        apiKey: kQonversionApiKey,
      ),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'In App Purchaser',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const PurchasePaywall(),
    );
  }
}

class PurchasePaywall extends StatelessWidget {
  const PurchasePaywall({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey.shade100,
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(32),
          child: Stack(
            children: [
              ListenableBuilder(
                listenable: Purchaser.i,
                builder: (context, child) {
                  return const PurchaseButton();
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class PurchaseButton extends StatefulWidget {
  const PurchaseButton({
    super.key,
  });

  @override
  State<PurchaseButton> createState() => _PurchaseButtonState();
}

class _PurchaseButtonState extends State<PurchaseButton> {
  int selected = 0;

  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: Alignment.bottomCenter,
      child: Padding(
        padding: const EdgeInsets.only(left: 15, right: 15, bottom: 5),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Text(
              'Get Unlimited Access',
              style: TextStyle(
                fontSize: 16,
              ),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 20),
            Column(
              children: List.generate(Purchaser.i.products.length, (index) {
                final product = Purchaser.i.products.elementAtOrNull(index);
                final priceString = product?.priceString ?? '0 BDT';
                final monthlyPrice = (product?.price ?? 0) / 12;
                return MonthlyPlan(
                  leftSideString: priceString,
                  selected: selected == index,
                  rightSideString: monthlyPrice.toString(),
                  discount: "25%",
                  onTap: () => setState(() => selected = index),
                );
              }),
            ),
            const SizedBox(height: 5),
            CupertinoButton(
              padding: EdgeInsets.zero,
              onPressed: () => Purchaser.i.purchaseAt(selected),
              child: Container(
                height: 65,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(1000),
                  color: Colors.black,
                ),
                padding: const EdgeInsets.symmetric(
                  horizontal: 20,
                ),
                alignment: Alignment.center,
                child: Builder(builder: (context) {
                  if (Purchaser.i.products.isEmpty) {
                    return const SizedBox.square(
                      dimension: 24,
                      child: CircularProgressIndicator(
                        color: Colors.white,
                        strokeWidth: 3,
                      ),
                    );
                  }
                  return const FittedBox(
                    child: Text(
                      'Continue',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 20,
                        fontWeight: FontWeight.w700,
                      ),
                    ),
                  );
                }),
              ),
            ),
            Padding(
              padding: const EdgeInsets.only(top: 10, bottom: 0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  GestureDetector(
                    child: const Text(
                      'Terms ',
                      style: TextStyle(
                        fontSize: 10,
                        color: Colors.grey,
                        fontWeight: FontWeight.w600,
                        decoration: TextDecoration.underline,
                        decorationColor: Colors.grey,
                      ),
                    ),
                  ),
                  GestureDetector(
                    onTap: Purchaser.i.restore,
                    child: const Text(
                      'Restore ',
                      style: TextStyle(
                        fontSize: 10,
                        color: Colors.grey,
                        fontWeight: FontWeight.w600,
                        decoration: TextDecoration.underline,
                        decorationColor: Colors.grey,
                      ),
                    ),
                  ),
                  GestureDetector(
                    child: const Text(
                      'Privacy ',
                      style: TextStyle(
                        fontSize: 10,
                        color: Colors.grey,
                        fontWeight: FontWeight.w600,
                        decoration: TextDecoration.underline,
                        decorationColor: Colors.grey,
                      ),
                    ),
                  ),
                  GestureDetector(
                    child: const Text(
                      'User ID ',
                      style: TextStyle(
                        fontSize: 10,
                        color: Colors.grey,
                        fontWeight: FontWeight.w600,
                        decoration: TextDecoration.underline,
                        decorationColor: Colors.grey,
                      ),
                    ),
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

class MonthlyPlan extends StatelessWidget {
  final String leftSideString;
  final bool selected;
  final String rightSideString;
  final String? discount;
  final VoidCallback onTap;

  const MonthlyPlan({
    super.key,
    required this.leftSideString,
    required this.selected,
    required this.rightSideString,
    required this.onTap,
    this.discount,
  });

  @override
  Widget build(BuildContext context) {
    return CupertinoButton(
      padding: EdgeInsets.zero,
      onPressed: onTap,
      child: Container(
        height: 76,
        margin: const EdgeInsets.only(bottom: 10),
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.circular(20),
          border: Border.all(
            color: selected ? Colors.black : Colors.transparent,
            width: 3,
          ),
        ),
        padding: const EdgeInsets.only(
          right: 20,
          left: 15,
        ),
        child: Stack(
          clipBehavior: Clip.none,
          alignment: Alignment.centerLeft,
          children: [
            Text(
              leftSideString,
              style: const TextStyle(
                fontSize: 16,
                color: Colors.black,
              ),
            ),
            Align(
              alignment: Alignment.centerRight,
              child: Text.rich(
                textScaler: TextScaler.noScaling,
                TextSpan(
                  children: [
                    TextSpan(
                      text: rightSideString,
                      style: const TextStyle(
                        fontSize: 15,
                        color: Colors.black,
                        fontWeight: FontWeight.w700,
                      ),
                    ),
                  ],
                ),
              ),
            ),
            if ((discount ?? '').isNotEmpty) ...[
              Positioned(
                top: -15,
                right: -0,
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.black,
                    borderRadius: BorderRadius.circular(105),
                  ),
                  padding: const EdgeInsets.symmetric(
                    horizontal: 10,
                    vertical: 5,
                  ),
                  child: Text(
                    discount!,
                    style: const TextStyle(
                      color: Colors.white,
                      fontSize: 12,
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }
}

说明

  1. 依赖配置: 在pubspec.yaml中添加以下依赖:
    dependencies:
      in_app_purchaser: ^latest_version
      in_app_purchaser_revenue_cat_delegate: ^latest_version
1 回复

更多关于Flutter应用内购买插件in_app_purchaser的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


in_app_purchase 是 Flutter 官方提供的一个插件,用于在应用中实现应用内购买功能。它支持 Android 和 iOS 平台,并且提供了统一的 API 来处理应用内购买流程。以下是如何使用 in_app_purchase 插件的基本步骤:

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 in_app_purchase 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  in_app_purchase: ^3.0.6  # 请使用最新版本

然后运行 flutter pub get 来安装依赖。

2. 配置应用内购买

Android

android/app/build.gradle 文件中,确保 minSdkVersion 至少为 16:

defaultConfig {
    minSdkVersion 16
    targetSdkVersion 30
    ...
}

iOS

ios/Runner/Info.plist 文件中,添加以下内容以启用应用内购买:

<key>SKPaymentQueueShouldAddStorePayment</key>
<true/>

3. 初始化 InAppPurchase

在你的 Dart 文件中,导入 in_app_purchase 插件并初始化它:

import 'package:in_app_purchase/in_app_purchase.dart';

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final InAppPurchase _inAppPurchase = InAppPurchase.instance;

  [@override](/user/override)
  void initState() {
    super.initState();
    _initialize();
  }

  Future<void> _initialize() async {
    final bool available = await _inAppPurchase.isAvailable();
    if (!available) {
      // 处理应用内购买不可用的情况
      return;
    }

    // 监听购买更新
    _inAppPurchase.purchaseStream.listen((List<PurchaseDetails> purchaseDetailsList) {
      _handlePurchase(purchaseDetailsList);
    });
  }

  void _handlePurchase(List<PurchaseDetails> purchaseDetailsList) {
    for (var purchaseDetails in purchaseDetailsList) {
      if (purchaseDetails.status == PurchaseStatus.purchased) {
        // 处理购买成功的情况
      } else if (purchaseDetails.status == PurchaseStatus.error) {
        // 处理购买失败的情况
      }
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('In-App Purchase Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: _buyProduct,
            child: Text('Buy Product'),
          ),
        ),
      ),
    );
  }

  Future<void> _buyProduct() async {
    const String productId = 'your_product_id';
    final ProductDetailsResponse response = await _inAppPurchase.queryProductDetails({productId});

    if (response.notFoundIDs.isNotEmpty) {
      // 处理未找到产品的情况
      return;
    }

    final ProductDetails productDetails = response.productDetails.first;
    final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);

    await _inAppPurchase.buyConsumable(purchaseParam: purchaseParam);
  }
}
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!