cordova-plugin-purchase icon indicating copy to clipboard operation
cordova-plugin-purchase copied to clipboard

iOS won't let me subscribe again, but works on Android

Open caleb87 opened this issue 1 year ago • 8 comments

My code works on Android, but not iOS.

On iOS, it won't pull up the window to subscribe. It did previously, but it looks like the status is owned so it won't do it again. The test subscription is expired though.

The docs (https://github.com/j3k0/cordova-plugin-purchase-documentation/blob/master/use-cases/subscription-ios.md) show to use store.order('subscription123') to place a subscription order; however, this creates an error: trying to purchase an unknown product. Right before I place the order, I use store.get('subscription123') and see it's there and says canPurchase: true.

Some issues/comments state that it should be done like this: store.get("subscription123").getOffer().order();

The getOffer method works on Android. On iOS, I'm never able to get the order screen up. Instead it seems to process the purchase all over again, but since it's an expired receipt, it won't won't load or allow me to resubscribe.

` const store = CdvPurchase.store; const ProductType = CdvPurchase.ProductType; const Platform = CdvPurchase.Platform; store.initialize([ Platform.APPLE_APPSTORE, Platform.GOOGLE_PLAY, { options: { applePay: { companyName: 'App Name', }, googlePay: { countryCode: 'US', googleMerchantName: 'App Name', },

            }
        }
    ])
    .then(() => {
        console.log('Store is ready!');
    });

if (device.platform == 'Android') {
    store.register([{
        id: 'subscription123',
        type: ProductType.PAID_SUBSCRIPTION,
        platform: Platform.GOOGLE_PLAY,
    }]);
} else {
    var productObject = {
        id: 'subscription123',
        type: ProductType.PAID_SUBSCRIPTION,
        platform: Platform.APPLE_APPSTORE,
    };
    console.log("REGISTER IS ", productObject); // shows the product type and platform values
    store.register([productObject]);
}

store.when()
    .approved(transaction => transaction.verify())
    .verified(function(receipt) {
        var receiptInfo = receipt.getNeededPlatformDataExample;
        checkReceipt(receiptInfo, function(result) {
            if (result['status'] == 'active') {
                // ACTIVE SUBSCRIPTION
                receipt.finish();
            } else {
                // NOT ACTIVE
            }

        });
    })
    .finished(transaction => console.log('Products owned: ' + transaction.products.map(p => p.id).join(',')))
    .receiptUpdated(r => updatePurchases(r))
    .productUpdated(p => updateUI(p));

function subscribe() { 
    // only using one of these, but put both in for examples i've used
    store.get("subscription123").getOffer().order().then(result => {
        // works on Android completely. on iOS, the subscribe screen wont show up even though subscription is expired
    });
    
    store.order("subscription123").then(result => {
        // trying to purchase an unknown product
    });
}

`

caleb87 avatar Jan 08 '24 19:01 caleb87

Do you get some logs in the console?

j3k0 avatar Jan 12 '24 10:01 j3k0

I had to do something like this for iOS order to work - maybe it helps:

//get IAP product
...

// get IAP offer
var IAPOffer1;
if (devicePlatform == 'iOS'){
     IAPOffer1 = IAPProduct1.getOffer('$'); // get default offer
     console.log(IAPOffer1);
} else {
    IAPOffer1 = IAPProduct1.getOffer();
}

// order IAP offer
IAPOffer1.order()
.then(error => {
   ...
}

For iOS to get the default offer: getOffer('$')

But it is more a workaround.

You will maybe have the same issue as me after reopening the app in iOS later: #1363

MarcelSchuermann avatar Jan 13 '24 11:01 MarcelSchuermann

I faced the same issue because I was filtering the .when().approve() and .when().verified() methods with my product ID as suggested here . But if you do that, you will never call verify() and finish() on you app's bundle ID. So I ended up doing this:

 CdvPurchase.store
      .when()
      .approved(async (transaction) => await transaction.verify())
      .verified(async (receipt) => await receipt.finish());

With this I can subscribe again. I don't know if this is the right way to do it, but it works, even if I notice a lot of logs (transaction finished) in Xcode with this.

I didn't publish the update yet because I'm not sure if this is the right way to do...

Edit: I've published it on TestFlight and now it doesn't seem to work anymore.

JumBay avatar Jan 20 '24 08:01 JumBay

I'm swamped with work, so I just used AlexDisler's plugin for iOS and this one for Android. I'll figure it out when I have time and report back.

Thanks for the suggestions JumBay and MarcelSchuermann

caleb87 avatar Jan 20 '24 15:01 caleb87

I think there's something wrong, cause now with the TestFlight version it works again, moreover when I try to subscribe it takes at least 5 sec before displaying the popup compare to 2 secs on v11 (tested with an old iphone 6s on iOS 15). Also sometimes I noticed a lot of logs in xcode, lots of finished transaction, maybe there's like a loop somewhere.

JumBay avatar Jan 20 '24 18:01 JumBay

@JumBay this is the right way to do. Just finish all verified transactions (eventually do what you have to do before finishing, the concept here is that you shouldn't charge the user if there was an issue with processing the purchase)...

j3k0 avatar Jan 24 '24 11:01 j3k0

Please share logs if you need help understanding what is happening. Just notice many (thousands of) apps are online using this plugin, so it is expected to work.

j3k0 avatar Jan 24 '24 11:01 j3k0

Hi @caleb87 looks like you are missing unverified. I believe you have to finish the unverified transaction if verification fails (for example subscription expires)

7h4r05 avatar Jan 24 '24 14:01 7h4r05