React-native-iap: 如果尚不存在付款方式,则当实时添加付款方式时,iOS应用内购买失败

创建于 2018-10-31  ·  27评论  ·  资料来源: dooboolab/react-native-iap

版本的react-native-iap

react-native-iap": "^2.3.17

您遇到错误的平台(IOS或Android还是两者兼有?)

的iOS

预期行为

仅应在调用finishTransaction时付款

实际行为

添加信用卡等付款方式后,系统会检测到该金额。
但是达到了RNIap.buyProductWithoutFinishTransaction(sku)方法。

经过测试的环境(仿真器?真实设备?)

真实设备-iPhone 6s

重现行为的步骤

  • 检查以确保设备中的Apple帐户的付款方式设置为无或某些无效的付款详细信息
  • 通过应用进行应用内购买
  • 用户被带到“帐户设置”页面以添加有效的付款方式
  • 支付方式已收费,但以下代码未收到交易收据
ComponentDidMount(){
     await RNIap.initConnection();
     await RNIap.consumeAllItems();
     const prod = await RNIap.getProducts(product);

} 

  async componentWillUnmount() {
       RNIap.endConnection()
}

buyProduct(sku){
await RNIap.clearTransaction();

RNIap.buyProductWithoutFinishTransaction(sku)
.then(purchase => {
  // not reached
 if(calltoserverisSuccess){
    RNIap.finishTransaction();
 }
})
.catch(error => {
 // code enters catch case if ever
}}
📱 iOS 🙏 help wanted

最有用的评论

我认为我们需要为此联系apple ,这看起来真的很糟糕,因为有一个不同的测试用例在sandbox环境中是不可复制的。 对于那些想了解问题的人,我已经记录了屏幕,您可以在这里查看@anandwahed您还可以联系苹果吗? 因为我知道他们并不是那么支持,所以最好让更多的人与他们联系。 让我们共同解决这个问题。

所有27条评论

抱歉,您的代码似乎有很多语法错误。 请参考我们仓库中的示例项目,然后与您的代码进行比较。

@dooboolab
感谢您的答复,此处发布的代码仅作为示例,这与实际应用程序中使用的并不完全相同。
我会尽力解释问题所在

  1. componentDidMount

    • 通过调用RNIap.initConnection();启动连接

    • 然后通过调用RNIap.getProducts(product)获取产品并将其存储在状态中

  1. 当用户点击购买按钮时

    • 调用RNIap.clearTransaction();只是为了确保没有剩余的未决交易。
    • 如果成功,则调用RNIap.buyProductWithoutFinishTransaction(sku)如果服务器成功,则触发对应用程序服务器的调用,然后调用RNIap.finishTransaction();以完成付款。
  2. componentWillUnmount()

    • RNIap.endConnection()终止连接。

如果用户已经添加了付款方式,则此过程可以正常进行。 如果用户未添加付款方式,则需要添加付款方式页面,并在达到RNIap.finishTransaction();之前向您收取费用

谢谢你的细节。 您的问题现在看起来很清楚。 cc @JJMoon

@JJMoon

@ zohaibahmed-22这是沙盒测试用例吗?

@JJMoon不,这是一个真实的环境案例。

我知道当用户处于注销状态或没有信用卡信息时会发生此错误。
如果这些方法工作正常,则此错误的原因可能在其他地方。
我们需要准备此操作,该操作将使应用程序,viewDidDisappear等退出。
在沙盒模式下,此症状发生的方式有所不同。
当我创建一个新的沙箱帐户时,第一次购买不起作用。
在第二次,该设备已登录状态,并且工作正常。
我没有这个错误的线索。

我还认为@dooboolab@JJMoon在通过我们的iOS代码时发现了问题。 在updatedTransactions方法中,当我们在SKPaymentTransactionStateDeferredSKPaymentTransactionStateFailed收到失败消息时,我们不假定为finishTransaction

由于在许多情况下, SKPaymentTransactionStateFailed结果后跟有上面线程6431中提到的SKPaymentTransactionStatePurchased 。 我不确定Objective-C代码,因此请检查并确认是否在失败时清除事务。

@anandwahed我同意你的看法。 我的错。 抱歉
我将研究Apple的线程并解决该问题。

@anandwahed我想这是失败时通往finish transaction的正确方法。 请查找此线程。 https://stackoverflow.com/questions/11008636/inapp-purchase-skpaymentqueue-finish-transaction-doesnt-work
当它失败时,将没有收据,因此您不会应用所购买的产品。 完成交易并不总是意味着“购买”。
同时,我将研究线程6431。

我刚刚阅读了6431线程(https://forums.developer.apple.com/thread/6431#14562)
底线。 自2015年以来未解决问题。哇..
有两种不同的方法来处理这种“存储套件流程”效果。

  1. 不显示任何用户警报。
  2. 显示结果。

我学到了两件事。
答:失败时,我们必须finishTransaction 。 (我猜总是有或没有选项)
B. Storekit流程使成功和失败都有收据。 (这不好)

我建议大家阅读此主题,然后再回到此问题。

我猜,您选择哪种方式(1或2)取决于您自己。
我们可能需要回电以进行故障响应。

@JJMoon表示我们不应该使用buyProductWithoutFinishTransaction吗?

@ maxs15我不是那个意思。 抱歉造成混淆。
StoreKit流可以在任何购买时发生。 这是iOS问题,而不是此模块。
就目前而言,我也没有任何线索。 这件事发生在任何本机iOS应用程序中。 正确的?
我们将在空闲时间中挖掘更多的东西。

今天,我尝试调试此问题,因为我已经产生了此问题。 付款方式finishTransanction已完成,但在payMethod更改时未获得callback 。 我尝试调试一些console.log但无法在dev环境中测试真实的帐单。 有人可以建议我如何调试此过程,以便我可以以real purchase debug为此real purchase吗? 我是否应该在sandbox模式下使用它? 它在沙箱中运行良好,所以我不知道如何调试它。 这是很不情愿的。

让我们收集一些想法,因为我认为这很重要。

当我尝试与非沙箱用户一起购买时,总是出现此错误

@hyochan如果连接真实服务器(您的服务器),则是处于调试模式还是释放模式都无关紧要。 我想您有2个选择。

  1. 您在Xcode中以调试模式在真实设备上运行。 使用JS控制台日志。
  2. 您在Xcode的发布模式下在真实设备上运行。 在Objective-C代码中使用NSLog。
    两种方法都应该起作用。

@JJMoon是的,我已经知道了,但是仍然无法在ios中进行实时购买测试。 这个stackoverflow是真的吗? 那我该如何解决呢? 我们必须测试现场购买。

面对此问题的任何人,我都可以肯定,请给我们一个有关如何解决此问题的想法。 in-app purchase fail when payment method added live ,如问题标题中所述。 我该如何调试? @anandwahed您是否曾就此问题联系过Apple?

@hyochan不,我们没有联系Ap​​ple支持。

我认为我们需要为此联系apple ,这看起来真的很糟糕,因为有一个不同的测试用例在sandbox环境中是不可复制的。 对于那些想了解问题的人,我已经记录了屏幕,您可以在这里查看@anandwahed您还可以联系苹果吗? 因为我知道他们并不是那么支持,所以最好让更多的人与他们联系。 让我们共同解决这个问题。

今天我们收到了苹果的答复failure之后可能再次返回回调。 我们正在研究#348中的解决方法,但恐怕这会很讨厌。

我已发布到2.4.0-beta1 ,以尝试解决此问题。 PR #348已添加到此版本,您还可以查看此功能的自述文件。 请注意,这正在测试中。

我已经在现场购买中对此进行了测试,并且似乎可以正常工作。 但是,请记住,仅应在发生故障时添加侦听器,否则它可能会被复制并产生成功的结果。

伙计们,谢谢您在这个问题上投入时间! 🙏

我认为当前文档需要更清楚地了解addAdditionalSuccessPurchaseListenerIOS的用法。 这就是我试图在#414上解决的问题。

但是我也认为这为改进API留下了空间。 你们愿意讨论API的更改以更好地适应所谓的“存储套件流程”吗? 可能使用RxJS,例如:

const observable = RNIap.buyProduct('com.example.coins100')
                        .subscribe(
                            purchase => console.log(purchase), // successful payment
                            err => console.log(err) // err.code and err.message are available
                        )

还是可以更好地隐藏iOS的其他订阅的其他内容?

@Edgpaez太好了,但这将改变在android完成的购买行为。 我希望我可以调查version 3在此模块中的2019

您好@hyochan ,AFAICT,我们不需要更改程序包的内部行为,只需更改面向公众的界面即可。 我们可以保持buyItemByType方法解析诺言,并在index.js之上简单地添加一点Rx。

例如,我们将在index.js中包含以下内容:

export const buyProduct = (sku) => Platform.select({
  android: () => Observable.of(RNIapModule.buyItemByType(ANDROID_ITEM_TYPE_IAP, sku, null, 0)), // returns an observable that emits when the RNIapModule.buyItemByType promise resolves
  ios: ... // ios would do the same but taking into account the usage of addAdditionalSuccessPurchaseListenerIOS
})();

我的目标不是此特定实现,而是隐藏“存储套件流程”特定的细节。
您认为这是个好主意吗?
您对PR感兴趣吗?

@Edgpaez好的。 我现在了解细节了。 但是,我觉得添加RxJS对于实现feature有点太多,因为我认为没有它就可以解决。

另外,我觉得以下内容会有所不同。

RNIap.buyProduct('com.example.coins100')
                        .subscribe(
                            purchase => console.log(purchase), // successful payment
                            err => console.log(err) // err.code and err.message are available
                        )

如果您buyProduct以下两个项目调用

RNIap.buyProduct('com.example.coins100');
RNIap.buyProduct('com.example.coins200');

我们不能保证哪个会先完成,所以我认为我们应该以本机处理sendEventJS

我觉得实现应该看起来像

RNIap.buyProduct('com.example.coins100');
RNIap.buyProduct('com.example.coins200');

// receiving events
const subs =  RNIap.purchaseUpdateListener(purchase => {
  ...
});

请告诉我是否有错过的事情。

让我们处理#423中的更多问题

此页面是否有帮助?
0 / 5 - 0 等级