PeterStaev / nativescript-purchase

:moneybag: A NativeScript plugin for making in-app purchases!
Apache License 2.0
83 stars 28 forks source link

nativeValue is undefined #84

Closed Psionyx closed 4 years ago

Psionyx commented 5 years ago

I'm running this in a NativeScript Angular app on an iOS Device. I'm able to retrieve my products, along with prices and description from Apple. However, when go to purchase an item I get : CONSOLE ERROR [native code]: ERROR TypeError: undefined is not an object (evaluating 'product.nativeValue')

I'm initializing the products in app.component.ts, in-app-purchase.component.ts respectively:

import { Component, OnInit, ViewChild } from "@angular/core";
import { NavigationEnd, Router } from "@angular/router";
import { RouterExtensions } from "nativescript-angular/router";
import { DrawerTransitionBase, RadSideDrawer, SlideInOnTopTransition } from "nativescript-ui-sidedrawer";
import { filter } from "rxjs/operators";
import * as app from "tns-core-modules/application";
import { UseYearService } from "~/app/services/use-year-calculator.service";
import { PointCalculatorService } from "~/app/services/points-calculator.service";
import * as purchase from "nativescript-purchase";
import { Product } from "nativescript-purchase/product";
(global as any).purchaseInitPromise = purchase.init(["com.codebluedatasolutions.mydvcpoints.2020Planning"]);
@Component({
    moduleId: module.id,
    selector: "ns-app",
    templateUrl: "app.component.html"
})
export class AppComponent implements OnInit {
    private _activatedUrl: string;
    private _sideDrawerTransition: DrawerTransitionBase;
    private database;
    constructor(private router: Router, private routerExtensions: RouterExtensions) {
        // Use the component constructor to inject services.
    }

    ngOnInit(): void {
        this._activatedUrl = "/home";
        this._sideDrawerTransition = new SlideInOnTopTransition();

        this.router.events
        .pipe(filter((event: any) => event instanceof NavigationEnd))
        .subscribe((event: NavigationEnd) => this._activatedUrl = event.urlAfterRedirects);
    }

    get sideDrawerTransition(): DrawerTransitionBase {
        return this._sideDrawerTransition;
    }

    isComponentSelected(url: string): boolean {
        return this._activatedUrl === url;
    }

    onNavItemTap(navItemRoute: string): void {
        this.routerExtensions.navigate([navItemRoute], {
            transition: {
                name: "fade"
            }
        });

        const sideDrawer = <RadSideDrawer>app.getRootView();
        sideDrawer.closeDrawer();
    }

}
import { Component, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { Location } from "@angular/common";
import { Http, Request, RequestMethod } from "@angular/http";
import * as applicationSettings from "application-settings";
import * as purchase from "nativescript-purchase";
import { Transaction, TransactionState } from "nativescript-purchase/transaction";
import { Product } from "nativescript-purchase/product";
import { ItemEventData } from "ui/list-view";
import {Observable} from 'rxjs';
import { EventData } from "tns-core-modules/data/observable";

@Component({
    selector: "purchase",
    templateUrl: "./in-app-purchase.component.html",
    styleUrls: []
})
export class InAppPurchaseComponent implements OnInit {

    public itemList: Array<Product>;

    public constructor() {
        purchase.getProducts()
        .then((res) => {
            this.itemList = res;
            this.itemList.forEach((product, index)=>{
                console.log("Found Product");
                console.log(JSON.stringify(this.itemList[index]));
            })
        })
        .catch((e) => console.log(e));

        purchase.on(purchase.transactionUpdatedEvent, (transaction: Transaction) => {
            if (transaction.transactionState === TransactionState.Restored) {
                applicationSettings.setBoolean(transaction.productIdentifier, true); /* 1 */
            }
            if (transaction.transactionState === TransactionState.Purchased) {
                if (transaction.productIdentifier.indexOf(".2020") >= 0) { /* 2 */
                    purchase.consumePurchase(transaction.transactionReceipt) /* 3 */
                        .then((responseCode) => {
                            if (responseCode === 0) {
                                // Provision your user with their digital goods bought. 

                            }
                        })
                        .catch((e) => console.log(e));
                }
                else {
                    applicationSettings.setBoolean(transaction.productIdentifier, true); /* 4 */
                }
            }    
        });
    }

    public ngOnInit() {

    }

    onProductTap(data: ItemEventData) {
        //let product = this.itemList[data.index] as Product;
        if (purchase.canMakePayments()) {
            // NOTE: 'product' must be the same instance as the one returned from getProducts()
            console.log("This account can make payments");
            purchase.buyProduct(this.itemList[data.index]);
        }
        else {
            console.log("This account cannot make payments");
            alert("Sorry, your account is not eligible to make payments!");
        }
    }
    onRestoreTap() {
        purchase.restorePurchases();
    }
}

However when I log the product, All of the other values are available but nativeValue is null: nativeValue:{} Do I need to set the values to nativeValue?

PeterStaev commented 5 years ago

Hey @Psionyx , nativeValue is a native object, so you can't really log it afaik. And per your description it does not log null so it is not null đŸ˜‰

Psionyx commented 5 years ago

Ok that makes sense. So then it's undefined according to the error message. Am I doing something that loses the type of the native object?

PeterStaev commented 5 years ago

Not that I can see. But you also never use the purchaseInitPromise you need to ensure that the plugin is initialized before calling getProducts. Also from the error seems the product itself is null, but not 100% sure.

Psionyx commented 5 years ago

11 line of the first set of code I placed is where I run that which is in app.component.ts
But I'm reimporting in in-app-purchase.component.ts so maybe that's the problem. Let me play around with it a bit

PeterStaev commented 5 years ago

On L11 you initialize the promise, but you are not using it anywhere else. You need to have code similar to the one in the readme:

import { Product } from "nativescript-purchase/product";

(global as any).purchaseInitPromise.then(() => {
    purchase.getProducts().then((products: Array<Product>) => {
        products.forEach((product: Product) => {
            console.log(product.productIdentifier);
            console.log(product.localizedTitle);
            console.log(product.priceFormatted);
        });
    });
});
PeterStaev commented 4 years ago

No further response so closing this one for now. In case you still have problems, please provide more details.