Flutter集成in_app_purchase包触发java.lang.NullPointerException求助
Flutter集成in_app_purchase包出现java.lang.NullPointerException问题排查
我在Flutter项目中集成in_app_purchase包(用于对接自有后端验证购买),但运行后出现java.lang.NullPointerException错误,控制台仅输出:
W/BillingLogger( 7906): Unable to log. W/BillingLogger( 7906): java.lang.NullPointerException
相关代码如下:
class SubscriptionPage extends StatefulWidget { const SubscriptionPage({super.key}); @override State<SubscriptionPage> createState() => _SubscriptionPageState(); } class _SubscriptionPageState extends State<SubscriptionPage> { final InAppPurchase _inAppPurchase = InAppPurchase.instance; late StreamSubscription<List<PurchaseDetails>> _subscription; //Product Listing static const List<String> _productIds = [ 'com.....subscription' ]; @override void initState() { final Stream<List<PurchaseDetails>> purchaseUpdated = _inAppPurchase.purchaseStream; _subscription = purchaseUpdated.listen((List<PurchaseDetails> purchaseDetailsList) { if (mounted) { _listenToPurchaseUpdated(purchaseDetailsList, context); } }, onDone: () { _subscription.cancel(); }, onError: (Object error) { if (mounted) { showSnackBar(context, 'Something went wrong', Severity.error); } }); super.initState(); } Future<Subscription> getProducts() async { final bool isAvailable = await _inAppPurchase.isAvailable(); if (!isAvailable) { return Subscription( isAvailable: isAvailable, products: [], notFoundIds: [], ); } final ProductDetailsResponse productDetailResponse = await _inAppPurchase.queryProductDetails(_productIds.toSet()); if (productDetailResponse.error != null) { throw Exception(productDetailResponse.error!.message); } return Subscription( isAvailable: isAvailable, products: productDetailResponse.productDetails, notFoundIds: productDetailResponse.notFoundIDs, ); } @override void dispose() { _subscription.cancel(); super.dispose(); } @override Widget build(BuildContext context) { var media = MediaQuery.of(context).size; return Scaffold( appBar: const BasicAppBar( title: 'Subscription', isBack: true, level: '3', ), body: Column( children: [ //..... ], ), ); } _listenToPurchaseUpdated( List<PurchaseDetails> purchaseDetailsList, BuildContext context) async { for (final PurchaseDetails purchaseDetails in purchaseDetailsList) { if (purchaseDetails.status == PurchaseStatus.pending) { showSnackBar( context, 'You are purchasing a subscription', Severity.success, ); } else if (purchaseDetails.status == PurchaseStatus.error) { showSnackBar( context, 'Your purchased failed!', Severity.error, ); } else if (purchaseDetails.status == PurchaseStatus.purchased) { showSnackBar( context, 'Your purchase is successfully', Severity.success, ); } } } }
排查与解决建议
强制指定Google Billing库版本
in_app_purchase底层依赖Google Play Billing库,版本不匹配可能触发空指针。在android/app/build.gradle中明确指定兼容版本:dependencies { implementation 'com.android.billingclient:billing:6.1.0' }调整初始化时机
避免在initState中直接订阅流,先确认服务可用再初始化:@override void initState() { super.initState(); _initPurchaseStream(); } Future<void> _initPurchaseStream() async { final bool isAvailable = await _inAppPurchase.isAvailable(); if (isAvailable && mounted) { final Stream<List<PurchaseDetails>> purchaseUpdated = _inAppPurchase.purchaseStream; _subscription = purchaseUpdated.listen( (List<PurchaseDetails> purchaseDetailsList) { _listenToPurchaseUpdated(purchaseDetailsList, context); }, onDone: () { if (mounted) _subscription.cancel(); }, onError: (Object error) { if (mounted) showSnackBar(context, 'Something went wrong', Severity.error); }, ); } }校验产品ID与空值处理
确保_productIds与Google Play Console中配置的订阅ID完全一致;同时在购买监听逻辑中增加空值判断:void _listenToPurchaseUpdated( List<PurchaseDetails> purchaseDetailsList, BuildContext context) { for (final PurchaseDetails? purchaseDetails in purchaseDetailsList) { if (purchaseDetails == null) continue; // 后续状态判断逻辑 } }清理构建缓存
执行以下命令清理缓存后重新构建项目:flutter clean flutter pub get cd android && ./gradlew clean && cd ..
内容的提问来源于stack exchange,提问作者user25770779
相关产品推荐
相关产品推荐

