React-native-iap: buyUpdatedListener вызывается несколько раз даже после покупки

Созданный на 26 окт. 2020  ·  22Комментарии  ·  Источник: dooboolab/react-native-iap

Версия react-native-iap

5.0.1

Версия react-native

0,63,3

Платформы, на которых вы столкнулись с ошибкой (IOS или Android или оба?)

IOS

Ожидаемое поведение

buyUpdatedListener не вызывается несколько раз

Фактическое поведение

buyUpdatedListener вызывается при запуске несколько раз, иногда даже в промежутках

Протестированная среда (Эмулятор? Настоящее устройство?)

Реальное устройство (iOS 14, 13 в тестовом полете и в AppStore)

Шаги по воспроизведению поведения

(Компонент навигатора)

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) вызывается buyUpdatedListener.
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 по-прежнему вызывается много раз, т.е.

любое решение?

Есть такая же проблема.
Он даже звонил на разные экраны.
Есть обновления по этому поводу?

То же самое для меня. Он вызывает прошлые квитанции, когда в следующий раз инициализируется iap.

У меня была та же проблема, и я понял, что происходит то же самое, потому что я неправильно собирал и дизассемблировал компонент, в результате чего открывались несколько слушателей одновременно.

componentWillUnmount() { if (this.purchaseUpdateSubscription) { this.purchaseUpdateSubscription.remove(); this.purchaseUpdateSubscription = null; } }
Каждый раз, когда совершается покупка и компонент разбирается, необходимо удалить слушатель / подписку и добавить новый при сборке компонента.
Эта ошибка не возникает на android, почему? Я не знаю, но поскольку он работает на Android, вы думаете, что ошибка в iOS, а не в коде.

Возможный обходной путь, тестирование. Я заметил, что иногда он показывает прошлые квитанции (отправленные на сервер), поэтому я немедленно сохраняю идентификатор транзакции каждого полученного уведомления, поэтому вы всегда сначала проверяете базу данных, чтобы узнать, был ли обработан этот идентификатор транзакции, и если так что проигнорируйте (это дубликат), если нет, то можете продолжить. Если уведомление сначала поступает в приложение (а не на сервер), вы можете ввести некоторую логику для управления этим, т.е. вы должны получить только 1 после нажатия определенной кнопки и т. Д.
После всестороннего тестирования он через некоторое время перестал дублироваться, там что-то происходит.

Да, есть несколько схематичных обходных путей, но все они хороши ...
Пожалуйста, исправьте эту проблему. Это определенно критическая и критическая ошибка с октября 2020 года ....

Есть только одно решение - использовать : Revenuecat;)

любое решение?

Revenuecat

Была ли эта страница полезной?
0 / 5 - 0 рейтинги