React-native-iap: purchaseUpdatedListener dipanggil beberapa kali bahkan setelah pembelian

Dibuat pada 26 Okt 2020  ·  22Komentar  ·  Sumber: dooboolab/react-native-iap

Versi react-native-IAP

5.0.1

Versi react-native

0.63.3

Platform yang Anda hadapi kesalahan (IOS atau Android atau keduanya?)

IOS

Perilaku yang diharapkan

purchaseUpdatedListener tidak dipanggil beberapa kali

Perilaku sebenarnya

purchaseUpdatedListener dipanggil saat startup beberapa kali, terkadang bahkan di antaranya

Lingkungan yang diuji (Emulator? Perangkat Nyata?)

Perangkat nyata (iOS 14, 13 di Test Flight dan di AppStore)

Langkah-langkah untuk mereproduksi perilaku

(Komponen Navigator)

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

Komentar yang paling membantu

Masih masalah yang sama. Sepertinya purchaseUpdatedListener itu rusak. Harap perbaiki ini secepatnya. Solusi tidak ditemukan.

Semua 22 komentar

Apakah peristiwa tersebut memicu hasil pembelian yang sama?

Ya, ini dijalankan dengan hasil / penerimaan yang berhasil. Jika tidak ada tanda terima saat ini, itu juga diaktifkan, tetapi gagal di server validasi.

Bisakah Anda memeriksa apakah komponen Anda tidak dirender? Ada banyak masalah ketika komponen dirender dan pendengar kadang-kadang memulai beberapa kali. Itu harus dirilis dengan sulit, tetapi kami perlu mereproduksi kasus Anda.

Nah, ini adalah "NavigatorContainer" yang berarti saya menyetel status yang berbeda, memperbarui berbagai hal, dan sebagainya. Tapi hanya merender satu dan kemudian "merender" untuk pembaruan berbagai status, alat peraga ...

Tapi itulah gunanya - berhenti berlangganan pendengar / untuk menghindari ini.

useEffect(() => {
  getProductsIAP();

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

Nah, ini adalah "NavigatorContainer" yang berarti saya menyetel status yang berbeda, memperbarui berbagai hal, dan sebagainya. Tetapi hanya merender satu dan kemudian "merender" untuk pembaruan berbagai status, alat peraga ...

Tapi itulah gunanya - berhenti berlangganan pendengar / untuk menghindari ini.

useEffect(() => {
  getProductsIAP();

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

Ya, saya juga telah menyebutkan ini. Baru saja membagikan masalah sebelumnya yang saya ingat. Kami membutuhkan reproduksi.

Selain itu, menyelesaikan transaksi atau mencoba dengan akun testflight yang berbeda mungkin membantu.

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

.....

Diuji di TestFlight, produksi, dan perangkat yang berbeda.

Akun berbeda?

Ya, hasilnya sama.

Aneh. Bisakah Anda juga mencoba cuplikan kode dalam proyek IapExample ?

Saya memiliki perilaku berikut.

1) Pengguna membeli IAP.
2) purchaseUpdatedListener dipanggil.
3) Pengguna mencopot pemasangan aplikasi.
4) Pengguna kembali ke aplikasi.
5) purchaseUpdatedListener dipicu dan berputar-putar.

Saya menggunakan kelas, tetapi saya tidak melihat render ulang apa pun.

Saya menggunakan "react-native-iap": "4.4.1" dan "react-native": "0.63.3".

Saya telah mencoba meningkatkan ke 5.0.0, tetapi saya mendapatkan perilaku yang sama.

Saya memiliki perilaku berikut.

  1. Pengguna membeli IAP.
  2. PurchaseUpdatedListener dipanggil.
  3. Pengguna mencopot pemasangan aplikasi.
  4. Pengguna kembali ke aplikasi.
  5. purchaseUpdatedListener mengaktifkan dan membentuk loop.

Saya menggunakan kelas, tapi saya tidak melihat ada pengulangan.

Saya berada di "react-native-iap": "4.4.1" dan "react-native": "0.63.3".

Saya mencoba memperbarui ke 5.0.0, tetapi saya mendapatkan perilaku yang sama.

Halo satu pertanyaan. apakah Anda menemukan solusi untuk ini?

Masih masalah yang sama. Sepertinya purchaseUpdatedListener itu rusak. Harap perbaiki ini secepatnya. Solusi tidak ditemukan.

Memiliki masalah yang sama dengan ini. Bagaimana mungkin itu tidak diperbaiki selama berbulan-bulan? Apakah ini bukan masalah kritis atau apakah seseorang telah menemukan solusi untuk ini? Juga jika itu membantu, saya pikir saya hanya mengalami masalah ini ketika saya memutakhirkan perangkat saya dari iOS 13 ke iOS 14. Sejauh yang saya ingat itu berfungsi dengan baik di iOS 13 tetapi saya bisa salah.

Masalah yang sama di sini.
Saya perhatikan bahwa itu terjadi setiap kali saya menyimpan kode dan aplikasi dalam keadaan panas dimuat ulang.
Dalam skenario ini komponen root dilepas, dan kemudian dipasang kembali.

Ini adalah hook 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}
}

Dan kemudian saya menggunakan kode ini di komponen root

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

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

Komponen root bisa saja dilepas dan dipasang kembali, meskipun metode clear dipanggil, dan saya juga melihat log 'clearing purchase event listener', 1,1, yang berarti akan menghapusnya.

Bahkan dalam situasi ini, pembelian purchaseUpdatedListener masih dipanggil berkali-kali, es

ada solusi?

Memiliki masalah yang sama.
Bahkan disebut di layar yang berbeda.
Ada pembaruan tentang ini?

Masalah yang sama untuk saya. Ini memanggil tanda terima yang lalu ketika IAP diinisialisasi di lain waktu.

Saya memiliki masalah yang sama dan saya menyadari bahwa hal yang sama terjadi karena saya tidak merakit dan membongkar komponen dengan benar, sehingga membuat beberapa pendengar terbuka pada saat yang bersamaan.

componentWillUnmount() { if (this.purchaseUpdateSubscription) { this.purchaseUpdateSubscription.remove(); this.purchaseUpdateSubscription = null; } }
Setiap kali pembelian dilakukan dan komponen dibongkar, pendengar / langganan harus dihapus dan menambahkan yang baru saat merakit komponen.
Error ini tidak terjadi di android, kenapa? Saya tidak tahu, tetapi karena ini berfungsi di Android, itu membuat Anda berpikir bahwa kesalahan ada di iOS dan bukan di kodenya.

Solusi yang mungkin, pengujian saya perhatikan bahwa kadang-kadang menunjukkan tanda terima yang lalu (dikirim ke server) jadi yang saya lakukan adalah segera menyimpan transactionId dari setiap pemberitahuan yang diterima, jadi Anda selalu memeriksa database terlebih dahulu apakah transactionId ini telah diproses dan jika jadi abaikan (ini duplikat) jika tidak maka Anda dapat melanjutkan. Jika pemberitahuan datang lebih dulu ke Aplikasi (bukan server) maka Anda dapat meletakkan beberapa logika untuk mengontrol ini yaitu Anda hanya menerima 1 setelah tombol tertentu diklik, dll.
Setelah pengujian secara ekstensif itu berhenti menduplikasi setelah beberapa saat, sesuatu terjadi di sana.

Ya, ada beberapa solusi yang samar-samar, tetapi semuanya cantik ....
Harap perbaiki masalah ini. Ini jelas merupakan bug kritis dan proyek melanggar sejak Oktober 2020 ....

Hanya ada satu solusi, adalah menggunakan : Revenuecat;)

ada solusi?

Revenuecat

Apakah halaman ini membantu?
0 / 5 - 0 peringkat