React-native-iap: 甚至在购买后,purchaseUpdatedListener也多次调用

创建于 2020-10-26  ·  22评论  ·  资料来源: dooboolab/react-native-iap

版本的react-native-iap

5.0.1

本机版本

0.63.3

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

iOS

预期行为

PurchaseUpdatedListener没有被多次调用

实际行为

PurchaseUpdatedListener在启动时被多次调用,有时甚至在两次调用之间

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

真实设备(测试飞行和AppStore中的iOS 14、13)

重现行为的步骤

(导航器组件)

const itemSkus = ['01', '02'];

const processNewPurchase = async (purchase) => {
  const { productId, transactionReceipt } = purchase;
  if (transactionReceipt !== undefined && transactionReceipt) {
       //backend call with fetch - validating receipt 
        if (data.ack === 'success') {
          console.log('finished');
          await finishTransaction(purchase);
      } else if (data.ack === 'failure') {
          props.setProcessing(false);
          console.log('error');
      }
    }
};


const getProductsIAP = useCallback(async () => {
  await clearProductsIOS();
  await clearTransactionIOS();

 try {
   const result = await initConnection();
   const products = await getProducts(itemSkus);
   props.setProducts(products);
   console.log('result', result);
 } catch (err) {
   console.warn(err.code, err.message);
 }

  purchaseUpdateSubscription = purchaseUpdatedListener(
    async (purchase) => {
      const receipt = purchase.transactionReceipt;
      console.log('purchaseUpdatedListener');
      if (receipt) {
        try {
          await processNewPurchase(purchase);
        } catch (ackErr) {
           console.log('ackErr', ackErr);
        }
      } else {
        console.log('purchaseUpdatedListener error: receipt');
      }
    },
  );

  purchaseErrorSubscription = purchaseErrorListener(
    (error: PurchaseError) => {
      console.log('purchaseErrorListener', error);
      console.log(JSON.stringify(error));
    },
  );

  setLoading(false);
}, []);


useEffect(() => {
  getProductsIAP();

  return () => {
    if (purchaseUpdateSubscription) {
      purchaseUpdateSubscription.remove();
      purchaseUpdateSubscription = null;
    }
    if (purchaseErrorSubscription) {
      purchaseErrorSubscription.remove();
      purchaseErrorSubscription = null;
    }
  };
}, []);

📱 iOS 🙏 help wanted

最有用的评论

还是同样的问题。 看来purchaseUpdatedListener已损坏。 请尽快修复此问题。 找不到解决方案。

所有22条评论

活动会触发相同的购买结果吗?

是的,它以成功的结果/收据触发。 如果没有当前收据,它也会触发,但在验证服务器上失败。

您能否检查一下是否重新渲染了组件? 当组件重新呈现并且侦听器偶尔启动几次时,会出现很多问题。 好吧,这应该放任自流,但是我们需要重提您的案子。

好吧,这是“ NavigatorContainer”,表示我正在设置不同的状态,更新内容等。 但仅渲染一个,然后“渲染”以更新不同的状态,道具...

但这就是为了-退订听众/避免这种情况。

useEffect(() => {
  getProductsIAP();

  return () => {
    if (purchaseUpdateSubscription) {
      purchaseUpdateSubscription.remove();
      purchaseUpdateSubscription = null;
    }
    if (purchaseErrorSubscription) {
      purchaseErrorSubscription.remove();
      purchaseErrorSubscription = null;
    }
  };
}, []);

好吧,这是“ NavigatorContainer”,表示我正在设置不同的状态,更新内容等。 但是只渲染一个然后“渲染”以更新不同的状态,道具...

但这就是为了-退订听众/避免这种情况。

useEffect(() => {
  getProductsIAP();

  return () => {
    if (purchaseUpdateSubscription) {
      purchaseUpdateSubscription.remove();
      purchaseUpdateSubscription = null;
    }
    if (purchaseErrorSubscription) {
      purchaseErrorSubscription.remove();
      purchaseErrorSubscription = null;
    }
  };
}, []);

是的,我也提到了这一点。 刚刚分享了我记得的上一个问题。 我们需要繁殖。

同样,清除事务或尝试使用其他testflight帐户也可能会有所帮助。

const getProductsIAP = useCallback(async () => {
  await clearProductsIOS();
  await clearTransactionIOS();

.....

在TestFlight,生产和其他设备中进行了测试。

不同的帐户?

是的,结果相同。

奇怪的。 您还可以在我们的IapExample项目中尝试代码段吗?

我有以下行为。

1)用户购买IAP。
2)purchaseUpdatedListener被调用。
3)用户卸载应用程序。
4)用户返回到应用程序。
5)purchaseUpdatedListener被触发并进入循环。

我正在使用类,但看不到任何重新渲染。

我在“ react-native-iap”:“ 4.4.1”和“ react-native”:“ 0.63.3”。

我曾尝试升级到5.0.0,但是我却得到了相同的行为。

我有以下行为。

  1. 用户购买IAP。
  2. PurchaseUpdatedListener被调用。
  3. 用户卸载应用程序。
  4. 用户返回到应用程序。
  5. PurchaseUpdatedListener触发并形成循环。

我正在使用类,但是看不到任何重复。

我处于“ react-native-iap”:“ 4.4.1”和“ react-native”:“ 0.63.3”。

我尝试更新到5.0.0,但是得到了相同的行为。

你好一个问题。 您找到解决方案了吗?

还是同样的问题。 看来purchaseUpdatedListener已损坏。 请尽快修复此问题。 找不到解决方案。

有与此相同的问题。 几个月不固定怎么可能? 这不是关键问题,还是有人找到了解决方法? 同样,如果有帮助,我想我只是将设备从iOS 13升级到iOS 14时才遇到此问题。据我所知,它在iOS 13上运行正常,但我可能会误会。

同样的问题在这里。
我注意到,每次我保存代码并热加载应用程序时,都会发生这种情况。
在这种情况下,将根组件卸载,然后重新安装。

这是我的useIap()钩子

const useIap=()=>{

const purchaseUpdateSubscription = useRef<EmitterSubscription[]>([]);
    const purchaseErrorSubscription = useRef<EmitterSubscription[]>([]);

const init = useCallback(async () => {
        console.taggedLog(logTag, 'call iap init');

        await RNIap.initConnection();

        await RNIap.flushFailedPurchasesCachedAsPendingAndroid();

        purchaseUpdateSubscription.current.push(RNIap.purchaseUpdatedListener(async purchase => {
            console.taggedLog(logTag, 'purchaseUpdatedListener', purchase);

            try {
                await finalizePurchase(purchase);
            } catch (err) {
                handleFailedPurchase();
            }
        }));

        // use array to be sure to not accidentally overwrite subscriptions and lose access to them.
        // being an array I can always iterate and call `remove` on them
        purchaseErrorSubscription.current.push(RNIap.purchaseErrorListener(error => {
            handleFailedPurchase(error);
        }));

        updateProducts();
        return clear;
    }, []);

  const clear = useCallback(() => {
        console.taggedLog(logTag, 'clearing all');
        clearPurchaseEventListeners();
    }, [clearPurchaseEventListeners]);


 const clearPurchaseEventListeners = useCallback(() => {
        console.taggedLog(logTag, 'clearing purchase event listener', purchaseUpdateSubscription.current.length, purchaseErrorSubscription.current.length);
        purchaseUpdateSubscription.current.forEach(sub => sub.remove());
        purchaseErrorSubscription.current.forEach(sub => sub.remove());
        purchaseUpdateSubscription.current = [];
        purchaseErrorSubscription.current = [];
    }, []);

return {init,clear}
}

然后我在根组件中使用此代码

const iap=useIap();
 useEffect(() => {
        console.log("root component mounted");
        iap.init();

        return () => {
            console.log("root component unmounted");
            iap.clear();
        };
    }, []);

根组件可能碰巧被卸载并重新安装,但是调用了clear方法,并且我还看到了日志“清除购买事件监听器”,1,1,这意味着它将清除它们。

即使在这种情况下,采购文件purchaseUpdatedListener仍然被多次调用,例如

有什么办法吗?

有同样的问题。
它甚至在不同的屏幕中调用。
有任何更新吗?

对我来说也是一样。 下一次初始化时,它将调用过去的收据。

我遇到了同样的问题,我意识到发生了同样的事情,因为我没有正确地组装和拆卸组件,从而使多个监听器同时打开。

componentWillUnmount() { if (this.purchaseUpdateSubscription) { this.purchaseUpdateSubscription.remove(); this.purchaseUpdateSubscription = null; } }
每次购买和拆卸组件时,都必须在组装组件时删除侦听器/订阅并添加新组件。
在Android上不会发生此错误,为什么? 我不知道,但是因为它可以在Android上运行,所以会让您认为错误出在iOS而非代码中。

一个可能的解决方法,测试我注意到它有时会显示过去的收据(发送给服务器),所以我要做的就是立即存储收到的每个通知的transactionId,因此,您始终首先检查数据库是否已处理该transactionId,是否因此,如果没有,则忽略(重复),然后继续。 如果通知首先到达应用程序(而不是服务器),则可以放置一些逻辑来控制此操作,即,在单击某个按钮等之后,您应该只收到1。
经过广泛的测试后,它停止了复制,过了一会儿。

是的,有一些粗略的解决方法,但是它们都很漂亮....
请解决此问题。 自2020年10月以来,这绝对是一个至关重要的重大项目错误。

只有一种解决方案,可以使用:Revenuecat;)

有什么办法吗?

收入猫

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