j3k0 / cordova-plugin-purchase

In-App Purchase for Cordova on iOS, Android and Windows
https://purchase.cordova.fovea.cc
1.29k stars 530 forks source link

validProducts.find is not a function #1434

Open astrocreep opened 11 months ago

astrocreep commented 11 months ago

We updated one of our apps to use this plugin (V13). It's now live for a while.

Observed behavior

We are seeing a crash in our logs that is strange. Here is the complete stack trace:

Error: TypeError: validProducts.find is not a function
    at http://localhost/:9909:64
    at Array.map (<anonymous>)
    at iabLoaded (http://localhost/:9908:46)
    at Object.callbackFromNative (http://localhost/:1708:52)
    at <anonymous>:1:9

This happens instantly after the products are loaded. The strange thing is, that validProducts is the string 'OK'. Plugin output is: [CdvPurchase.GooglePlay] DEBUG: Loaded: "OK"

Expected behavior

No crash. Maybe check if this is really an array?

System Info

The app is using Capacitor. The problem is happening mostly on Huawei and Xiaomi devices (with one Samsung in the mix...). Countries are mixed completely. So I think this has something to do with these devices not having Google Support any longer and people just installed the Playstore manually?

Countries: PL, BG, GR, FR, UK, CZ, DE, BR, US, ES

Devices: Huawei P Smart 2019(Android 10) Huawei Y5 Prime 2018 (Android 8.1) Redmi 9 (Android 10) Huawei MediaPad T5 (Android 8) Xiaomi Redmi 9T (Android 11) Xiaomi Redmi Note 9 (Android 10) Xiaomi Redmi Note 11 (Android 11) Redmi Note 9T (Android 10) Redmi 9A (Android 11) Huawei Honor 10 Lite (Android 10) Redmi Note 8T (Android 11) Huawei P30 Lite (Android 10) Huawei Y5 Prime (Android 8.1) Huawei Y7 (Android 8.1.0) Samsung Galaxy A53 (Android 13) Xiaomi Poco X4 GT (Android 13) Xiaomi Redmi Note 12 (Android 13) Xiaomi Redmi Note 10 Pro (Android 11) Redmi Note 8 Pro (Android 10) Redmi 9A (Android 10) Xiaomi Redmi A1 (Android 12) There are more, but at the top of the list are the most common ones

becvert commented 11 months ago

Same error

TypeError: validProducts.find is not a function at https://localhost/plugins/cordova-plugin-purchase/www/store.js:4450:64 at Array.map () at iabLoaded (https://localhost/plugins/cordova-plugin-purchase/www/store.js:4449:46) at Object.callbackFromNative (https://localhost/cordova.js:295:58) at :1:9

Xiaomi Redmi A1 (220733SG) (Android 12)

oren-oro commented 9 months ago

I have the same error. Release 13.6.0 Additional info: It appears that on some devices, sometimes the call for getAvailableProducts returns the string "OK" instead of the expected array, thus we get the error validProducts.find is not a function. This is a fatal error. I think the problem is that the mCallbackContext is stored on the PurchasePlugin class, thus, if after calling the getAvailableProducts method, we get the callSuccess() of a previous request which returns the status "OK", it will answer the getAvailableProducts with the status string "OK" which leads to this exception. I think that at least we should overcome this problem by checking the validProducts in the response on the getAvailableProducts before using it. If it isn't an array, just retry the getAvailableProducts function instead of using it.

Here is the workarround for this problem in the store.js loadProducts function:

        loadProducts(products) {
            return new Promise((resolve) => {
                this.log.debug("Load: " + JSON.stringify(products));
                /** Called when a list of product definitions have been loaded */
                const errHandler = (err) => {
                    // failed to load products, retry later.
                    this.retry.retry(go);
                    this.context.error(CdvPurchase.storeError(CdvPurchase.ErrorCode.LOAD, 'Loading product info failed - ' + err + ' - retrying later...'));
                }

                const iabLoaded = (validProducts) => {
                    this.log.debug("Loaded: " + JSON.stringify(validProducts));
                    if (!(validProducts instanceof Array)) {
                        errHandler('Wrong response type! validProducts=' + JSON.stringify(validProducts))
                        return
                    }

                    const ret = products.map(registeredProduct => {
                        const validProduct = validProducts.find(vp => vp.productId === registeredProduct.id);
                        if (validProduct && validProduct.productId) {
                            return this._products.addProduct(registeredProduct, validProduct);
                        }
                        else {
                            return CdvPurchase.storeError(CdvPurchase.ErrorCode.INVALID_PRODUCT_ID, `Product with id ${registeredProduct.id} not found.`);
                        }
                    });
                    resolve(ret);
                };
                /** Start loading products */
                const go = () => {
                    const { inAppSkus, subsSkus } = this.getSkusOf(products);
                    this.log.debug("getAvailableProducts: " + JSON.stringify(inAppSkus) + " | " + JSON.stringify(subsSkus));
                    this.bridge.getAvailableProducts(inAppSkus, subsSkus, iabLoaded, errHandler);
                };
                go();
            });
        }
oduverne commented 7 months ago

Hello, Same problem here with 13.8.6. It happens only on Android for me.

GlukhovaJulia commented 5 months ago

Hi! I have the same problem. validProducts.find is not a function cordova-plugin-purchase 13.10.0

const iabLoaded = (validProducts) => { this.log.debug("Loaded: " + JSON.stringify(validProducts)); const ret = products.map(registeredProduct => { const validProduct = validProducts.find(vp => vp.productId === registeredProduct.id);

The last log I got - [CdvPurchase.GooglePlay] DEBUG: Loaded: "OK"