in_app_purchase_android:Flutter 应用内购买插件在 Android 平台的 BillingClient 实现指南

发布时间:2026/9/21 1:35:10
in_app_purchase_android:Flutter 应用内购买插件在 Android 平台的 BillingClient 实现指南 移动开发跨平台【免费下载链接】pluginsPlugins for Flutter maintained by the Flutter team项目地址https://gitcode.com/gh_mirrors/pl/plugins点击查看免费下载in_app_purchase_android是 Flutter 官方 in_app_purchase 插件的 Android 平台实现内部基于 Google Play BillingClient API 完成商品查询、发起购买、消费与订阅管理等全套应用内购买流程。本文以该包的 README 为核心骨架结合包内 Dart 封装、Java 原生实现与测试代码说明如何接入、如何调用平台专属能力、底层如何桥接以及参与该插件开发时如何用build_runner维护序列化代码。插件定位被官方背书的联合插件实现in_app_purchase_android是in_app_purchase这一联合插件federated plugin在 Android 端的默认实现。该包本身不对开发者暴露独立入口而是实现 Flutter 团队定义的统一InAppPurchasePlatform接口将 Android 上的 Google Play 购买能力翻译成跨平台通用 API。从 pubspec.yaml 可以看到其联合插件的身份声明name: in_app_purchase_android description: An implementation for the Android platform of the Flutter in_app_purchase plugin. This uses the Android BillingClient APIs. version: 0.2.41 environment: sdk: 2.14.0 3.0.0 flutter: 3.0.0 flutter: plugin: implements: in_app_purchase platforms: android: package: io.flutter.plugins.inapppurchase pluginClass: InAppPurchasePlugin dependencies: collection: ^1.15.0 flutter: sdk: flutter in_app_purchase_platform_interface: ^1.3.0 json_annotation: ^4.6.0implements: in_app_purchase即“背书”endorsed标记当应用依赖in_app_purchase时Flutter 工具链会自动把本包纳入构建开发者无需显式依赖它。Android 原生入口类为io.flutter.plugins.inapppurchase.InAppPurchasePlugin对应 InAppPurchasePlugin.java。快速接入两种依赖方式按官方 README 的 Usage 说明接入方式取决于你是否需要使用 Android 平台专属 API方式一只添加主包推荐绝大多数场景由于本包已被背书仅在pubspec.yaml中添加in_app_purchase即可Android 实现会被自动带入dependencies: in_app_purchase: ^3.0.0方式二直接添加 Android 包当你的业务需要使用in_app_purchase_android暴露的 Android 专属接口如InAppPurchaseAndroidPlatformAddition、billing_client_wrappers时需要把in_app_purchase_android作为显式依赖直接添加dependencies: in_app_purchase: ^3.0.0 in_app_purchase_android: ^0.2.4两种方式最终都会在 Android 构建时引入io.flutter.plugins.inapppurchase的原生代码区别仅在于后者允许你在 Dart 层直接 import 平台扩展 API如package:in_app_purchase_android/in_app_purchase_android.dart与package:in_app_purchase_android/billing_client_wrappers.dart。注意不建议再自行在android/app/build.gradle中重复依赖com.android.billingclient:billing以免与插件内置的 BillingClient 版本冲突。核心 APIInAppPurchaseAndroidPlatform 如何翻译 BillingClient平台实现的主体是 InAppPurchaseAndroidPlatform它继承自平台接口层的InAppPurchasePlatform把通用 API 翻译成一个个 BillingClient 调用。以下几点是理解其行为的钥匙。错误码与来源常量源码顶部定义了 Android 侧统一使用的错误语义kPurchaseErrorCode purchase_error购买失败kConsumptionFailedErrorCode consume_purchase_failed消费已购商品失败kRestoredPurchaseErrorCode restore_transactions_failed查询历史交易失败kIAPSource google_play标识当前商店前端为 Google Play。这些常量会作为IAPError.code出现在purchaseStream中是判断错误类别的依据。商品查询一次并发查询两类 SKUqueryProductDetails并非只查一次而是同时用SkuType.inapp与SkuType.subs各发起一次querySkuDetails再将两次结果合并为一个ProductDetailsResponse。被过滤出的未找到 ID 会放入notFoundIDs任一查询抛出PlatformException时会转换为带BillingResponse.error的响应并填充error字段。从源码结构看这样设计是为了让一次查询同时覆盖一次性商品与订阅商品减少开发者对两类 SKU 的分开处理。购买流程与自动消费buyConsumable与buyNonConsumable最终都走launchBillingFlow。区别在于buyConsumable在autoConsume默认true时会把商品 ID 记入内部静态集合_productIdsToConsume等购买结果经purchaseStream回调回来时由_maybeAutoConsumePurchase自动调用consumePurchase完成消费若消费失败购买状态会被置为PurchaseStatus.error并附上kConsumptionFailedErrorCode错误。因此使用通用 API 时可消耗商品通常无需手动消费。完成购买acknowledge 语义Android 侧调用completePurchase时若底层GooglePlayPurchaseDetails.billingClientPurchase.isAcknowledged已为真则直接返回成功否则要求verificationData非空并转发到BillingClient.acknowledgePurchase。这一点与主包 README 的警告呼应不调用completePurchase或未在期限内得到成功响应Google Play 会退款。恢复购买并发查询两类历史订单restorePurchases并发执行queryPurchases(SkuType.inapp)与queryPurchases(SkuType.subs)将结果统一置为PurchaseStatus.restored后推入purchaseStream。任一响应码非BillingResponse.ok时抛出InAppPurchaseExceptioncode 为kRestoredPurchaseErrorCode。需要留意的是已被消费的可消耗商品不会出现在这里跨设备恢复可消耗品需自行在服务端持久化。Android 平台专属扩展InAppPurchaseAndroidPlatformAddition通用 API 无法覆盖的平台能力集中在 InAppPurchaseAndroidPlatformAddition 中通过getPlatformAdditionInAppPurchaseAndroidPlatformAddition()获取。它提供以下方法方法用途consumePurchase手动消费一笔购买消费前用户无法再次购买同一商品queryPastPurchases查询所有历史购买不返回已消费商品applicationUserName需与初始PurchaseParam保持一致未传则传nullisFeatureSupported检查设备/Play 商店是否支持某个BillingClientFeaturelaunchPriceChangeConfirmationFlow弹出订阅涨价确认界面sku需已通过queryProductDetails获取一个典型用法是订阅涨价确认。Google Play 上调订阅价格后默认会弹出确认框若开发者希望延后展示可手动触发该流程import package:in_app_purchase_android/in_app_purchase_android.dart; import package:in_app_purchase_android/billing_client_wrappers.dart; if (Platform.isAndroid) { final InAppPurchaseAndroidPlatformAddition androidAddition _inAppPurchase .getPlatformAdditionInAppPurchaseAndroidPlatformAddition(); final result await androidAddition.launchPriceChangeConfirmationFlow( sku: your_subscription_id, ); if (result.responseCode BillingResponse.ok) { // 用户确认了价格变更 } else { // 展示错误提示 } }另外源码中enablePendingPurchase与enablePendingPurchases()均已标记DeprecatedGoogle Play 已不再接受不支持 pending purchases 的应用因此该能力被内置且恒为true调用此方法已无实际作用实现为空操作无需在初始化时再调用。平台专属数据GooglePlayProductDetails 与 GooglePlayPurchaseDetails通用 API 返回的ProductDetails、PurchaseDetails在 Android 上实际是子类GooglePlayProductDetails、GooglePlayPurchaseDetails定义于 types 目录。当需要读取平台独有字段时可向下转型后访问原始包装对象商品侧(productDetails as GooglePlayProductDetails).skuDetails返回 SkuDetailsWrapper可读取introductoryPricePeriod、subscriptionPeriod、originalJson等 Google Play SKU 原始字段购买侧(purchaseDetails as GooglePlayPurchaseDetails).billingClientPurchase返回 PurchaseWrapper可读取originalJson、isAcknowledged、isAutoRenewing等字段。使用这些字段前需要同时 importin_app_purchase_android与billing_client_wrappers。这也是官方 README 给出的两种使用路线之一除通用 API 外billing_client_wrappers作为更贴近 JavaBillingClient的底层 Dart 封装可当作in_app_purchase的替代品直接调用见 billing_client_wrappers/README.md。底层原理Dart、MethodChannel 与 Java BillingClient 的三层桥接从源码结构可以梳理出完整调用链Dart 层 BillingClient → MethodChannelchannel.dart→ Java 层MethodCallHandlerImpl→ 原生com.android.billingclient.api.BillingClient。Java 端 MethodCallHandlerImpl.java 以字符串方法名分发调用例如BillingClient#querySkuDetailsAsync(SkuDetailsParams, SkuDetailsResponseListener)、BillingClient#launchBillingFlow(...)等一一对应 Dart 端的invokeMethod。原生BillingClient实例由BillingClientFactoryImpl创建BillingClientFactoryImpl.javaJava 回调如PurchasesUpdatedListener#onPurchasesUpdated、onBillingServiceDisconnected则通过 method channel 的setMethodCallHandler反向回调到 Dart 层注册的监听器。Dart 侧用一张“方法名 → 回调列表”的映射表_callbacks保存这些回调句柄Java 层触发时按句柄取回执行从而把 Java 回调模式转换成 Dart 的 Future/Stream。购买结果统一由PurchasesUpdatedListener回调到 DartInAppPurchaseAndroidPlatform构造时将其包装为purchaseStream的广播流所有购买更新包括应用内发起的和 Play 商店直接发起的都会流经InAppPurchase.instance.purchaseStream。因此官方建议在initState尽早订阅以免漏掉上一会话遗留的购买更新。原生层同样有配套测试Java 端 MethodCallHandlerTest.java、InAppPurchasePluginTest.java 与 TranslatorTest.java 覆盖了方法分发、结果翻译与生命周期处理Dart 侧则在包的 test 目录中通过 mockBillingClient验证平台类行为例如购买结果到PurchaseDetails状态purchased/canceled/error的映射逻辑。参与开发json_serializable 与 build_runner 维护流程该插件在 Dart 与原生层之间传递大量数据结构和序列化 JSON如SkuDetailsWrapper、PurchaseWrapper、BillingResultWrapper及其.g.dart文件因此依赖json_annotation与json_serializable。官方 README 明确编辑任何被序列化的数据结构后必须重新生成序列化代码命令如下# 一次性重建序列化代码会删除冲突输出 flutter packages pub run build_runner build --delete-conflicting-outputs # 监听文件变化增量生成 flutter packages pub run build_runner watch --delete-conflicting-outputs第一行适合在修改完JsonSerializable注解类后手动执行一次第二行适合长时间开发时让build_runner驻留监听改动即自动重新生成对应的.g.dart。涉及的源文件包括 billing_client_wrapper.dart、purchase_wrapper.dart 与 sku_details_wrapper.dart 等。需要说明的是本仓库只读开发者应基于 fork 的副本执行上述生成命令并提交生成的.g.dart文件。小结in_app_purchase_android通过“背书”机制让 Flutter 应用在 Android 上开箱即用地获得 Google Play 应用内购买能力同时保留了两条进阶路径向上转型读取GooglePlayProductDetails/GooglePlayPurchaseDetails获取平台原始数据或直接使用InAppPurchaseAndroidPlatformAddition与billing_client_wrappers精细控制消费、历史查询、特性检测与订阅价格确认等专属流程。理解其“Dart 封装 → MethodChannel → Java BillingClient”的三层结构有助于在排查购买回调、处理 acknowledge/consume 时序以及扩展新 Billing 特性时快速定位问题。赞分享移动开发跨平台【免费下载链接】pluginsPlugins for Flutter maintained by the Flutter team项目地址https://gitcode.com/gh_mirrors/pl/plugins点击查看免费下载相关推荐Capacitor应用内购买实现iOS与Android支付集成全指南Capacitor应用内购买实现iOS与Android支付集成全指南 引言解决跨平台支付的痛点 你是否还在为Capacitor应用开发中iOS与Androi移动开发跨平台插件系统前端Flutter应用内购买终极指南三步实现跨平台收入变现Flutter应用内购买终极指南三步实现跨平台收入变现 想要为你的Flutter应用添加应用内购买功能吗Flutter InApp Purchase插件为你从论文到落地mobilevitv2_050.cvnets_in1k在ImageNet-1k上的训练与优化从论文到落地mobilevitv2_050.cvnets_in1k在ImageNet 1k上的训练与优化 mobilevitv2_050.cvnets_in1上一篇TastyIgniter多门店管理实战连锁餐厅的统一运营平台终极指南下一篇突破单机限制用LangChain Go构建分布式AI系统的实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考