From 16531812b6b36f49d8610ef78b895c00952b3cb9 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 22:36:04 +0800 Subject: [PATCH 01/26] WIP: Remove @awesome-cordova-plugins/in-app-purchase-2 dependency --- package-lock.json | 21 --------------------- package.json | 1 - 2 files changed, 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5979d24e5..3c0d5a346 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,6 @@ "@angular/platform-browser-dynamic": "^14.2.0", "@angular/router": "^14.2.0", "@awesome-cordova-plugins/core": "^5.46.0", - "@awesome-cordova-plugins/in-app-purchase-2": "^5.43.0", "@capacitor-community/advertising-id": "^5.0.0", "@capacitor-community/bluetooth-le": "^2.2.3", "@capacitor-community/http": "github:numbersprotocol/http#fix-catch-disabled-Local-Network-case-on-iOS", @@ -1431,18 +1430,6 @@ "rxjs": "^5.5.0 || ^6.5.0 || ^7.3.0" } }, - "node_modules/@awesome-cordova-plugins/in-app-purchase-2": { - "version": "5.43.0", - "resolved": "https://registry.npmjs.org/@awesome-cordova-plugins/in-app-purchase-2/-/in-app-purchase-2-5.43.0.tgz", - "integrity": "sha512-y292xt+DSqsIpFCe0X7yjTZkC4moPT+gYpo7C59yBR8OeZPx0LHNTth3rzeSYsVityyCjnpEIf08x0hGfKr3bw==", - "dependencies": { - "@types/cordova": "latest" - }, - "peerDependencies": { - "@awesome-cordova-plugins/core": "^5.1.0", - "rxjs": "^5.5.0 || ^6.5.0 || ^7.3.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -25065,14 +25052,6 @@ "@types/cordova": "latest" } }, - "@awesome-cordova-plugins/in-app-purchase-2": { - "version": "5.43.0", - "resolved": "https://registry.npmjs.org/@awesome-cordova-plugins/in-app-purchase-2/-/in-app-purchase-2-5.43.0.tgz", - "integrity": "sha512-y292xt+DSqsIpFCe0X7yjTZkC4moPT+gYpo7C59yBR8OeZPx0LHNTth3rzeSYsVityyCjnpEIf08x0hGfKr3bw==", - "requires": { - "@types/cordova": "latest" - } - }, "@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", diff --git a/package.json b/package.json index 0fb03c52c..89f25ce9c 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "@angular/platform-browser-dynamic": "^14.2.0", "@angular/router": "^14.2.0", "@awesome-cordova-plugins/core": "^5.46.0", - "@awesome-cordova-plugins/in-app-purchase-2": "^5.43.0", "@capacitor-community/advertising-id": "^5.0.0", "@capacitor-community/bluetooth-le": "^2.2.3", "@capacitor-community/http": "github:numbersprotocol/http#fix-catch-disabled-Local-Network-case-on-iOS", From e986a3c65b7185f99acedd56a0eecb6141d5d4f3 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 22:37:53 +0800 Subject: [PATCH 02/26] WIP: bump cordova-plugin-purchase to 13.9.0 --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3c0d5a346..6407fee1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,7 +62,7 @@ "capacitor-blob-writer": "^1.0.4", "capacitor-native-settings": "^4.0.3", "compressorjs": "^1.0.7", - "cordova-plugin-purchase": "^11.0.0", + "cordova-plugin-purchase": "^13.9.0", "ethers": "^6.8.1", "hammerjs": "^2.0.8", "immutable": "^4.0.0-rc.14", @@ -8401,9 +8401,9 @@ } }, "node_modules/cordova-plugin-purchase": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/cordova-plugin-purchase/-/cordova-plugin-purchase-11.0.0.tgz", - "integrity": "sha512-FkgOyWBYS989dYpM6d3R36VrdsHweTbmp5y7ELa1GwMYq2AG+ImdB6DJcVpyU/se/zpTndBWH/zN9s3AFKfsLg==" + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/cordova-plugin-purchase/-/cordova-plugin-purchase-13.9.0.tgz", + "integrity": "sha512-dzN81dlfxYMidhPQRjpo8dNeQO7Fifwsf2fsi6AWMT+aiPBf5MVtwbzRBMiSuHJnMHCuNY9oIml37zrIXwbI/w==" }, "node_modules/core-js-compat": { "version": "3.25.0", @@ -30156,9 +30156,9 @@ } }, "cordova-plugin-purchase": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/cordova-plugin-purchase/-/cordova-plugin-purchase-11.0.0.tgz", - "integrity": "sha512-FkgOyWBYS989dYpM6d3R36VrdsHweTbmp5y7ELa1GwMYq2AG+ImdB6DJcVpyU/se/zpTndBWH/zN9s3AFKfsLg==" + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/cordova-plugin-purchase/-/cordova-plugin-purchase-13.9.0.tgz", + "integrity": "sha512-dzN81dlfxYMidhPQRjpo8dNeQO7Fifwsf2fsi6AWMT+aiPBf5MVtwbzRBMiSuHJnMHCuNY9oIml37zrIXwbI/w==" }, "core-js-compat": { "version": "3.25.0", diff --git a/package.json b/package.json index 89f25ce9c..b4210371b 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "capacitor-blob-writer": "^1.0.4", "capacitor-native-settings": "^4.0.3", "compressorjs": "^1.0.7", - "cordova-plugin-purchase": "^11.0.0", + "cordova-plugin-purchase": "^13.9.0", "ethers": "^6.8.1", "hammerjs": "^2.0.8", "immutable": "^4.0.0-rc.14", From 9432ed8775ecefa3d9f69f1fe3de47a526a00435 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 22:44:21 +0800 Subject: [PATCH 03/26] WIP(in-app-store.service): fix imports --- .../shared/in-app-store/in-app-store.service.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index f8e33b64d..846443f7d 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -1,11 +1,7 @@ import { Injectable, OnDestroy } from '@angular/core'; -import { - IAPError, - IAPProduct, - InAppPurchase2, -} from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { Platform, ToastController } from '@ionic/angular'; import { TranslocoService } from '@ngneat/transloco'; +import 'cordova-plugin-purchase'; import { BehaviorSubject, combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; import { @@ -24,9 +20,11 @@ import { ErrorService } from '../error/error.service'; export class InAppStoreService implements OnDestroy { debugPrint = setupInAppPurchaseDebugPrint('InAppStoreService'); - readonly inAppProducts$ = new BehaviorSubject([]); + readonly inAppProducts$ = new BehaviorSubject([]); readonly numPointPricesById$ = new BehaviorSubject({}); + private store!: CdvPurchase.Store; + readonly inAppProductsWithNumpoints$ = combineLatest([ this.inAppProducts$, this.numPointPricesById$, @@ -45,7 +43,6 @@ export class InAppStoreService implements OnDestroy { private readonly appId = 'io.numbersprotocol.capturelite'; constructor( - private readonly store: InAppPurchase2, private readonly platform: Platform, private readonly errorService: ErrorService, private readonly toastController: ToastController, @@ -64,10 +61,10 @@ export class InAppStoreService implements OnDestroy { try { await this.platform.ready(); + this.store = CdvPurchase.store; + this.regiseterStoreListeners(); this.registerStoreProducts(); - - this.store.refresh(); } catch (error) { const errorMessage = this.translocoService.translate( 'inAppPurchase.failedToInitInAppStore' From 6ff2c02a3d9e194750f68a7417ce30c67bf7832c Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 22:57:39 +0800 Subject: [PATCH 04/26] WIP(in-app-store.service): migrate registerStoreProducts method --- .../shared/in-app-store/in-app-store.service.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 846443f7d..8fd2c25bb 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -156,17 +156,18 @@ export class InAppStoreService implements OnDestroy { } private registerStoreProducts() { - const consumableProductIds = [ - CaptureInAppProductIds.BRONZE_PACK, - CaptureInAppProductIds.SLIVER_PACK, - CaptureInAppProductIds.GOLD_PACK, - CaptureInAppProductIds.PLATINUM_PACK, - ]; - const type = this.store.CONSUMABLE; + const consumableProductIds = Object.values(CaptureInAppProductIds); + const type = CdvPurchase.ProductType.CONSUMABLE; + const appstorePlatform = CdvPurchase.Platform.APPLE_APPSTORE; + const googlePlayPlatform = CdvPurchase.Platform.GOOGLE_PLAY; + const productsToRegister: CdvPurchase.IRegisterProduct[] = []; for (const id of consumableProductIds) { - this.store.register({ id, type }); + productsToRegister.push({ id, type, platform: appstorePlatform }); + productsToRegister.push({ id, type, platform: googlePlayPlatform }); } + + this.store.register(productsToRegister); } private readonly onStoreError = (_: IAPError) => { From 749a3442c152303ecfbf60a8e0ea19f71cf9b737 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 22:59:51 +0800 Subject: [PATCH 05/26] WIP(in-app-store.service): migrate regiseterStoreListeners method --- src/app/shared/in-app-store/in-app-store.service.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 8fd2c25bb..51f5e7b8f 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -142,9 +142,9 @@ export class InAppStoreService implements OnDestroy { private regiseterStoreListeners() { this.store.error(this.onStoreError); this.store.ready(this.onStoreReady); - this.store.when('product').approved(this.onStoreProductApproved); - this.store.when('product').updated(this.onStoreProductUpdated); - this.store.when('product').verified(this.onStoreProductVerified); + this.store.when().approved(this.onStoreProductApproved); + this.store.when().productUpdated(this.onStoreProductUpdated); + this.store.when().verified(this.onStoreProductVerified); } private unregisterStoreListeners() { From 1745e73d2bdf55bb9c61013958d9a82a101d698b Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:01:20 +0800 Subject: [PATCH 06/26] WIP(in-app-store.service): migrate onStoreError method --- src/app/shared/in-app-store/in-app-store.service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 51f5e7b8f..eaa231a7b 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -170,11 +170,12 @@ export class InAppStoreService implements OnDestroy { this.store.register(productsToRegister); } - private readonly onStoreError = (_: IAPError) => { + private readonly onStoreError = (_: CdvPurchase.IError) => { const errorMessage = this.translocoService.translate( 'inAppPurchase.inAppPurchaseErrorOcurred' ); this.errorService.toastError$(errorMessage).toPromise(); + // TODO: report to remote error service }; private readonly onStoreReady = () => { From b240e4ae8c8c80208bb048ed8d87435354936ac6 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:04:22 +0800 Subject: [PATCH 07/26] WIP(in-app-store.service): migrate onStoreProductUpdated method --- src/app/shared/in-app-store/in-app-store.service.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index eaa231a7b..695c34ec4 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -185,18 +185,16 @@ export class InAppStoreService implements OnDestroy { this.inAppProducts$.next(inAppProducts); }; - private readonly onStoreProductUpdated = (updatedProduct: IAPProduct) => { + private readonly onStoreProductUpdated = ( + updatedProduct: CdvPurchase.Product + ) => { if (this.shouldIgnoreProduct(updatedProduct)) { return; } this.debugPrint('onStoreProductUpdated', updatedProduct); - const inAppProducts = this.inAppProducts$.value.map(product => - product.id === updatedProduct.id ? updatedProduct : product - ); - - this.inAppProducts$.next(inAppProducts); + this.inAppProducts$.next(this.store.products); }; private readonly onStoreProductApproved = (product: IAPProduct) => { From 28ddeb2c02d28cd0b6777d3ca64a6f4a2fa968de Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:06:00 +0800 Subject: [PATCH 08/26] WIP(in-app-store.service): migrate onStoreProductApproved method --- src/app/shared/in-app-store/in-app-store.service.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 695c34ec4..907dfc619 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -197,13 +197,11 @@ export class InAppStoreService implements OnDestroy { this.inAppProducts$.next(this.store.products); }; - private readonly onStoreProductApproved = (product: IAPProduct) => { - if (this.shouldIgnoreProduct(product)) { - return; - } - this.debugPrint('onStoreProductApproved', product); - // TODO: in the future add validation logic here - product.verify(); + private readonly onStoreProductApproved = ( + transacction: CdvPurchase.Transaction + ) => { + this.debugPrint('onStoreProductApproved', transacction); + transacction.verify(); }; private readonly onStoreProductVerified = (product: IAPProduct) => { From c238e4b7fc1288431141172c353e63271893d2aa Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:06:56 +0800 Subject: [PATCH 09/26] WIP(in-app-store.service): migrate numPointsForProduct method --- src/app/shared/in-app-store/in-app-store.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 907dfc619..999b29090 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -221,7 +221,7 @@ export class InAppStoreService implements OnDestroy { // eslint-disable-next-line class-methods-use-this private numPointsForProduct( - product: IAPProduct, + product: CdvPurchase.Product, numPriceListById: NumPointPricesById ) { if (product.id in numPriceListById) { From abc0520c2cb55cf806c4069c00bdb44d09444c58 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:07:46 +0800 Subject: [PATCH 10/26] WIP: migrate InAppProductsWithNumPoint interface --- src/app/shared/in-app-store/in-app-store.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 999b29090..94fda267a 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -243,7 +243,7 @@ export enum CaptureInAppProductIds { } interface InAppProductsWithNumPoint { - inAppProduct: IAPProduct; + inAppProduct: CdvPurchase.Product; numPoints: number; } From 4737c96e5c1fa7b928bd746e8a59ab9020e5be82 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:09:32 +0800 Subject: [PATCH 11/26] WIP(in-app-store.service): migrate purchase method --- src/app/shared/in-app-store/in-app-store.service.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 94fda267a..dec7256c7 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -95,8 +95,10 @@ export class InAppStoreService implements OnDestroy { } } - purchase(product: IAPProduct) { - this.store.order(product); + purchase(product: CdvPurchase.Product) { + const offer = product.getOffer(); + if (!offer) return; + this.store.order(offer); } private async finishPurchase(inAppProduct: IAPProduct) { From 5afd3e9ab7f01dcbd3624ddd57cf90f8fb132191 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:13:44 +0800 Subject: [PATCH 12/26] WIP(in-app-store.service): migrate onStoreProductVerified method --- src/app/shared/in-app-store/in-app-store.service.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index dec7256c7..0ebcc0d0b 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -206,12 +206,11 @@ export class InAppStoreService implements OnDestroy { transacction.verify(); }; - private readonly onStoreProductVerified = (product: IAPProduct) => { - if (this.shouldIgnoreProduct(product)) { - return; - } - this.debugPrint('onStoreProductVerified', product); - this.finishPurchase(product); + private readonly onStoreProductVerified = ( + receipt: CdvPurchase.VerifiedReceipt + ) => { + this.debugPrint('onStoreProductVerified', receipt); + this.finishPurchase(receipt); }; private shouldIgnoreProduct(product: IAPProduct) { From 825fd1157783d3699ac7550e3e0d188e61c7889a Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:15:12 +0800 Subject: [PATCH 13/26] WIP(in-app-store.service): remove unused method shouldIgnoreProduct --- .../shared/in-app-store/in-app-store.service.ts | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 0ebcc0d0b..46d596c36 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -181,21 +181,13 @@ export class InAppStoreService implements OnDestroy { }; private readonly onStoreReady = () => { - const inAppProducts = this.store.products.filter( - product => this.shouldIgnoreProduct(product) === false - ); - this.inAppProducts$.next(inAppProducts); + this.inAppProducts$.next(this.store.products); }; private readonly onStoreProductUpdated = ( updatedProduct: CdvPurchase.Product ) => { - if (this.shouldIgnoreProduct(updatedProduct)) { - return; - } - this.debugPrint('onStoreProductUpdated', updatedProduct); - this.inAppProducts$.next(this.store.products); }; @@ -213,13 +205,6 @@ export class InAppStoreService implements OnDestroy { this.finishPurchase(receipt); }; - private shouldIgnoreProduct(product: IAPProduct) { - // For some reason on iOS there will be 1 in app product - // with product.id === io.numbersprotocol.capturelite - // we should ignore that product - return product.id === this.appId; - } - // eslint-disable-next-line class-methods-use-this private numPointsForProduct( product: CdvPurchase.Product, From 60b539050980c14b5b429a1ed58a0548edb5ddeb Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:22:52 +0800 Subject: [PATCH 14/26] WIP(in-app-store.service): add helper method extractProductFromReceipt --- .../in-app-store/in-app-store.service.ts | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 46d596c36..f7f0e4e25 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -101,9 +101,16 @@ export class InAppStoreService implements OnDestroy { this.store.order(offer); } - private async finishPurchase(inAppProduct: IAPProduct) { + private async finishPurchase(receipt: CdvPurchase.VerifiedReceipt) { + const product = this.extractProductFromReceipt(receipt); + + if (!product) { + receipt.finish(); + return; + } + const pointsToAdd = this.numPointsForProduct( - inAppProduct, + product.id, this.numPointPricesById$.value ); @@ -134,6 +141,18 @@ export class InAppStoreService implements OnDestroy { this.errorService.toastError$(errorMessage).toPromise(); } } + // eslint-disable-next-line class-methods-use-this + private extractProductFromReceipt(receipt: CdvPurchase.VerifiedReceipt) { + for (const transaction of receipt.sourceReceipt.transactions) { + for (const product of transaction.products) { + const isIncluded = Object.values( + CaptureInAppProductIds + ).includes(product.id); + if (isIncluded) return product; + } + } + return null; + } private async notifyUser(message: string) { return this.toastController @@ -207,11 +226,11 @@ export class InAppStoreService implements OnDestroy { // eslint-disable-next-line class-methods-use-this private numPointsForProduct( - product: CdvPurchase.Product, + productId: string, numPriceListById: NumPointPricesById ) { - if (product.id in numPriceListById) { - return numPriceListById[product.id].quantitiy; + if (productId in numPriceListById) { + return numPriceListById[productId].quantitiy; } return 0; } From 3f7db3b80c5de53f0b9bb76814af119f1d9257c0 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:25:23 +0800 Subject: [PATCH 15/26] WIP: WIP(in-app-store.service): refactor finishPurchase for debugging purpose --- .../in-app-store/in-app-store.service.ts | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index f7f0e4e25..867546ab1 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -114,32 +114,36 @@ export class InAppStoreService implements OnDestroy { this.numPointPricesById$.value ); - let receipt; - if (inAppProduct.transaction?.type === 'ios-appstore') { - receipt = inAppProduct.transaction.appStoreReceipt; - } - if (inAppProduct.transaction?.type === 'android-playstore') { - receipt = inAppProduct.transaction.receipt; - } - if (!receipt) return; - - try { - await this.diaBackendNumService - .purchaseNumPoints$(pointsToAdd, receipt) - .toPromise(); - inAppProduct.finish(); - - this.notifyUser( - this.translocoService.translate('wallets.buyCredits.xCreditsAdded', { - credits: pointsToAdd, - }) - ); - } catch (error) { - const errorMessage = this.translocoService.translate( - 'wallets.buyCredits.failedToAddCredits' - ); - this.errorService.toastError$(errorMessage).toPromise(); - } + alert(`Debug ${pointsToAdd} points added`); + receipt.finish(); + + return; // TODO: remove this line after UI testing + // let receipt; + // if (inAppProduct.transaction?.type === 'ios-appstore') { + // receipt = inAppProduct.transaction.appStoreReceipt; + // } + // if (inAppProduct.transaction?.type === 'android-playstore') { + // receipt = inAppProduct.transaction.receipt; + // } + // if (!receipt) return; + + // try { + // await this.diaBackendNumService + // .purchaseNumPoints$(pointsToAdd, receipt) + // .toPromise(); + // inAppProduct.finish(); + + // this.notifyUser( + // this.translocoService.translate('wallets.buyCredits.xCreditsAdded', { + // credits: pointsToAdd, + // }) + // ); + // } catch (error) { + // const errorMessage = this.translocoService.translate( + // 'wallets.buyCredits.failedToAddCredits' + // ); + // this.errorService.toastError$(errorMessage).toPromise(); + // } } // eslint-disable-next-line class-methods-use-this private extractProductFromReceipt(receipt: CdvPurchase.VerifiedReceipt) { From 413ab9ba1dc004b54367fc3bdd56747088822a77 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:46:42 +0800 Subject: [PATCH 16/26] WIP(buy-num.page): partially migrate to get working UI product.inAppProduct.state is no longer available in CdvPurchase.Product --- src/app/features/wallets/buy-num/buy-num.page.html | 5 +---- src/app/features/wallets/buy-num/buy-num.page.ts | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/app/features/wallets/buy-num/buy-num.page.html b/src/app/features/wallets/buy-num/buy-num.page.html index 2c7a832a9..9ef6dc1ea 100644 --- a/src/app/features/wallets/buy-num/buy-num.page.html +++ b/src/app/features/wallets/buy-num/buy-num.page.html @@ -25,7 +25,7 @@ >
- {{ product.inAppProduct.price }} + {{ product.inAppProduct.pricing?.price }}
@@ -38,9 +38,6 @@ {{ t('wallets.buyCredits.buyXCredits', { credits: product.numPoints }) }} - diff --git a/src/app/features/wallets/buy-num/buy-num.page.ts b/src/app/features/wallets/buy-num/buy-num.page.ts index 8eaae3e31..713319dc1 100644 --- a/src/app/features/wallets/buy-num/buy-num.page.ts +++ b/src/app/features/wallets/buy-num/buy-num.page.ts @@ -1,5 +1,4 @@ import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; -import { IAPProduct } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { AlertController } from '@ionic/angular'; import { TranslocoService } from '@ngneat/transloco'; import { combineLatest } from 'rxjs'; @@ -45,7 +44,7 @@ export class BuyNumPage implements OnInit { this.store.refreshNumPointsPricing(); } - purchase(product: IAPProduct) { + purchase(product: CdvPurchase.Product) { this.store.purchase(product); } From 910d648c60f4cada6b13cafa196c999cdf8164a9 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:49:47 +0800 Subject: [PATCH 17/26] WIP(in-app-store.service): fix pass inAppProduct.id instead of inAppProduct --- src/app/shared/in-app-store/in-app-store.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 867546ab1..4b113bdbb 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -32,7 +32,7 @@ export class InAppStoreService implements OnDestroy { map(([inAppProducts, numPointPricesById]) => { return inAppProducts.map(inAppProduct => { const numPoints = this.numPointsForProduct( - inAppProduct, + inAppProduct.id, numPointPricesById ); return { inAppProduct, numPoints }; From 108e5192708e40406166f6b329ddbe2899777fde Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Sun, 3 Dec 2023 23:50:13 +0800 Subject: [PATCH 18/26] WIP(app.module.ts): migration remove unused imports --- src/app/utils/in-app-purchase.ts | 75 +++++++++++++++----------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/src/app/utils/in-app-purchase.ts b/src/app/utils/in-app-purchase.ts index 38b0539d0..de74a70a2 100644 --- a/src/app/utils/in-app-purchase.ts +++ b/src/app/utils/in-app-purchase.ts @@ -1,5 +1,4 @@ import { isDevMode } from '@angular/core'; -import { IAPProduct } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { CaptureInAppProductIds } from '../shared/in-app-store/in-app-store.service'; export function truncateReceipt(recipt: string) { @@ -32,72 +31,66 @@ export function setupInAppPurchaseDebugPrint(tag: string) { * does not work in Web environment therefore we can use this util function * to pupulate with mock product to develop UI with different product states */ -export function generateMockInAppProducts(): IAPProduct[] { - const mockInAppProductSample: IAPProduct = { +export function generateMockInAppProducts(): CdvPurchase.Product[] { + const mockInAppProductSample: CdvPurchase.Product = { id: 'string', - alias: 'string', - type: 'string', - state: 'string', + className: 'Product', + platform: CdvPurchase.Platform.TEST, + offers: [], + pricing: undefined, + type: CdvPurchase.ProductType.CONSUMABLE, title: 'string', description: 'string', - priceMicros: 0, - price: 'string', - currency: 'string', - loaded: true, - valid: true, canPurchase: true, owned: true, - finish: () => ({}), - verify: () => ({}), - set: (_: string, __: any) => ({}), - stateChanged: () => ({}), - on: (_: string, __: any) => ({}), - once: (_: string, __: any) => ({}), - off: (_: any) => ({}), - trigger: (_: string, __: any) => ({}), + getOffer: () => undefined, + addOffer: () => ({} as CdvPurchase.Product), }; return [ { ...mockInAppProductSample, id: CaptureInAppProductIds.BRONZE_PACK, - title: 'Bronze Pack', - price: '0.99', - currency: 'USD', + title: '100 NumPoints', + description: '100 NumPoints', + pricing: undefined, canPurchase: true, - state: 'valid', - type: 'CONSUMABLE', + owned: true, + getOffer: () => undefined, + addOffer: () => ({} as CdvPurchase.Product), }, { ...mockInAppProductSample, - id: CaptureInAppProductIds.SLIVER_PACK, - title: 'Silver Pack', - price: '1.99', - state: 'valid', - canPurchase: false, - currency: 'USD', - type: 'CONSUMABLE', + title: '500 NumPoints', + description: '500 NumPoints', + pricing: undefined, + canPurchase: true, + owned: true, + getOffer: () => undefined, + addOffer: () => ({} as CdvPurchase.Product), }, { ...mockInAppProductSample, id: CaptureInAppProductIds.GOLD_PACK, - title: 'Gold Pack', - price: '2.99', - state: 'valid', - currency: 'USD', - type: 'CONSUMABLE', + title: '1000 NumPoints', + description: '1000 NumPoints', + pricing: undefined, canPurchase: true, + owned: true, + getOffer: () => undefined, + addOffer: () => ({} as CdvPurchase.Product), }, { ...mockInAppProductSample, id: CaptureInAppProductIds.PLATINUM_PACK, - title: 'Platinum Pack', - price: '3.99', - state: 'valid', - currency: 'USD', - type: 'CONSUMABLE', + title: '5000 NumPoints', + description: '5000 NumPoints', + pricing: undefined, canPurchase: true, + owned: true, + getOffer: () => undefined, + addOffer: () => ({} as CdvPurchase.Product), }, ]; } From 948184030acad7408808d62d303fbaaed13da5ac Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 4 Dec 2023 00:03:43 +0800 Subject: [PATCH 19/26] WIP(in-app-store.service): add missing method to initialize store --- src/app/shared/in-app-store/in-app-store.service.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 4b113bdbb..96f18e59c 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -60,11 +60,10 @@ export class InAppStoreService implements OnDestroy { try { await this.platform.ready(); - this.store = CdvPurchase.store; - this.regiseterStoreListeners(); this.registerStoreProducts(); + this.store.initialize(); } catch (error) { const errorMessage = this.translocoService.translate( 'inAppPurchase.failedToInitInAppStore' From 0dd3159900dedaf084385c1bcb893e11bbdb2a88 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 4 Dec 2023 01:23:46 +0800 Subject: [PATCH 20/26] WIP: shows loading indicator on buy num --- .../features/wallets/buy-num/buy-num.page.ts | 19 +++++++++++++++++-- .../in-app-store/in-app-store.service.ts | 11 ++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/app/features/wallets/buy-num/buy-num.page.ts b/src/app/features/wallets/buy-num/buy-num.page.ts index 713319dc1..800e0a896 100644 --- a/src/app/features/wallets/buy-num/buy-num.page.ts +++ b/src/app/features/wallets/buy-num/buy-num.page.ts @@ -1,10 +1,13 @@ import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { AlertController } from '@ionic/angular'; import { TranslocoService } from '@ngneat/transloco'; +import { UntilDestroy } from '@ngneat/until-destroy'; import { combineLatest } from 'rxjs'; -import { map, tap } from 'rxjs/operators'; +import { filter, first, map, tap } from 'rxjs/operators'; +import { BlockingActionService } from '../../../shared/blocking-action/blocking-action.service'; import { InAppStoreService } from '../../../shared/in-app-store/in-app-store.service'; +@UntilDestroy() @Component({ selector: 'app-buy-num', templateUrl: './buy-num.page.html', @@ -33,11 +36,14 @@ export class BuyNumPage implements OnInit { tap(_ => this.ref.detectChanges()) ); + readonly isProcessingOrder$ = this.store.isProcessingOrder$; + constructor( private readonly store: InAppStoreService, private readonly ref: ChangeDetectorRef, private readonly alertController: AlertController, - private readonly translocoService: TranslocoService + private readonly translocoService: TranslocoService, + private readonly blockingActionService: BlockingActionService ) {} ngOnInit() { @@ -45,9 +51,18 @@ export class BuyNumPage implements OnInit { } purchase(product: CdvPurchase.Product) { + this.showLoadingIndicatorUntillOrderIsProcessed(); this.store.purchase(product); } + private showLoadingIndicatorUntillOrderIsProcessed() { + const action$ = this.isProcessingOrder$.pipe( + filter(isProcessing => isProcessing === false), + first() + ); + this.blockingActionService.run$(action$).subscribe(); + } + async showNumPointsQuantity(numPoints: number) { const info = this.translocoService.translate( 'wallets.buyCredits.thisPackageIncludeXCredits', diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 96f18e59c..02b28bce0 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -40,6 +40,8 @@ export class InAppStoreService implements OnDestroy { }) ); + readonly isProcessingOrder$ = new BehaviorSubject(false); + private readonly appId = 'io.numbersprotocol.capturelite'; constructor( @@ -97,6 +99,7 @@ export class InAppStoreService implements OnDestroy { purchase(product: CdvPurchase.Product) { const offer = product.getOffer(); if (!offer) return; + this.isProcessingOrder$.next(true); this.store.order(offer); } @@ -114,6 +117,8 @@ export class InAppStoreService implements OnDestroy { ); alert(`Debug ${pointsToAdd} points added`); + + this.isProcessingOrder$.next(false); receipt.finish(); return; // TODO: remove this line after UI testing @@ -194,7 +199,11 @@ export class InAppStoreService implements OnDestroy { this.store.register(productsToRegister); } - private readonly onStoreError = (_: CdvPurchase.IError) => { + private readonly onStoreError = (error: CdvPurchase.IError) => { + this.isProcessingOrder$.next(false); + + if (error.message === 'The user cancelled the order.') return; + const errorMessage = this.translocoService.translate( 'inAppPurchase.inAppPurchaseErrorOcurred' ); From 3167c1375ffcd946e8932492896b8bbd22390d47 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 4 Dec 2023 01:38:48 +0800 Subject: [PATCH 21/26] WIP(in-app-store.service): migrate receipt extraction --- .../in-app-store/in-app-store.service.ts | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index 02b28bce0..daff08d51 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -116,21 +116,16 @@ export class InAppStoreService implements OnDestroy { this.numPointPricesById$.value ); + const storeReceipt = this.extractStoreReceipt(receipt); + alert(`Debug ${pointsToAdd} points added`); this.isProcessingOrder$.next(false); receipt.finish(); - return; // TODO: remove this line after UI testing - // let receipt; - // if (inAppProduct.transaction?.type === 'ios-appstore') { - // receipt = inAppProduct.transaction.appStoreReceipt; - // } - // if (inAppProduct.transaction?.type === 'android-playstore') { - // receipt = inAppProduct.transaction.receipt; - // } - // if (!receipt) return; + if (!storeReceipt) return; + return; // TODO: remove this line after UI testing // try { // await this.diaBackendNumService // .purchaseNumPoints$(pointsToAdd, receipt) @@ -149,6 +144,7 @@ export class InAppStoreService implements OnDestroy { // this.errorService.toastError$(errorMessage).toPromise(); // } } + // eslint-disable-next-line class-methods-use-this private extractProductFromReceipt(receipt: CdvPurchase.VerifiedReceipt) { for (const transaction of receipt.sourceReceipt.transactions) { @@ -162,6 +158,24 @@ export class InAppStoreService implements OnDestroy { return null; } + // eslint-disable-next-line class-methods-use-this + private extractStoreReceipt( + receipt: CdvPurchase.VerifiedReceipt + ): string | undefined { + const platform = receipt.sourceReceipt.platform; + + if (platform === CdvPurchase.Platform.APPLE_APPSTORE) { + // nativeData is not documented, but it is there (can be veified by console.log(receipt)) + return (receipt.sourceReceipt as any).nativeData.appStoreReceipt; + } + + if (platform === CdvPurchase.Platform.GOOGLE_PLAY) { + // nativePurchase is not documented, but it is there (can be veified by console.log(receipt)) + return (receipt.sourceReceipt.transactions[0] as any).nativePurchase + .receipt; + } + } + private async notifyUser(message: string) { return this.toastController .create({ message, duration: 700 }) From b9c368d7372702c80806e6b8d0dfcc141fe7ca4a Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 4 Dec 2023 03:08:59 +0800 Subject: [PATCH 22/26] WIP(in-app-store.service): migrate finishPurchase. By this commit basic purchase functionality is working. Duplicate calls are handle properly and user won't be given double NUM points. --- .../in-app-store/in-app-store.service.ts | 82 ++++++++++++------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/src/app/shared/in-app-store/in-app-store.service.ts b/src/app/shared/in-app-store/in-app-store.service.ts index daff08d51..71ae412b3 100644 --- a/src/app/shared/in-app-store/in-app-store.service.ts +++ b/src/app/shared/in-app-store/in-app-store.service.ts @@ -1,3 +1,4 @@ +import { HttpErrorResponse } from '@angular/common/http'; import { Injectable, OnDestroy } from '@angular/core'; import { Platform, ToastController } from '@ionic/angular'; import { TranslocoService } from '@ngneat/transloco'; @@ -105,44 +106,65 @@ export class InAppStoreService implements OnDestroy { private async finishPurchase(receipt: CdvPurchase.VerifiedReceipt) { const product = this.extractProductFromReceipt(receipt); - if (!product) { receipt.finish(); + this.isProcessingOrder$.next(false); return; } - const pointsToAdd = this.numPointsForProduct( - product.id, - this.numPointPricesById$.value - ); - const storeReceipt = this.extractStoreReceipt(receipt); + if (!storeReceipt) { + receipt.finish(); + this.isProcessingOrder$.next(false); + return; + } - alert(`Debug ${pointsToAdd} points added`); + try { + const pointsToAdd = this.numPointsForProduct( + product.id, + this.numPointPricesById$.value + ); - this.isProcessingOrder$.next(false); - receipt.finish(); - - if (!storeReceipt) return; - - return; // TODO: remove this line after UI testing - // try { - // await this.diaBackendNumService - // .purchaseNumPoints$(pointsToAdd, receipt) - // .toPromise(); - // inAppProduct.finish(); - - // this.notifyUser( - // this.translocoService.translate('wallets.buyCredits.xCreditsAdded', { - // credits: pointsToAdd, - // }) - // ); - // } catch (error) { - // const errorMessage = this.translocoService.translate( - // 'wallets.buyCredits.failedToAddCredits' - // ); - // this.errorService.toastError$(errorMessage).toPromise(); - // } + await this.diaBackendNumService + .purchaseNumPoints$(pointsToAdd, storeReceipt) + .toPromise(); + + receipt.finish(); + this.isProcessingOrder$.next(false); + + this.notifyUser( + this.translocoService.translate('wallets.buyCredits.xCreditsAdded', { + credits: pointsToAdd, + }) + ); + } catch (error) { + if ( + error instanceof HttpErrorResponse && + error.error.error?.type === 'duplicate_receipt_id' + ) { + /** + * The receipt has already been used to get NUM points. + * + * In case of duplicate receipt id, the user has already received the points + * and we can ignore the error. Duplicate receipt can happen if callbacks + * registered in CdvPurchase is called twice. Issue is more related to plugin itslef: + * https://github.com/j3k0/cordova-plugin-purchase/issues/1458 + * + * Thanks to our backend implementation, the user will not be given NUMs twice. + * In this case we just finish the receipt and make sure loading indicator is hidden. + */ + receipt.finish(); + this.isProcessingOrder$.next(false); + } else { + this.errorService + .toastError$( + this.translocoService.translate( + 'wallets.buyCredits.failedToAddCredits' + ) + ) + .toPromise(); + } + } } // eslint-disable-next-line class-methods-use-this From df3d818e42d05281093ed2f7140c3bfc3120e2b6 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 4 Dec 2023 03:19:50 +0800 Subject: [PATCH 23/26] WIP: remove unused InAppPurchase2 module --- src/app/app.component.spec.ts | 12 +----------- src/app/app.module.ts | 2 -- .../features/wallets/buy-num/buy-num.page.spec.ts | 8 -------- .../shared/in-app-store/in-app-store.service.spec.ts | 2 -- 4 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index d535634eb..4d3c14ca8 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -1,7 +1,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { TestBed, waitForAsync } from '@angular/core/testing'; -import { InAppPurchase2 } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { Platform } from '@ionic/angular'; import { AppComponent } from './app.component'; import { CapacitorPluginsTestingModule } from './shared/capacitor-plugins/capacitor-plugins-testing.module'; @@ -22,12 +21,6 @@ describe('AppComponent', () => { is: platformIsSpy, }); - const iap2SpyMethods = ['error', 'ready', 'when', 'refresh', 'off']; - const inAppPurchase2Spy = jasmine.createSpyObj( - 'InAppPurchase2', - iap2SpyMethods - ); - TestBed.configureTestingModule({ declarations: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], @@ -37,10 +30,7 @@ describe('AppComponent', () => { getTranslocoTestingModule(), MaterialTestingModule, ], - providers: [ - { provide: Platform, useValue: platformSpy }, - { provide: InAppPurchase2, useValue: inAppPurchase2Spy }, - ], + providers: [{ provide: Platform, useValue: platformSpy }], }).compileComponents(); }) ); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ea69db6d5..ed941933e 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -3,7 +3,6 @@ import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar'; import { BrowserModule, HammerModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouteReuseStrategy } from '@angular/router'; -import { InAppPurchase2 } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; import { FormlyModule } from '@ngx-formly/core'; import { FormlyMaterialModule } from '@ngx-formly/material'; @@ -36,7 +35,6 @@ import { SharedModule } from './shared/shared.module'; provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: { duration: 2500 }, }, - InAppPurchase2, ], bootstrap: [AppComponent], }) diff --git a/src/app/features/wallets/buy-num/buy-num.page.spec.ts b/src/app/features/wallets/buy-num/buy-num.page.spec.ts index a55dc6b13..9429bd718 100644 --- a/src/app/features/wallets/buy-num/buy-num.page.spec.ts +++ b/src/app/features/wallets/buy-num/buy-num.page.spec.ts @@ -1,5 +1,4 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { InAppPurchase2 } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { SharedTestingModule } from '../../../shared/shared-testing.module'; import { BuyNumPage } from './buy-num.page'; @@ -10,16 +9,9 @@ describe('BuyNumPage', () => { beforeEach( waitForAsync(() => { - const iap2SpyMethods = ['error', 'ready', 'when', 'refresh', 'off']; - const inAppPurchase2Spy = jasmine.createSpyObj( - 'InAppPurchase2', - iap2SpyMethods - ); - TestBed.configureTestingModule({ declarations: [BuyNumPage], imports: [SharedTestingModule], - providers: [{ provide: InAppPurchase2, useValue: inAppPurchase2Spy }], }).compileComponents(); fixture = TestBed.createComponent(BuyNumPage); diff --git a/src/app/shared/in-app-store/in-app-store.service.spec.ts b/src/app/shared/in-app-store/in-app-store.service.spec.ts index 37e304a94..f479b7174 100644 --- a/src/app/shared/in-app-store/in-app-store.service.spec.ts +++ b/src/app/shared/in-app-store/in-app-store.service.spec.ts @@ -1,5 +1,4 @@ import { TestBed } from '@angular/core/testing'; -import { InAppPurchase2 } from '@awesome-cordova-plugins/in-app-purchase-2/ngx'; import { SharedModule } from '../shared.module'; import { InAppStoreService } from './in-app-store.service'; @@ -10,7 +9,6 @@ describe('InAppStoreService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [SharedModule], - providers: [InAppPurchase2], }); service = TestBed.inject(InAppStoreService); }); From ecacfdbf9abef8add5c80f1b5ccaae5582f308e8 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 4 Dec 2023 03:31:53 +0800 Subject: [PATCH 24/26] WIP: bump android billing client to 5.2.1 after migrating cordova-plugin-purchase npx cap sync automatically bumps android billing client to version 5 which in turn solves issue mentioned before: https://app.asana.com/0/0/1206062906361649/1206062916657894/f --- android/app/capacitor.build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index 8c2576eae..6b66551e2 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -33,7 +33,7 @@ dependencies { implementation project(':appsflyer-capacitor-plugin') implementation project(':capacitor-blob-writer') implementation project(':capacitor-native-settings') - implementation "com.android.billingclient:billing:4.0.0" + implementation "com.android.billingclient:billing:5.2.1" } From 68196e55717539ba80a033b8d0f6ac59eb2c3211 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 4 Dec 2023 13:32:17 +0800 Subject: [PATCH 25/26] chore: bump app version to 0.87.1 --- android/app/build.gradle | 4 ++-- ios/App/App.xcodeproj/project.pbxproj | 8 ++++---- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 1aa66ef2c..c2d30e65b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "io.numbersprotocol.capturelite" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 870 - versionName "0.87.0" + versionCode 871 + versionName "0.87.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildFeatures { diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index fa79a5bc1..d08c49ea4 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -368,13 +368,13 @@ CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 870; + CURRENT_PROJECT_VERSION = 871; DEVELOPMENT_TEAM = G7NB5YCKAP; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = G7NB5YCKAP; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.87.0; + MARKETING_VERSION = 0.87.1; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = io.numbersprotocol.capturelite; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -395,13 +395,13 @@ CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 870; + CURRENT_PROJECT_VERSION = 871; DEVELOPMENT_TEAM = G7NB5YCKAP; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = G7NB5YCKAP; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.87.0; + MARKETING_VERSION = 0.87.1; PRODUCT_BUNDLE_IDENTIFIER = io.numbersprotocol.capturelite; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = NumbersAppDistributionV4; diff --git a/package-lock.json b/package-lock.json index 6407fee1d..25b71405e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "capture-lite", - "version": "0.87.0", + "version": "0.87.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "capture-lite", - "version": "0.87.0", + "version": "0.87.1", "dependencies": { "packages": "^0.0.8", "@angular/animations": "^14.2.0", diff --git a/package.json b/package.json index b4210371b..aeac9c949 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "capture-lite", - "version": "0.87.0", + "version": "0.87.1", "author": "numbersprotocol", "homepage": "https://numbersprotocol.io/", "scripts": { From a3e6c26225c86432b57d8701ce6e6da330ba4371 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 4 Dec 2023 14:40:02 +0800 Subject: [PATCH 26/26] chore: update CHANGELOG.md for 0.87.1 --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a0be3b59..48cd5d047 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.87.1] - 2023-12-04 + +### Fixed + +1. Fix in app purchase by migrating cordove-plugin-purchase to v13 (#3125) + ## [0.87.0] - 2023-11-30 ### Added @@ -2220,7 +2226,8 @@ This is the first release! _Capture Lite_ is a cross-platform app adapted from [ - Web - see the demo [here](https://github.com/numbersprotocol/capture-lite#demo-app) - Android - the APK file `app-debug.apk` is attached to this release -[unreleased]: https://github.com/numbersprotocol/capture-lite/compare/0.87.0...HEAD +[unreleased]: https://github.com/numbersprotocol/capture-lite/compare/0.87.1...HEAD +[0.87.1]: https://github.com/numbersprotocol/capture-lite/compare/0.87.0...0.87.1 [0.87.0]: https://github.com/numbersprotocol/capture-lite/compare/0.86.4...0.87.0 [0.86.4]: https://github.com/numbersprotocol/capture-lite/compare/0.83.2...0.86.4 [0.83.2]: https://github.com/numbersprotocol/capture-lite/compare/0.82.4...0.85.2