cordova-plugin-purchase
cordova-plugin-purchase copied to clipboard
V13 Android products array are empty. Capacitor Ionic VueJS
Observed behavior
Android products are empty after registering the products, I haven't found any of these issues here.
Full log will be below
2023-07-07 14:11:54.654 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: GooglePlay products: []
So, what I did:
- I have created subscriptions at Google Play Console, built a release, and pushed the app to internal tests.
- working with android v32
- have added into
build.gradle
dependencies
implementation 'com.android.billingclient:billing:6.0.1'
- have added to
AndroidManifest.xml
(found that this is not required currently, but I did so)
<uses-permission android:name="com.android.vending.BILLING" />
- I'm using product_id of subscriptions from Google Play to use them for the register method.
- have heard from the dev of this package that BILlING_KEY is not used anymore and ignored this.
- My code looks like this:
import "cordova-plugin-purchase";
const initStore = async () => {
CdvPurchase.Logger.console = {
error: (message: string | unknown) => logerror(message),
warn: (message: string | unknown) => logwarn(message),
log: (message: string | unknown) => loginfo(message)
};
CdvPurchase.store.verbosity = LogLevel.DEBUG;
CdvPurchase.store.validator =
process.env.VUE_APP_IAP_RECEIPT_VALIDATION_URL + `/${deviceid}`;
CdvPurchase.store.validator_privacy_policy = ['analytics', 'support', 'tracking', 'fraud'];
CdvPurchase.store.applicationUsername = () => deviceid;
/** getting products from the backend */
onPlansResult(async ({ data }) => {
plans.value = data?.plans || [];
CdvPurchase.store.ready(() => {
products.value = CdvPurchase.store.products;
console.log('STORE IS READY');
});
await registerProducts();
setupListeners();
await CdvPurchase.store.initialize([
Platform.APPLE_APPSTORE,
Platform.GOOGLE_PLAY,
]);
console.log('store must be initialized');
});
}
document.addEventListener('deviceready', initStore);
const registerProducts = async () => {
const productsForRegister = [];
plans.value.forEach((plan) => {
/** I'm absolutely certain that I'm getting the ID of backend product, have seen it within the console.log()
const id = getPlanId(plan) || '';
const iapProduct = {
id: id,
type: ProductType.PAID_SUBSCRIPTION,
plantorm: getStorePlatform(),
// group: 'default'
};
productsForRegister.push(iapProduct);
});
console.log(productsForRegister);
CdvPurchase.store.register(productsForRegister);
console.log('products constructed send to register');
};
const setupListeners = async () => {
CdvPurchase.store.when().approved(approvedEvent);
CdvPurchase.store.when().verified(verifiedEvent);
CdvPurchase.store.when().finished(ownedEvent);
CdvPurchase.store.when().receiptUpdated(updatedEvent);
CdvPurchase.store.error(errorEvent);
};
Any advice?
2023-07-07 14:06:12.493 23242-23242/? D/CdvPurchase: onStart()
2023-07-07 14:06:12.493 23242-23242/? D/CdvPurchase: queryPurchases()
2023-07-07 14:06:12.503 23242-23242/? D/CdvPurchase: executeServiceRequest() -> OK
2023-07-07 14:06:12.795 23242-27751/? I/CdvPurchase: queryPurchases(SUBS) -> Elapsed time: 292ms
2023-07-07 14:06:12.836 23242-27749/? I/CdvPurchase: queryPurchases(INAPP) -> Elapsed time: 333ms
2023-07-07 14:06:12.836 23242-27749/? D/CdvPurchase: sendToListener() -> setPurchases
2023-07-07 14:06:12.836 23242-27749/? D/CdvPurchase: data -> {"purchases":[]}
2023-07-07 14:06:14.288 23242-23242/? D/CdvPurchase: onStop()
2023-07-07 14:07:01.370 28582-28672/? D/CdvPurchase: sendToListener() -> ready
2023-07-07 14:07:01.372 28582-28672/? D/CdvPurchase: data -> {}
2023-07-07 14:07:01.372 28582-28672/? D/CdvPurchase: init()
2023-07-07 14:07:01.384 28582-28672/? D/CdvPurchase: startServiceConnection()
2023-07-07 14:07:01.410 28582-28719/? D/CdvPurchase: startServiceConnection() -> Success
2023-07-07 14:07:01.410 28582-28719/? D/CdvPurchase: init() -> Success
2023-07-07 14:09:25.438 28582-28582/? D/CdvPurchase: onStop()
2023-07-07 14:11:11.164 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/ - Line 4362 - Msg: Create CdvPurchase...
2023-07-07 14:11:11.705 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: Create CdvPurchase...
2023-07-07 14:11:54.484 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase] INFO: initialize()
2023-07-07 14:11:54.484 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: Adding platforms: [{"platform":"ios-appstore"},{"platform":"android-playstore"}]
2023-07-07 14:11:54.484 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO:
2023-07-07 14:11:54.485 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO:
2023-07-07 14:11:54.485 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: AppStore initializing...
2023-07-07 14:11:54.486 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: AppStore is not supported.
2023-07-07 14:11:54.487 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: GooglePlay initializing...
2023-07-07 14:11:54.488 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.GooglePlay] INFO: Initialize
2023-07-07 14:11:54.488 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.GooglePlay.Bridge] INFO: setup ok
2023-07-07 14:11:54.491 30894-31009/io.my.app D/CdvPurchase: sendToListener() -> ready
2023-07-07 14:11:54.491 30894-31009/io.my.app D/CdvPurchase: data -> {}
2023-07-07 14:11:54.492 30894-31009/io.my.app D/CdvPurchase: init()
2023-07-07 14:11:54.517 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.GooglePlay.Bridge] INFO: listener: {"type":"ready","data":{}}
2023-07-07 14:11:54.531 30894-31009/io.my.app D/CdvPurchase: startServiceConnection()
2023-07-07 14:11:54.613 30894-31626/io.my.app D/CdvPurchase: startServiceConnection() -> Success
2023-07-07 14:11:54.613 30894-31626/io.my.app D/CdvPurchase: init() -> Success
2023-07-07 14:11:54.629 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.GooglePlay] DEBUG: Ready
2023-07-07 14:11:54.630 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: GooglePlay initialized.
2023-07-07 14:11:54.654 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: GooglePlay products: []
2023-07-07 14:11:54.655 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase.AdapterListener] DEBUG: setSupportedPlatforms: android-playstore
2023-07-07 14:11:54.655 30894-30894/io.my.app I/Capacitor/Console: File: http://localhost/js/app.30a84cbc.js - Line 1 - Msg: [CdvPurchase] DEBUG: Calling callback: type=ready() name=
Same as what I encountered. Capacitor Ionic ReactJS. @j3k0 Hope to help us
Same, works with ios but not android. Ping @j3k0 🙏🏽]
Resolved :)
@j3k0 Hello. Any advice, please?
I apologize, I'm in vacation (thus the delay).
Adding implementation 'com.android.billingclient:billing:6.0.1'
is a mistake for 2 reasons:
- the plugin uses version 5
-
npx cap sync
should add that dependency to yourbuild.gradle
and the permission to the android manifest file.
Make sure you configured the licensed testers, check this doc: https://developer.android.com/google/play/billing/test
I apologize, I'm in vacation (thus the delay).
Adding
implementation 'com.android.billingclient:billing:6.0.1'
is a mistake for 2 reasons:
- the plugin uses version 5
npx cap sync
should add that dependency to yourbuild.gradle
and the permission to the android manifest file.Make sure you configured the licensed testers, check this doc: https://developer.android.com/google/play/billing/test
@j3k0 Thank you for the answer.
I have licensed testers.
npx cap sync
did work and set the correct version of the billing client, but I still have the same output after I rebuilt the Android app and reuploaded it to Google Play Console.
2023-07-13 13:14:22.549 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/ - Line 4362 - Msg: Create CdvPurchase...
2023-07-13 13:14:23.072 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: Create CdvPurchase...
2023-07-13 13:14:29.141 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase] INFO: initialize()
2023-07-13 13:14:29.150 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: Adding platforms: [{"platform":"android-playstore"}]
2023-07-13 13:14:29.151 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO:
2023-07-13 13:14:29.151 17624-17624/io.sdcn.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: GooglePlay initializing...
2023-07-13 13:14:29.151 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase.GooglePlay] INFO: Initialize
2023-07-13 13:14:29.151 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase.GooglePlay.Bridge] INFO: setup ok
2023-07-13 13:14:29.158 17624-17704/io.my.app D/CdvPurchase: sendToListener() -> ready
2023-07-13 13:14:29.158 17624-17704/io.my.app D/CdvPurchase: data -> {}
2023-07-13 13:14:29.159 17624-17704/io.my.app D/CdvPurchase: init()
2023-07-13 13:14:29.168 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase.GooglePlay.Bridge] INFO: listener: {"type":"ready","data":{}}
2023-07-13 13:14:29.174 17624-17704/io.my.app D/CdvPurchase: startServiceConnection()
2023-07-13 13:14:29.192 17624-17844/io.my.app D/CdvPurchase: startServiceConnection() -> Success
2023-07-13 13:14:29.192 17624-17844/io.my.app D/CdvPurchase: init() -> Success
2023-07-13 13:14:29.195 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase.GooglePlay] DEBUG: Ready
2023-07-13 13:14:29.235 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: GooglePlay initialized.
2023-07-13 13:14:29.235 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase.Adapters] INFO: GooglePlay products: []
2023-07-13 13:14:29.235 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase.AdapterListener] DEBUG: setSupportedPlatforms: android-playstore
2023-07-13 13:14:29.235 17624-17624/io.my.app I/Capacitor/Console: File: http://localhost/js/app.f622b1fd.js - Line 1 - Msg: [CdvPurchase] DEBUG: Calling callback: type=ready() name=
I have a similar issue with Framework7, Capacitor, Vue3 app. The PAID_SUBSCRIPTION product is not getting registered while NON_CONSUMABLE product is working fine.
async initPro() {
const { store, ProductType, Platform } = CdvPurchase;
this.refreshProduct();
this.refreshSubscriptionProduct();
// This registration works fine
store.register({
type: CdvPurchase.NON_CONSUMABLE,
id: "pro",
platform: Platform.GOOGLE_PLAY,
});
// Not working. "app.subscription" is ID for Subscription. "monthly-plan" is ID for base plan.
store.register({
type: CdvPurchase.PAID_SUBSCRIPTION,
id: "app.subscription.monthly-plan",
platform: Platform.GOOGLE_PLAY,
});
store
.when("pro")
.productUpdated(this.refreshProduct)
.approved(this.finishPurchase);
store
.when("app.subscription.monthly-plan")
.productUpdated(this.refreshSubscriptionProduct)
.approved(this.finishSubscriptionPurchase);
this.products = store.products;
store.error(error => {
console.log("ERROR " + error.code + ": " + error.message);
});
store.initialize([Platform.GOOGLE_PLAY]);
},
orderPro() {
if (this.product && this.product.canPurchase) {
await this.product.getOffer().order();
}
},
orderSubscription() {
const { store } = CdvPurchase;
await store.order("app.subscription.monthly-plan");
}
orderSubscription returns this error. Store Error 6777003: Product not registered: null
.
And this.products
array returns only a single NON_CONSUMABLE product. Why subscription product is not getting registered? I would appreciate any help. Thanks
@v-trishyn Double-check what you pass to the store.register
method. The platform field for at least some products should be CdvPurchase.Platform.GOOGLE_PLAY
, for example:
const ProductType = CdvPurchase.ProductType;
const Platform = CdvPurchase.Platform;
store.register([{
id: 'subscription1',
type: ProductType.PAID_SUBSCRIPTION,
platform: Platform.APPLE_APPSTORE,
}, {
id: 'subscription1',
type: ProductType.PAID_SUBSCRIPTION,
platform: Platform.GOOGLE_PLAY,
}, {
id: 'consumable1',
type: ProductType.CONSUMABLE,
platform: Platform.BRAINTREE,
}]);
For PAID_SUBSCRIPTION you should register like:
store.register({
type: ProductType.PAID_SUBSCRIPTION,
id: "subscription_product_id",
platform: Platform.GOOGLE_PLAY,
});
"CdvPurchase" namespace does not work for PAID_SUBSCRIPTION type. No idea why!
For PAID_SUBSCRIPTION you should register like:
store.register({ type: ProductType.PAID_SUBSCRIPTION, id: "subscription_product_id", platform: Platform.GOOGLE_PLAY, });
"CdvPurchase" namespace does not work for PAID_SUBSCRIPTION type. No idea why!
ProductType.PAID_SUBSCRIPTION
does not work for me.
I get following error then:
custom.js:19560 Uncaught ReferenceError: ProductType is not defined
If I use window.CdvPurchase.ProductType.PAID_SUBSCRIPTION
instead, I do not get the error but then I get
IAP error code:6777003 Product not registered: null
I use following code to register:
window.CdvPurchase.store.register([{
id: inAppPurch_PRO,
type: window.CdvPurchase.ProductType.PAID_SUBSCRIPTION,
platform: devicePlatformCdvPurchase
}]);
id
is refering the the product id (it worked on earlier versions <13)
devicePlatformCdvPurchase
is refering to window.CdvPurchase.Platform.GOOGLE_PLAY
for Android.
And following code to order() the subscription:
const offer1 = product1.offers[0].id;
window.CdvPurchase.store.order(offer1)
The store object is available with the right product and the right offer (subscription).
Any ideas?
PS. I also migrated to the iapic v3 API according to this migration documentations: https://www.iaptic.com/documentation/information-fovea-billing https://www.iaptic.com/documentation/setup/cordova
any ideas @j3k0 ? Any help is highly appreciated.
@MarcelSchuermann are you defining the ProductType? you should define it like
import "cordova-plugin-purchase/www/store";
const { store, ProductType, Platform } = CdvPurchase;
Here is a working composable I use
https://gist.github.com/idesignzone/962746e23f967286f0608f0b7cc276c2
@idesignzone Thanks for the input.
Yes, exactly like you mentioned (without the import command as I am using vanilla .js).
const { store, ProductType, Platform } = CdvPurchase;
I am also using the Iaptic backend like this:
const iaptic = new CdvPurchase.Iaptic({
appName: "com.xxx.xxx",
apiKey: "xxx",
});
store.validator = iaptic.validator;
Any other ideas?
Nice, it worked - I looked at your example @idesignzone thx a lot!
I changed:
store.order(IAPProduct1.offers[0].id)
To:
iapProduct.getOffer().order();
I think that was the main change. I also improved the store.get() function parameters according to your example.