Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] Appstore products appear to load, but products list is empty, Appstore Plugin undefined. #1394

Closed
jmdjr opened this issue Mar 13, 2023 · 31 comments

Comments

@jmdjr
Copy link

jmdjr commented Mar 13, 2023

Observed behavior

[Log] [CdvPurchase] INFO: initialize() (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO: Adding platforms: [{"platform":"ios-appstore"}] (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO:  (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO: AppStore initializing... (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: bridge.init (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: setup ok (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: ready (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: bridge.init done (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO: AppStore initialized.  (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO: AppStore products: [{"id":"app.sgl.linker.iap.test.1","platform":"ios-appstore","type":"consumable"}] (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: bridge.load (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: load ["app.sgl.linker.iap.test.1"] (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: load ok: { valid:[{"id":"app.sgl.linker.iap.test.1","description":"test purchasing something","introPrice":null,"introPricePaymentMode":null,"billingPeriodUnit":"Day","countryCode":"US","introPricePeriodUnit":null,"discounts":[],"title":"SGL: Test purchase 1","price":"$0.99","billingPeriod":0,"group":null,"priceMicros":990000,"currency":"USD","introPricePeriod":null,"introPriceMicros":null}] invalid:[] } (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: bridge.loaded: {"validProducts":[{"id":"app.sgl.linker.iap.test.1","description":"test purchasing something","introPrice":null,"introPricePaymentMode":null,"billingPeriodUnit":"Day","countryCode":"US","introPricePeriodUnit":null,"discounts":[],"title":"SGL: Test purchase 1","price":"$0.99","billingPeriod":0,"group":null,"priceMicros":990000,"currency":"USD","introPricePeriod":null,"introPriceMicros":null}],"invalidProducts":[]} (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: eligibilities ready. (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] DEBUG: app.sgl.linker.iap.test.1 is valid: {"id":"app.sgl.linker.iap.test.1","description":"test purchasing something","introPrice":null,"introPricePaymentMode":null,"billingPeriodUnit":"Day","countryCode":"US","introPricePeriodUnit":null,"discounts":[],"title":"SGL: Test purchase 1","price":"$0.99","billingPeriod":0,"group":null,"priceMicros":990000,"currency":"USD","introPricePeriod":null,"introPriceMicros":null} (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] DEBUG: registering existing product (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] DEBUG: Products loaded: [{"className":"Product","title":"SGL: Test purchase 1","description":"test purchasing something","platform":"ios-appstore","type":"consumable","id":"app.sgl.linker.iap.test.1","offers":[{"className":"Offer","id":"$","pricingPhases":[{"price":"$0.99","priceMicros":990000,"currency":"USD","paymentMode":"UpFront","recurrenceMode":"NON_RECURRING"}],"productId":"app.sgl.linker.iap.test.1","productType":"consumable","platform":"ios-appstore","offerType":"Default"}],"raw":{"id":"app.sgl.linker.iap.test.1","description":"test purchasing something","introPrice":null,"introPricePaymentMode":null,"billingPeriodUnit":"Day","countryCode":"US","introPricePeriodUnit":null,"discounts":[],"title":"SGL: Test purchase 1","price":"$0.99","billingPeriod":0,"group":null,"priceMicros":990000,"currency":"USD","introPricePeriod":null,"introPriceMicros":null},"countryCode":"US"}] (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO: AppStore loaded: [{"className":"Product","title":"SGL: Test purchase 1","description":"test purchasing something","platform":"ios-appstore","type":"consumable","id":"app.sgl.linker.iap.test.1","offers":[{"className":"Offer","id":"$","pricingPhases":[{"price":"$0.99","priceMicros":990000,"currency":"USD","paymentMode":"UpFront","recurrenceMode":"NON_RECURRING"}],"productId":"app.sgl.linker.iap.test.1","productType":"consumable","platform":"ios-appstore","offerType":"Default"}],"raw":{"id":"app.sgl.linker.iap.test.1","description":"test purchasing something","introPrice":null,"introPricePaymentMode":null,"billingPeriodUnit":"Day","countryCode":"US","introPricePeriodUnit":null,"discounts":[],"title":"SGL: Test purchase 1","price":"$0.99","billingPeriod":0,"group":null,"priceMicros":990000,"currency":"USD","introPricePeriod":null,"introPriceMicros":null},"countryCode":"US"}] (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: processing pending transactions (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] DEBUG: loading appstore receipt... (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: loading appStoreReceipt (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: infoPlist: app.lostseraph.linker,1.0,16809984,null (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] DEBUG: appstore receipt loaded (user-script:13, line 321)
[Warning] [CdvPurchase.AppleAppStore] WARNING: no appStoreReceipt (user-script:13, line 321)

and on the app none of the products are visible?
after all this, everything looks great, but inspecting the appstore adapter

const appStore = store.getAdapter(CdvPurchase.Platform.APPLE_APPSTORE);

is undefined. I have In-App Purchases enabled in the XCode, and my implementation follows all the tutorials (for the most part) yet this is happening...

Expected behavior

The CdvPurchase.store.products list has the loaded products, or at least the appstore adapter reporting itself as undefined.

System Info

XCode v 14.2
iMac MacOS Ventura 13.2.1
Capacitor v. 4.6.0 (capacitor apps are based off cordova, don't see how this would make a difference here)

@jmdjr jmdjr changed the title IOS Appstore products appear to load, but products list is empty, Appstore Plugin undefined. [IOS] Appstore products appear to load, but products list is empty, Appstore Plugin undefined. Mar 16, 2023
@jmdjr jmdjr changed the title [IOS] Appstore products appear to load, but products list is empty, Appstore Plugin undefined. [iOS] Appstore products appear to load, but products list is empty, Appstore Plugin undefined. Mar 16, 2023
@j3k0
Copy link
Owner

j3k0 commented Mar 16, 2023

The list of products is empty because the App Store adapter didn't reach the "ready" state. I wonder if it will work with the integration of a receipt validation service? The use case is more broadly tested. You can try this quickly with a free account on https://www.iaptic.com/

@jmdjr
Copy link
Author

jmdjr commented Mar 17, 2023

smooth method to "recommend" your company's services... but honestly was hoping not to need any more accounts to use iap. going to test with the free account but really sad that I have to use a service to get a free component to function.

@jmdjr
Copy link
Author

jmdjr commented Mar 17, 2023

how do we integrate the receipt validation service? the documentation links:
https://www.iaptic.com/documentation/setup/ios is out of date (the images are of older ui and step 5/6 no longer exist on those pages)
and
https://www.iaptic.com/documentation/validator-url/ is straight up 404.

@jmdjr
Copy link
Author

jmdjr commented Mar 17, 2023

image

@j3k0
Copy link
Owner

j3k0 commented Mar 17, 2023

smooth method to "recommend" your company's services... but honestly was hoping not to need any more accounts to use iap. going to test with the free account but really sad that I have to use a service to get a free component to function.

You don't have to. I'm trying to understand what doesn't work in your case. As far as I know you're the only user with this issue, so I'm trying to eliminate possible reasons.

The broken link and outdated screenshots are fixed.

@jmdjr
Copy link
Author

jmdjr commented Mar 17, 2023

That was rude of me. I am sorry. It was uncalled for.
I am going to review the updates and post the updates.

@jmdjr
Copy link
Author

jmdjr commented Mar 18, 2023

[Log] onscript loading complete (user-script:11, line 1456)
[Log] -IAP-: CdvPurchase IS defined (main.js, line 1)
[Log] -IAP-: installing iaptic receipt validator... (main.js, line 1)
[Log] -IAP-: registering products... (main.js, line 1)
[Log] -IAP-: setting up listeners... (main.js, line 1)
[Log] -IAP-: Store initializing... (main.js, line 1)
[Log] [CdvPurchase] INFO: initialize() (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO: Adding platforms: [{"platform":"ios-appstore"}] (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO:  (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO: AppStore initializing... (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: bridge.init (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: setup ok (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: ready (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: bridge.init done (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO: AppStore initialized.  (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO: AppStore products: [{"id":"app.sgl.linker.iap.test.1","platform":"ios-appstore","type":"consumable"}] (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: bridge.load (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: load ["app.sgl.linker.iap.test.1"] (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: load ok: { valid:[{"id":"app.sgl.linker.iap.test.1","description":"test purchasing something","introPrice":null,"introPricePaymentMode":null,"billingPeriodUnit":"Day","countryCode":"US","introPricePeriodUnit":null,"discounts":[],"title":"SGL: Test purchase 1","price":"$0.99","billingPeriod":0,"group":null,"priceMicros":990000,"currency":"USD","introPricePeriod":null,"introPriceMicros":null}] invalid:[] } (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: bridge.loaded: {"validProducts":[{"id":"app.sgl.linker.iap.test.1","description":"test purchasing something","introPrice":null,"introPricePaymentMode":null,"billingPeriodUnit":"Day","countryCode":"US","introPricePeriodUnit":null,"discounts":[],"title":"SGL: Test purchase 1","price":"$0.99","billingPeriod":0,"group":null,"priceMicros":990000,"currency":"USD","introPricePeriod":null,"introPriceMicros":null}],"invalidProducts":[]} (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] INFO: eligibilities ready. (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] DEBUG: app.sgl.linker.iap.test.1 is valid: {"id":"app.sgl.linker.iap.test.1","description":"test purchasing something","introPrice":null,"introPricePaymentMode":null,"billingPeriodUnit":"Day","countryCode":"US","introPricePeriodUnit":null,"discounts":[],"title":"SGL: Test purchase 1","price":"$0.99","billingPeriod":0,"group":null,"priceMicros":990000,"currency":"USD","introPricePeriod":null,"introPriceMicros":null} (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] DEBUG: registering existing product (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] DEBUG: Products loaded: [{"className":"Product","title":"SGL: Test purchase 1","description":"test purchasing something","platform":"ios-appstore","type":"consumable","id":"app.sgl.linker.iap.test.1","offers":[{"className":"Offer","id":"$","pricingPhases":[{"price":"$0.99","priceMicros":990000,"currency":"USD","paymentMode":"UpFront","recurrenceMode":"NON_RECURRING"}],"productId":"app.sgl.linker.iap.test.1","productType":"consumable","platform":"ios-appstore","offerType":"Default"}],"raw":{"id":"app.sgl.linker.iap.test.1","description":"test purchasing something","introPrice":null,"introPricePaymentMode":null,"billingPeriodUnit":"Day","countryCode":"US","introPricePeriodUnit":null,"discounts":[],"title":"SGL: Test purchase 1","price":"$0.99","billingPeriod":0,"group":null,"priceMicros":990000,"currency":"USD","introPricePeriod":null,"introPriceMicros":null},"countryCode":"US"}] (user-script:13, line 321)
[Log] [CdvPurchase.Adapters] INFO: AppStore loaded: [{"className":"Product","title":"SGL: Test purchase 1","description":"test purchasing something","platform":"ios-appstore","type":"consumable","id":"app.sgl.linker.iap.test.1","offers":[{"className":"Offer","id":"$","pricingPhases":[{"price":"$0.99","priceMicros":990000,"currency":"USD","paymentMode":"UpFront","recurrenceMode":"NON_RECURRING"}],"productId":"app.sgl.linker.iap.test.1","productType":"consumable","platform":"ios-appstore","offerType":"Default"}],"raw":{"id":"app.sgl.linker.iap.test.1","description":"test purchasing something","introPrice":null,"introPricePaymentMode":null,"billingPeriodUnit":"Day","countryCode":"US","introPricePeriodUnit":null,"discounts":[],"title":"SGL: Test purchase 1","price":"$0.99","billingPeriod":0,"group":null,"priceMicros":990000,"currency":"USD","introPricePeriod":null,"introPriceMicros":null},"countryCode":"US"}] (user-script:13, line 321)
[Log] -IAP-: AppStore users can make payments (main.js, line 1)
[Log] -IAP-: checking app store redemption sheet... (main.js, line 1)
[Log] -IAP-: Store initialize done... (main.js, line 1)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: processing pending transactions (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] DEBUG: loading appstore receipt... (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: loading appStoreReceipt (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore.Bridge] DEBUG: infoPlist: app.lostseraph.linker,1.0,16809984,null (user-script:13, line 321)
[Log] [CdvPurchase.AppleAppStore] DEBUG: appstore receipt loaded (user-script:13, line 321)
[Warning] [CdvPurchase.AppleAppStore] WARNING: no appStoreReceipt (user-script:13, line 321)
[Log] -IAP-: running update purchases... (main.js, line 1)
...
< redacted PI related logs >
...
[Log] -IAP-:  (main.js, line 1)
TESTS:
____________________________
list: false
actual product: undefined
test product: undefined

should I attach my iap connection logic?

@jmdjr
Copy link
Author

jmdjr commented Mar 18, 2023

it ends up allowing the appstore to initialize and the appstore is available, but the list is still empty and trying to get a product is undefined. later test show that while the appstore adapter is defined now, it is not "ready" after initializing the store.

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

I have a MVP of the project (takes out all the wrapping stuff and just the iap, which still doesn't connect. if that would be helpful?
LinkerMVP_Purchasing.zip

@j3k0 j3k0 closed this as completed in 7d76fa5 Mar 20, 2023
j3k0 added a commit that referenced this issue Mar 20, 2023
@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023

It looks like the CdvPurchase plugin is loaded twice.

I added this in the service constructor (right after "CdvPurchase is defined")

 (CdvPurchase as any).createdAt = new Date();

And this:

 (CdvPurchase as any).debuggedAt = new Date();

In the debug_Purchases() function.

Just after startup, when I've seen the "CdvPurchase is defined" log message, I open Safari's developer tools, but createdAt is undefined.

... clicking the debug button I get debuggedAt defined, createdAt still undefined.

Somehow the CdvPurchase object used by the service is different from the global object, or this global object has been overiden.

Quick test: adding window._CdvPurchase = CdvPurchase in the service constructor. And see if window.CdvPurchase === CdvPurchase.

In the constructor: window.CdvPurchase === CdvPurchase is true, however from debug_Purchases, window._CdvPurchase !== CdvPurchase.... So the global object was overridden, as if the plugin was loaded twice?

Also notice, in debug_Purchases, _CdvPurchase.store.products contains the non-empty list of products...

This is the root of the issue.

I have no idea what triggers this "double loading" of the plugin, working on a workaround...

NOTE:

Sometime at startup I get this logs:

⚡️  [log] - [LostSeraph] [-IAP-]: CdvPurchase IS defined!!
⚡️  [error] - ERROR Error: Uncaught (in promise): TypeError: undefined is not an object (evaluating 'CdvPurchase.LogLevel.DEBUG')

From this code:

        this.logger.log("CdvPurchase IS defined!!");
        const store = CdvPurchase.store;
        store.verbosity = CdvPurchase.LogLevel.DEBUG;

It means there's really something fishy with the way the plugin's JavaScript is being loaded by the bundler.

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

thank you for continuing to work on this, I saw you push a couple of other changes, but are they not enough to solve the issue?

@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023

No, it didn't solve the issue, I tried a few quick fix that I thought would be simple... but eventually it's not that simple, as it either broke access to CdvPurchase's enums or the CdvPurchase.store object. I have to step through what your app is doing to figure out how is this happening in the first place and get a better understanding.

I see that the code of the plugin is present in the main.js (bundled js file) but also in plugins/cordova/etc/..., possible that there are 2 separate instances of the javascript code loaded...?

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

hrm... that is odd. it would explain why my particular project isn't working while others are just fine, if that is the case. I take it the mvp project helps?

@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023

MVP helps, because it allows to reproduce the issue.

@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023

Look, the 2 "CdvPurchase.store" instance have different types:

Screenshot 2023-03-20 at 18 49 05

One is "Store" the other is "F", I guess the second one is from a minified version of the same code while the first is the non-minified version. So the problem definitely isn't with the plugin, just that you somehow bundle and load the code twice.

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

I see how that can be troublesome... odd. I don't know why I am loading the unminified version and the minified version at the same time...

@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023 via email

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

ah. ok. armed with that I can look to see how to break the double loading. thank you for your hard work!

@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023 via email

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

will do. I don't know how I double loaded the code, will try some unloading/reloading methods to see. seems like an edge case but if it helps make your codebase more resilient, maybe some minor reworking would be good.

@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023

I found a fix that works here at least:

In your code, replace:

import "cordova-plugin-purchase";

with:

import 'cordova-plugin-purchase/www/store.d';

This way, angular only includes the typings, not the actual code of the plugin.

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

⚡️  [log] - [LostSeraph] [-IAP-]: CdvPurchase IS defined

⚡️  [log] - [LostSeraph] [-IAP-]: installing iaptic receipt validator...

⚡️  [error] - ERROR Error: Uncaught (in promise): TypeError: undefined is not an object (evaluating 'this.store.log')

Iaptic@user-script:13:104:34

@capacitor://www.lostseraph.com/main.js:1:646682

onInvoke@capacitor://www.lostseraph.com/main.js:1:87039

run@capacitor://www.lostseraph.com/polyfills.js:1:1920

@capacitor://www.lostseraph.com/polyfills.js:1:16761

onInvokeTask@capacitor://www.lostseraph.com/main.js:1:86859

runTask@capacitor://www.lostseraph.com/polyfills.js:1:2541

_@capacitor://www.lostseraph.com/polyfills.js:1:9190

trying the updated input and pushed to device, this is the result.

@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023 via email

@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023

And make sure to remove the cordova-pluing-purchase import from iapCatalog as well

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

did that. added your extra check... still the same exception...

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

with the setup you provided

> window.CdvPurchase.store
< Store {0: "QUIET", 1: "ERROR", 2: "WARNING", 3: "INFO", 4: "DEBUG", 6777001: "SETUP", 6777002: "LOAD", 6777003: "PURCHASE", 6777004: "LOAD_RECEIPTS", 6777005: "CLIENT_INVALID", …}
> window._CdvPurchase.store
< TypeError: undefined is not an object (evaluating 'window._CdvPurchase.store')

@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023

My edited project, works fine here (notice I changed app ID in XCode project, might have to be reverted to your own).
LinkerMVP_Purchasing_Edited.zip

@j3k0
Copy link
Owner

j3k0 commented Mar 20, 2023

window._CdvPurchase.store will be undefined unless you stored window._CdvPurchase somewhere in your code.

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

will try it :D... and ha. ok.

@jmdjr
Copy link
Author

jmdjr commented Mar 20, 2023

OK! whatever you did it works on your version. so now I get to find the differences between that edited and my local one. yay!
thank you.

@jmdjr
Copy link
Author

jmdjr commented Mar 21, 2023

is the purchase supposed to show a confirmation before popping up the customary apple purchase dialog? I am only seeing the "type Y for purchase" and not the actual in-app purchase view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants