react-native-iap iOS端getSubscriptions获取订阅挂起无响应
问题描述
下述组件在Android端可正常运行,原本判定功能已调试完成,但相同代码在iOS端尝试获取订阅时会出现挂起问题:请求既不返回成功、也不抛出失败、不会触发崩溃,对应的JS Promise始终不会被决议(既不resolve也不reject)。
本次测试运行在登录了本人Apple账号的正版真机iPhone上,设备连接MacBook Pro调试,该设备本身的应用内购买功能无任何异常。
运行日志
LOG [Subscription] Will init connection LOG [Subscription] Did init connection LOG [Subscription] Will clear transaction ios LOG [Subscription] Did clear transaction ios LOG [Subscription] Will get subscription ...then nothing, I've waited over 5 minutes...
组件代码
import React, { Component } from "react"; import { Platform, Text, TouchableOpacity } from "react-native"; import * as Sentry from "@sentry/react-native"; import * as RNIap from "react-native-iap"; import { Subscription, SubscriptionPurchase } from "react-native-iap/src/types"; import { SUBSCRIPTION_ID } from "../env"; class SubscriptionScreen extends Component { state = { subscription: undefined, available: undefined, }; constructor(props) { super(props); } async componentDidMount() { try { console.log('[Subscription]','Will init connection'); await RNIap.initConnection(); console.log('[Subscription]','Did init connection'); if (Platform.OS === 'ios') { console.log('[Subscription]','Will clear transaction ios'); await RNIap.clearTransactionIOS(); console.log('[Subscription]','Did clear transaction ios'); } console.log('[Subscription]','Will get subscription'); const subscription: Subscription = (await RNIap.getSubscriptions([SUBSCRIPTION_ID])).find(s => s.productId === SUBSCRIPTION_ID); console.log('[Subscription]','Did get subscription', subscription); console.log('[Subscription]','Will get available'); const available: SubscriptionPurchase = (await RNIap.getAvailablePurchases([SUBSCRIPTION_ID])).find(p => p.productId === SUBSCRIPTION_ID); console.log('[Subscription]','Did get available', available); this.setState({subscription, available}); } catch (err) { console.error('Failed to get subscriptions!', err.code, err.message); Sentry.captureException(err); } } async componentWillUnmount() { console.log('[Subscription]','Will close connection'); await RNIap.endConnection(); console.log('[Subscription]','Did close connection'); } async purchaseSubscription() { try { await RNIap.requestSubscription(SUBSCRIPTION_ID); } catch (err) { console.error('Failed to purchase subscriptions!', err.code, err.message); Sentry.captureException(err); } } render() { if (this.state.available) return ( <Text>You're a subscriber!</Text> ) else return ( <TouchableOpacity onPress={this.purchaseSubscription} > <Text>Subscribe</Text> </TouchableOpacity> ) } } export default SubscriptionScreen;
依赖版本
"react": "17.0.2", "react-native": "0.66.3", "react-native-iap": "^8.0.0-rc.6",
可尝试的排查方向
- 先确认iOS端内购配置完整性:检查App Store Connect中对应订阅商品的状态是否为准备提交/已批准,确保商品ID、订阅组配置、税务银行协议全部生效,iOS端商品查询请求对未完成配置的商品不会返回错误,只会直接挂起无响应。
- 替换依赖版本:当前使用的
react-native-iap@8.0.0-rc.6属于预览版本,存在已知的iOS端SKProductsRequest回调未正确桥接的问题,直接升级到v8.0.0及以上的正式稳定版即可修复该类Promise挂起问题,不要使用rc预览版本处理支付相关逻辑。 - 调整初始化调用顺序:不要在
initConnection完成后立即调用clearTransactionIOS,该方法会清空当前交易队列并中断商品请求监听,可将该方法调用移到购买流程结束后,或暂时注释该步骤验证是否能正常拿到商品列表。 - 查看原生端系统日志:打开Xcode运行项目,在控制台筛选
StoreKit相关日志,确认是否有无法连接App Store、商品ID无效类的系统级报错,JS层未做桥接捕获的原生端报错不会触发Promise reject,只会导致请求永久挂起。 - 修正测试账号配置:不要使用登录了正式Apple ID的设备测试开发包内购,需要在iOS设置的「App Store-沙盒账户」入口单独登录沙盒测试账号,正式账号在调试包环境下发起StoreKit请求会被系统拦截且无任何回调。
- 检查全局监听冲突:确认项目中没有其他模块在当前组件挂载前调用过
endConnection方法,StoreKit全局只存在一个交易监听实例,被提前释放后所有后续内购请求都会无响应。
内容的提问来源于stack exchange,提问作者Nick Charney Kaye
相关产品推荐
相关产品推荐

