j3k0 / cordova-plugin-purchase

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

[IOS] iOS Subscription Groups #1221

Open nippilaus opened 3 years ago

nippilaus commented 3 years ago

system info

 "@angular/core": "11.2.14",
"@capacitor/app": "1.0.1",
"cordova-plugin-purchase": "10.6.0",
"@ionic-native/in-app-purchase-2": "5.34.0",
...
Device: iPhone iOS 14.6
...

Expected behavior

I am developing an Ionic app with capacitor 3.

Created a subscription group two service levels with two subscriptions each. Level 1 (=Pro), Level 2 (=Basic). On each level I have an auto-renewing subscription with 6 and 12 month.

Bildschirmfoto 2021-07-26 um 13 36 14

I expect that I can only own one subscription from the whole group at all and that I am asked for an upgrade or downgrade when switching between service levels.

I think the plugin supports subscription groups on iOS (on Android it definitely does since my code work there).

Observed behavior

I can buy and own all four subscription in a sandbox. No message about upgrades or downgrades. Same setup on Android works.

Sidenode: I am in a sandbox and I have a sandbox user to buy the subscriptions. When I go on my iPhone under Settings->App Store->Sanbox User->Manage there is always only one checkmark while my code in parallel tells me that I own all four subscriptions like e.g. here shown for the two 6-month subscriptions:

[{"id":"pro_6_month","alias":"pro_6_month","type":"paid subscription","group":"20840123","state":"owned","title":"Pro","description":"Das Pro-Abonnement für 6 Monate","priceMicros":7990000,"price":"7,99 €","currency":"EUR","countryCode":"DE","loaded":true,"canPurchase":false,"owned":true,"introPrice":null,"introPriceMicros":null,"introPricePeriod":null,"introPricePeriodUnit":null,"introPricePaymentMode":null,"ineligibleForIntroPrice":null,"discounts":[],"downloading":false,"downloaded":false,"additionalData":null,"transaction":{"type":"ios-appstore","id":"1000000848151315","appStoreReceipt":"MIIdNAYJKoZIhvcNAQcCoIIdJTCCHSECAQExCzAJBgUrDgMCGgUAMIIM1QYJKoZIhvcNAQcBoIIMxgSCDMIxggy+MAoCAQgCAQEEAhYAMAoCARQCAQEEAgwAMAsCAQECAQEEAwIBADALAgELAgEBBAMCAQAwCwIBDwIBAQQDAgEAMAsCARACAQEEAwIBADALAgEZAgEBBAMCAQMwDAIBAwIBAQQEDAIyMjAMAgEKAgEBBAQWAjQrMAwCAQ4CAQEEBAICAOEwDQIBDQIBAQQFAgMCJTgwDQIBEwIBAQQFDAMxLjAwDgIBCQIBAQQGAgRQMjU2MBgCAQQCAQIEEEQ5Hb83VcahjZgvtEFO+tkwGQIBAgIBAQQRDA9kZS50cmFjZml0LmJldGEwGwIBAAIBAQQTDBFQcm9kdWN0aW9uU2FuZGJveDAcAgEFAgEBBBQVz9qLGCZ1dYiqd5T3NAa7l+l1xTAeAgEMAgEBBBYWFDIwMjEtMDctMjZUMTE6Mzc6MThaMB4CARICAQEEFhYUMjAxMy0wOC0wMVQwNzowMDowMFowQwIBBgIBAQQ7R+FaiqP7FAAEOfWUkU51JcUqFrB8x2bNVFcLiqQ4XzRakKDxe1iloq+DD860PadQFgm7zjKX8kYNAxkwRAIBBwIBAQQ8+nvwpuZi3nTe/CP/qUg2nyXQlqAEAb9ic06Wo9e40XFosAGLiKKFYBzlGQ3NY98RkFajXwyYrZVGhStlMIIBhgIBEQIBAQSCAXwxggF4MAsCAgatAgEBBAIMADALAgIGsAIBAQQCFgAwCwICBrICAQEEAgwAMAsCAgazAgEBBAIMADALAgIGtAIBAQQCDAAwCwICBrUCAQEEAgwAMAsCAga2AgEBBAIMADAMAgIGpQIBAQQDAgEBMAwCAgarAgEBBAMCAQMwDAICBq4CAQEEAwIBADAMAgIGsQIBAQQDAgEAMAwCAga3AgEBBAMCAQAwDAICBroCAQEEAwIBADASAgIGrwIBAQQJAgcDjX6onJGJMBYCAgamAgEBBA0MC3Byb182X21vbnRoMBsCAganAgEBBBIMEDEwMDAwMDA4NDY2MjE5MDMwGwICBqkCAQEEEgwQMTAwMDAwMDg0NjYyMTI1ODAfAgIGqAIBAQQWFhQyMDIxLTA3LTIyVDE1OjU4OjQyWjAfAgIGqgIBAQQWFhQyMDIxLTA3LTIyVDE1OjU2OjQ0WjAfAgIGrAIBAQQWFhQyMDIxLTA3LTIyVDE2OjI4OjQyWjCCAYgCARECAQEEggF+MYIBejALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEDMAwCAgauAgEBBAMCAQAwDAICBrECAQEEAwIBADAMAgIGtwIBAQQDAgEAMAwCAga6AgEBBAMCAQAwEgICBq8CAQEECQIHA41+qJyRiDAYAgIGpgIBAQQPDA1iYXNpY182X21vbnRoMBsCAganAgEBBBIMEDEwMDAwMDA4NDY2MjEyNTgwGwICBqkCAQEEEgwQMTAwMDAwMDg0NjYyMTI1ODAfAgIGqAIBAQQWFhQyMDIxLTA3LTIyVDE1OjU2OjQzWjAfAgIGqgIBAQQWFhQyMDIxLTA3LTIyVDE1OjU2OjQ0WjAfAgIGrAIBAQQWFhQyMDIxLTA3LTIyVDE2OjI2OjQzWjCCAYgCARECAQEEggF+MYIBejALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEDMAwCAgauAgEBBAMCAQAwDAICBrECAQEEAwIBADAMAgIGtwIBAQQDAgEAMAwCAga6AgEBBAMCAQAwEgICBq8CAQEECQIHA41+qJyRyzAYAgIGpgIBAQQPDA1iYXNpY182X21vbnRoMBsCAganAgEBBBIMEDEwMDAwMDA4NDY2MzE5ODMwGwICBqkCAQEEEgwQMTAwMDAwMDg0NjYyMTI1ODAfAgIGqAIBAQQWFhQyMDIxLTA3LTIyVDE2OjI4OjQyWjAfAgIGqgIBAQQWFhQyMDIxLTA3LTIyVDE1OjU2OjQ0WjAfAgIGrAIBAQQWFhQyMDIxLTA3LTIyVDE2OjU4OjQyWjCCAYgCARECAQEEggF+MYIBejALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEDMAwCAgauAgEBBAMCAQAwDAICBrECAQEEAwIBADAMAgIGtwIBAQQDAgEAMAwCAga6AgEBBAMCAQAwEgICBq8CAQEECQIHA41+qJyU6zAYAgIGpgIBAQQPDA1iYXNpY182X21vbnRoMBsCAganAgEBBBIMEDEwMDAwMDA4NDY2NDQ4MjgwGwICBqkCAQEEEgwQMTAwMDAwMDg0NjYyMTI1ODAfAgIGqAIBAQQWFhQyMDIxLTA3LTIyVDE2OjU4OjQyWjAfAgIGqgIBAQQWFhQyMDIxLTA3LTIyVDE1OjU2OjQ0WjAfAgIGrAIBAQQWFhQyMDIxLTA3LTIyVDE3OjI4OjQyWjCCAYgCARECAQEEggF+MYIBejALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEDMAwCAgauAgEBBAMCAQAwDAICBrECAQEEAwIBADAMAgIGtwIBAQQDAgEAMAwCAga6AgEBBAMCAQAwEgICBq8CAQEECQIHA41+qJyXpjAYAgIGpgIBAQQPDA1iYXNpY182X21vbnRoMBsCAganAgEBBBIMEDEwMDAwMDA4NDY2NTY1MDMwGwICBqkCAQEEEgwQMTAwMDAwMDg0NjYyMTI1ODAfAgIGqAIBAQQWFhQyMDIxLTA3LTIyVDE3OjI4OjQyWjAfAgIGqgIBAQQWFhQyMDIxLTA3LTIyVDE1OjU2OjQ0WjAfAgIGrAIBAQQWFhQyMDIxLTA3LTIyVDE3OjU4OjQyWjCCAYgCARECAQEEggF+MYIBejALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEDMAwCAgauAgEBBAMCAQAwDAICBrECAQEEAwIBADAMAgIGtwIBAQQDAgEAMAwCAga6AgEBBAMCAQAwEgICBq8CAQEECQIHA41+qJyaUTAYAgIGpgIBAQQPDA1iYXNpY182X21vbnRoMBsCAganAgEBBBIMEDEwMDAwMDA4NDY2Njg4MTcwGwICBqkCAQEEEgwQMTAwMDAwMDg0NjYyMTI1ODAfAgIGqAIBAQQWFhQyMDIxLTA3LTIyVDE3OjU4OjQyWjAfAgIGqgIBAQQWFhQyMDIxLTA3LTIyVDE1OjU2OjQ0WjAfAgIGrAIBAQQWFhQyMDIxLTA3LTIyVDE4OjI4OjQyWjCCAYgCARECAQEEggF+MYIBejALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEDMAwCAgauAgEBBAMCAQAwDAICBrECAQEEAwIBADAMAgIGtwIBAQQDAgEAMAwCAga6AgEBBAMCAQAwEgICBq8CAQEECQIHA41+qJydCjAYAgIGpgIBAQQPDA1iYXNpY182X21vbnRoMBsCAganAgEBBBIMEDEwMDAwMDA4NDgxNDE4NzUwGwICBqkCAQEEEgwQMTAwMDAwMDg0NjYyMTI1ODAfAgIGqAIBAQQWFhQyMDIxLTA3LTI2VDExOjI2OjA3WjAfAgIGqgIBAQQWFhQyMDIxLTA3LTIyVDE1OjU2OjQ0WjAfAgIGrAIBAQQWFhQyMDIxLTA3LTI2VDExOjU2OjA3WqCCDmUwggV8MIIEZKADAgECAggO61eH554JjTANBgkqhkiG9w0BAQUFADCBljELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkFwcGxlIEluYy4xLDAqBgNVBAsMI0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVsYXRpb25zMUQwQgYDVQQDDDtBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9ucyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNTExMTMwMjE1MDlaFw0yMzAyMDcyMTQ4NDdaMIGJMTcwNQYDVQQDDC5NYWMgQXBwIFN0b3JlIGFuZCBpVHVuZXMgU3RvcmUgUmVjZWlwdCBTaWduaW5nMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQClz4H9JaKBW9aH7SPaMxyO4iPApcQmyz3Gn+xKDVWG/6QC15fKOVRtfX+yVBidxCxScY5ke4LOibpJ1gjltIhxzz9bRi7GxB24A6lYogQ+IXjV27fQjhKNg0xbKmg3k8LyvR7E0qEMSlhSqxLj7d0fmBWQNS3CzBLKjUiB91h4VGvojDE2H0oGDEdU8zeQuLKSiX1fpIVK4cCc4Lqku4KXY/Qrk8H9Pm/KwfU8qY9SGsAlCnYO3v6Z/v/Ca/VbXqxzUUkIVonMQ5DMjoEC0KCXtlyxoWlph5AQaCYmObgdEHOwCl3Fc9DfdjvYLdmIHuPsB8/ijtDT+iZVge/iA0kjAgMBAAGjggHXMIIB0zA/BggrBgEFBQcBAQQzMDEwLwYIKwYBBQUHMAGGI2h0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtd3dkcjA0MB0GA1UdDgQWBBSRpJz8xHa3n6CK9E31jzZd7SsEhTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFIgnFwmpthhgi+zruvZHWcVSVKO3MIIBHgYDVR0gBIIBFTCCAREwggENBgoqhkiG92NkBQYBMIH+MIHDBggrBgEFBQcCAjCBtgyBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMDYGCCsGAQUFBwIBFipodHRwOi8vd3d3LmFwcGxlLmNvbS9jZXJ0aWZpY2F0ZWF1dGhvcml0eS8wDgYDVR0PAQH/BAQDAgeAMBAGCiqGSIb3Y2QGCwEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQANphvTLj3jWysHbkKWbNPojEMwgl/gXNGNvr0PvRr8JZLbjIXDgFnf4+LXLgUUrA3btrj+/DUufMutF2uOfx/kd7mxZ5W0E16mGYZ2+FogledjjA9z/Ojtxh+umfhlSFyg4Cg6wBA3LbmgBDkfc7nIBf3y3n8aKipuKwH8oCBc2et9J6Yz+PWY4L5E27FMZ/xuCk/J4gao0pfzp45rUaJahHVl0RYEYuPBX/UIqc9o2ZIAycGMs/iNAGS6WGDAfK+PdcppuVsq1h1obphC9UynNxmbzDscehlD86Ntv0hgBgw2kivs3hi1EdotI9CO/KBpnBcbnoB7OUdFMGEvxxOoMIIEIjCCAwqgAwIBAgIIAd68xDltoBAwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEzMDIwNzIxNDg0N1oXDTIzMDIwNzIxNDg0N1owgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOFSmy1aqyCQ5SOmM7uxfuH8mkbw0U3rOfGOAYXdkXqUHI7Y5/lAtFVZYcC1+xG7BSoU+L/DehBqhV8mvexj/avoVEkkVCBmsqtsqMu2WY2hSFT2Miuy/axiV4AOsAX2XBWfODoWVN2rtCbauZ81RZJ/GXNG8V25nNYB2NqSHgW44j9grFU57Jdhav06DwY3Sk9UacbVgnJ0zTlX5ElgMhrgWDcHld0WNUEi6Ky3klIXh6MSdxmilsKP8Z35wugJZS3dCkTm59c3hTO/AO0iMpuUhXf1qarunFjVg0uat80YpyejDi+l5wGphZxWy8P3laLxiX27Pmd3vG2P+kmWrAgMBAAGjgaYwgaMwHQYDVR0OBBYEFIgnFwmpthhgi+zruvZHWcVSVKO3MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5jcmwwDgYDVR0PAQH/BAQDAgGGMBAGCiqGSIb3Y2QGAgEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQBPz+9Zviz1smwvj+4ThzLoBTWobot9yWkMudkXvHcs1Gfi/ZptOllc34MBvbKuKmFysa/Nw0Uwj6ODDc4dR7Txk4qjdJukw5hyhzs+r0ULklS5MruQGFNrCk4QttkdUGwhgAqJTleMa1s8Pab93vcNIx0LSiaHP7qRkkykGRIZbVf1eliHe2iK5IaMSuviSRSqpd1VAKmuu0swruGgsbwpgOYJd+W+NKIByn/c4grmO7i77LpilfMFY0GCzQ87HUyVpNur+cmV6U/kTecmmYHpvPm0KdIBembhLoz2IYrF+Hjhga6/05Cdqa3zr/04GpZnMBxRpVzscYqCtGwPDBUfMIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg++FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9wtj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IWq6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKMaLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAEggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBcNplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQPy3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4FgxhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oPIQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AXUKqK1drk/NAJBzewdXUhMYIByzCCAccCAQEwgaMwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkCCA7rV4fnngmNMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEggEAMDALt0CIPevmguhmsCzFYdNzJC4h7e9wrf+RMMeyV+k+KGT3AB/TraucExOfJW1HMvE5vE81icGjHk96qyDS6RwERp/JcB2R6IJV4JrSaf0n+5eX1wgeON6vysSLS164MSbKI5ybztPt3UgHJKtcITa58Ey58aeMfbh0yUI2ELGDwvUuXRkZ63aztQ2ooN9M3WrbyCnopuVNaCvVoHtB5CIPBcQgYBgyUsL1xH6gC2vRjJ7fFHWGrUMt2uNBksZc3bntcjrJvB5xmtOVa0KGAYy4RCxWt8Lsz/krmYdfDVFCarncXzxkGvBv+yABYUtmnVZ/pIUwEJBkMyhclw/uQg=="},"billingPeriod":6,"billingPeriodUnit":"Month","valid":true,"transactions":[]}]
[{"id":"basic_6_month","alias":"basic_6_month","type":"paid subscription","group":"20840123","state":"owned","title":"Basis","description":"Das Basis-Abonnement für 6 Monate","priceMicros":6990000,"price":"6,99 €","currency":"EUR","countryCode":"DE","loaded":true,"canPurchase":false,"owned":true,"introPrice":null,"introPriceMicros":null,"introPricePeriod":null,"introPricePeriodUnit":null,"introPricePaymentMode":null,"ineligibleForIntroPrice":null,"discounts":[],"downloading":false,"downloaded":false,"additionalData":null,"transaction":{"type":"ios-appstore","id":"1000000848151316","appStoreReceipt":"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"},"billingPeriod":6,"billingPeriodUnit":"Month","valid":true,"transactions":[]}]

Steps to reproduce

1) Create four subscriptions (pro and basic with 6 and 12 month time runtime each) 2) Create a subscription group with two service levels, but the pro subscription products on the first tear and the basic products on the second tear 3) Buy and own all products using this service:

import { Injectable } from '@angular/core';
import { IAPProduct, InAppPurchase2 } from '@ionic-native/in-app-purchase-2/ngx';
import { Platform } from '@ionic/angular';
import { Observable, ReplaySubject } from 'rxjs';
import { first, map } from 'rxjs/operators';
import { LoggingService } from './LoggingService';
import { ToastService } from './ToastService';

@Injectable({
  providedIn: 'root',
})
export class PaymentService {
  static BASIC_SUBSCRIPTION_TYPE = 'basic';
  static PRO_SUBSCRIPTION_TYPE = 'pro';
  static SUBSCRIPTION_TYPES = [PaymentService.BASIC_SUBSCRIPTION_TYPE, PaymentService.PRO_SUBSCRIPTION_TYPE];

  static TURN_6_MONTH = '6_month';
  static TURN_12_MONTH = '12_month';
  static SUBSCRIPTION_TURNS = [PaymentService.TURN_6_MONTH, PaymentService.TURN_12_MONTH];

  products$: Observable<IAPProduct[]>;
  productsSubject: ReplaySubject<IAPProduct[]>;

  ownedProducts$: Observable<IAPProduct[]>;
  ownedProductsSubject: ReplaySubject<IAPProduct[]>;

  constructor(
    private plt: Platform,
    private store: InAppPurchase2,
    private logger: LoggingService,
    private toastService: ToastService,
  ) {
    this.productsSubject = new ReplaySubject(1);
    this.products$ = this.productsSubject.asObservable();

    this.ownedProductsSubject = new ReplaySubject(1);
    this.ownedProducts$ = this.ownedProductsSubject.asObservable();

    this.plt.ready().then(() => {
      // Only for debugging!
      this.store.verbosity = this.store.DEBUG;

      this.registerProducts();

      this.setupListeners();

      this.store.ready(() => {
        this.logger.debug('Found products: ', this.store.products);
        this.productsSubject.next(
          this.store.products.filter(p => p.valid == true && p.canPurchase == true && p.type !== 'application'),
        );
      });
    });
  }

  registerProducts() {
    PaymentService.SUBSCRIPTION_TURNS.forEach(turn => {
      PaymentService.SUBSCRIPTION_TYPES.forEach(type => {
        this.store.register({
          id: `${type}_${turn}`,
          type: this.store.PAID_SUBSCRIPTION,
        });
      });
    });
    this.store.refresh();
  }

  setupListeners() {
    this.store.error(error => {
      this.logger.error('Error during purchase: ' + error.code + ' = ' + error.message);
      //   this.toastService.showNegativeToast(error.code + ' - ' + error.message, true);
    });

    this.store.when('subscription').updated(() => {
      this.logger.debug('Updated subscriptions: ', this.store.products);
      this.productsSubject.next(
        this.store.products.filter(p => p.valid == true && p.canPurchase == true && p.type !== 'application'),
      );
    });

    this.store
      .when('product')
      .approved((p: IAPProduct) => {
        this.logger.debug('Approved product: ', p);
        return p.verify();
      })
      .verified((p: IAPProduct) => {
        p.finish();
      });

    this.store.when('product').owned((p: IAPProduct) => {
      if (p.valid && p.type !== 'application') {
        this.logger.debug('Owning product: ', p);
        this.ownedProductsSubject.next([p]);
      }
    });
  }

  purchase(product: IAPProduct) {
    return this.store.order(product);
  }

  restore() {
    this.store.refresh();
  }

}

4) Use a wrapper component to call `purchase(...)' on the registered products.

j3k0 commented 3 years ago

On iOS, Apple is the one preventing your app from owning multiple subscriptions. So if your setup is correct, it should work.

However notice one thing, Apple doesn't support pro-rata refunds, so when you downgrade, the upper level subscription stays active until the end of the period, the lower level subscription is also owned. Thus you can perceive the user as subscribed to 2 products. Maybe that's what you are seeing here.

nippilaus commented 2 years ago

That was also my understanding that apple controls which subscriptions I can own and when an up- or downgrade should happen. On Android it works like a charm.

Meanwhile I published the app via testflight since I hoped that the sandbox was causing the problem. It was not...

The strange thing: I am still owning three subscriptions when starting the app from testflight (I register the products via the plugin and then get a reply from the apple server that I own three out of four subscriptions) but neither my license testing account (I even created and logged-in a new one) nor my developer account who is logged-in on the iphone owns a subscription according to the app store.

I am totally confused.

j3k0 commented 2 years ago

The plugin reports the subscriptions as owned because the expiry date is not available client side, you need to setup a receipt validation server (like https://billing.fovea.cc or your own) that will add the additional information (by fetching this from Apple, which also ensures the validity of the receipt)

nippilaus commented 2 years ago

I have implemented a validation backend but the problem persists. As soon as the store is ready, I receive a list of the registered products and they are all marked with owned=true and canPurchase=false. They all run through the lifecycle, so I receive hooks for approved, verified, and owned. The plugin sends one of these products (the one that I really own) to the backend and asks for validation (which works). The other products are not checked with the backend which means I cannot check their state. From my services point of view they cannot be purchased.

Update: This is definitely some kind of caching problem. When erasing the app completely and starting over again, only one subscription is marked as owned - the one that I really own according to the AppStore. When I then make another subscription, this one is verified with the backend but the other is not invalidated. When I then start the app again, both previously owned subscriptions are marked as owned (I have two more, they are not) but only the one that I really own is checked with the backend. I can repeat this until all my subscriptions are marked as owned in the cache but the backend always only receives the one for verification that I really own according to the AppStore.

vesper8 commented 2 years ago

I just arrived at the exact same scenario. Also have my own receipt validation back-end, also have 2 tiers of subscriptions and currently the front-end shows that I own both tiers. Haven't tried uninstalling / re-installing the app yet.

Same as with you, if I go in the settings it only shows the upper tier subscription. It does seem like a cache issue. Have you figured out how to clear that cache or something?

This is preventing me from allowing users to switch back to the other tier, since it is marked as canPurchase: false and owned: true

It's been a few months since your last reply.. did you figure out a way to make this manageable @nippilaus ? We can't expect users to uninstall/reinstall their apps.

Also, if you wouldn't mind taking a moment of your time, I'd like to know if you know how to allow for a downgrade back to the free tier? I have two premium tiers as well as a free tier. Do I need to create the free tier as a free subscription in order to be able to use it and allow users to downgrade back to free if that's what they want? Or for example when their premium subscription expires.

Many thanks for your time!

nippilaus commented 2 years ago

For me, the issue was about an incomplete implementation of my backend validation service. I created a free account at the fovea service and tested my app with this (and logged the response data). As soon as everything worked as expected, I fixed my backend implementation so that it gave the exact same responses (I had the feeling that some of the edge cases are not very well documented). This made my use cases work in the end. However, it was a very itsy-bitsy peace of work and took about 2 weeks.

We do not have a free tier but we provide a link to cancel the subscription within our app. The relevant native dialog can be opened platform-agnostic by calling store.manageSubscriptions() (see docs of the plugin). However, you would probably have to refresh the store after the user returns from the native screen where she potentially cancelled the subscription. This should (after some time) be returned as invalid.

Hope this helps!?!

vesper8 commented 2 years ago

Thanks for the response @nippilaus, certainly very helpful. I'll have a look at store.manageSubscriptions() for sure.

I feel like I've also arrived at the same point you did. I realized that the reason why I'm running into problems is because my receipt verification is not returning a proper response.

I'm using https://github.com/imdhemy/laravel-in-app-purchases to validate my receipts. Curious what you are using?

At first I wasn't enabling the validator at all and was instead doing a custom API call inside the window.store.when(this.subscriptions[key].id).verified() hook of each product. The backend would validate the receipt and return essentially true or false. If true, then I would call product.finish(); and if false I would just eject there.

This isn't checking if the subscription is expired so I guess that's why the window.store.when(this.subscriptions[key].id).expired() is never called

After doing more digging I'm realizing now that in order to solve my issues, I need to use the validator. And I just found what the response object is supposed to look like here: https://billing.fovea.cc/documentation/api/v1/validate/

I also thought about signing up for https://billing.fovea.cc/ and logging the responses, same as you did. Curious, how are you managing to intercept the responses from the validator exactly?

Currently I just enable the validator like so

window.store.validator = `${this.$api}/api/v1/iap/${process.env.CORDOVA_PLATFORM}/validate`;

I still have to work out how to generate the proper response on my back-end, and handle all the possible edge cases.. the fun bit that you described as itsy-bitsy piece of work and took about 2 weeks

I find it unfortunate that there doesn't appear to be a solid example for an open-source alternative to https://billing.fovea.cc/

I don't suppose you are at liberty to share that piece of the puzzle are you? I'd have to convert it to php / Laravel in any case. If you can share it here that would be fantastic. If you would rather not, but are open to share it privately then please send me an email, it's publicly available when you click on my name.

Many thanks once again!

vesper8 commented 2 years ago

@nippilaus one more question if you please...

I'm trying to access the data returned from https://developer.apple.com/documentation/appstoreserverapi/get_transaction_history and https://developer.apple.com/documentation/appstoreserverapi/get_all_subscription_statuses

It states that a JWT token is required.. I'm just unsure where to get this token.. if it's already available as part of this here package.. I'm unsure how to extract it from the internal API.. do you happen to know how?

Many thanks!!

nippilaus commented 2 years ago

Just want to reply quickly: I am on short holidays till tomorrow. I will give more detailed answers on Friday but in short: my backend is written in TS / relies on node.js. Therefore, I utilize this package for validating the receipts and then wrap the result as expected by the cordova/ionic plugin. I will check on Friday if I can add more useful details.

vesper8 commented 2 years ago

Great, take your time seriously, I really appreciate your help.

If you're able to share the part of your back-end that validates the receipt and generates the response that would be incredibly useful, even if I have to port it to PHP, I'm sure it'll save me many days or weeks even.

Looking forward to your reply when you're back from your holidays. Enjoy! Hope you're having great weather wherever you are.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.