React-native-iap: تم استدعاء buyUpdatedListener عدة مرات حتى بعد الشراء

تم إنشاؤها على ٢٦ أكتوبر ٢٠٢٠  ·  22تعليقات  ·  مصدر: dooboolab/react-native-iap

نسخة من رد فعل - أصلية - IAP

5.0.1

نسخة من رد الفعل الأصلي

0.63.3

المنصات التي واجهت الخطأ فيها (IOS أو Android أو كليهما؟)

IOS

سلوك متوقع

لا يتم استدعاء buyUpdatedListener عدة مرات

السلوك الفعلي

PurchaseUpdatedListener يتم استدعاؤه عند بدء التشغيل عدة مرات ، وأحيانًا ما بينهما

بيئة اختبار (محاكي؟ جهاز حقيقي؟)

جهاز حقيقي (iOS 14 و 13 في Test Flight وفي 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

التعليق الأكثر فائدة

لا تزال نفس المشكلة. يبدو أن عملية الشراءUpdatedListener معطلة. الرجاء إصلاح هذا في أسرع وقت ممكن. لم يتم العثور على حل.

ال 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 ويدخل في حلقة.

أنا أستخدم الفصول ، لكني لا أرى أي إعادة تصيير.

أنا على "رد فعل - أصلي - iap": "4.4.1" و "رد فعل أصلي": "0.63.3".

لقد حاولت الترقية إلى 5.0.0 ، لكني أحصل على نفس السلوك.

لدي السلوك التالي.

  1. يشتري المستخدم IAP.
  2. يسمى PurchaseUpdatedListener.
  3. يقوم المستخدم بإلغاء تثبيت التطبيق.
  4. يعود المستخدم إلى التطبيق.
  5. buyUpdatedListener يطلق ويشكل حلقة.

أنا أستخدم الفصول الدراسية ، لكني لا أرى أي تكرار.

أنا في "رد فعل - أصلي - iap": "4.4.1" و "رد فعل أصلي": "0.63.3".

حاولت التحديث إلى 5.0.0 ، لكنني أحصل على نفس السلوك.

مرحبا سؤال واحد. هل وجدت الحل لهذا؟

لا تزال نفس المشكلة. يبدو أن عملية الشراءUpdatedListener معطلة. الرجاء إصلاح هذا في أسرع وقت ممكن. لم يتم العثور على حل.

وجود نفس المشكلة مع هذا. كيف يعقل أنه لم يتم إصلاحه لأشهر؟ أليست هذه مشكلة حرجة أم هل وجد شخص ما حلاً لها؟ إذا كان ذلك مفيدًا أيضًا ، أعتقد أنني واجهت هذه المشكلة فقط عندما قمت بترقية جهازي من 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 عدة مرات ، es

اي حل؟

لديك نفس المشكلة.
حتى أنها استدعت في شاشات مختلفة.
أي تحديثات على هذا؟

نفس المشكلة بالنسبة لي. يستدعي الإيصالات السابقة عندما تتم تهيئة iap في المرة التالية.

واجهت نفس المشكلة وأدركت أن الأمر نفسه يحدث لأنني لم أكن أقوم بتجميع وتفكيك المكون بشكل صحيح ، مما جعل العديد من المستمعين مفتوحين في نفس الوقت.

componentWillUnmount() { if (this.purchaseUpdateSubscription) { this.purchaseUpdateSubscription.remove(); this.purchaseUpdateSubscription = null; } }
في كل مرة يتم فيها إجراء عملية شراء ويتم تفكيك المكون ، من الضروري إزالة المستمع / الاشتراك وإضافة عنصر جديد عند تجميع المكون.
هذا الخطأ لا يحدث على android ، لماذا؟ لا أعرف ، ولكن نظرًا لأنه يعمل على نظام Android ، فإنه يجعلك تعتقد أن الخطأ موجود في نظام التشغيل iOS وليس في الكود.

حل بديل محتمل ، وهو الاختبار ، لاحظت أنه يعرض أحيانًا الإيصالات السابقة (المرسلة إلى الخادم) ، لذا فإن ما فعلته هو تخزين معرّف المعاملة على الفور لكل إشعار تم استلامه ، لذلك عليك دائمًا التحقق من قاعدة البيانات أولاً لمعرفة ما إذا تمت معالجة هذه المعاملة وما إذا لذا تجاهل (إنها نسخة مكررة) إذا لم يكن الأمر كذلك ، فيمكنك المتابعة. إذا كان الإشعار يأتي أولاً إلى التطبيق (بدلاً من الخادم) ، فيمكنك وضع بعض المنطق للتحكم في ذلك ، أي يجب أن تتلقى 1 فقط بعد النقر فوق زر معين وما إلى ذلك.
بعد الاختبار على نطاق واسع ، توقف عن التكرار بعد فترة ، حدث شيء ما هناك.

نعم ، هناك بعض الحلول البسيطة ، لكنها كلها جميلة ....
يرجى فقط إصلاح هذه المشكلة. هذا بالتأكيد خطأ حرج وخطأ في المشروع منذ أكتوبر 2020 ...

لا يوجد سوى حل واحد ، وهو استخدام : Revenuecat ؛)

اي حل؟

Revenuecat

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات