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

appAccountToken missing on the return of the getAvailablePurchases method #2434

Open
quentinNpApnl opened this issue May 11, 2023 · 15 comments

Comments

@quentinNpApnl
Copy link
Contributor

quentinNpApnl commented May 11, 2023

Description

appAccountToken is not on the return of the getAvailablePurchases method.

Expected Behavior

appAccountToken should be on the return of the getAvailablePurchases method.

Environment:

  • react-native-iap: 12.10.5
  • react-native: 0.67.1
  • Platforms: iOS

To Reproduce
Steps to reproduce the behavior:

export const getLastSubscription = async () => {
    const purchases = await RNIap.getAvailablePurchases({ automaticallyFinishRestoredTransactions: false })

    let lastSubscription = purchases?.filter(purchase => purchase?.transactionReceipt !== null)
    
    let uuid = Platform.select({
            ios: latestSubscription?.appAccountToken,
            android: latestSubscription?.obfuscatedAccountIdAndroid,
        })

    return {
        sku: lastSubscription?.productId,
        uuid // <------ null on iOS
    }
}

To fix the problem :
I added the followings fields on the types files

// file : types/index.ts

export interface ProductPurchase {
  productId: string;
  transactionId?: string;
  transactionDate: number;
  transactionReceipt: string;
  purchaseToken?: string;
  //iOS
  quantityIOS?: number;
  originalTransactionDateIOS?: number;
  originalTransactionIdentifierIOS?: string;
  verificationResultIOS?: string;
  appAccountToken?: string; // <---- I added this
  //Android
  productIds?: string[];
  dataAndroid?: string;
  signatureAndroid?: string;
  autoRenewingAndroid?: boolean;
  purchaseStateAndroid?: PurchaseStateAndroid;
  isAcknowledgedAndroid?: boolean;
  packageNameAndroid?: string;
  developerPayloadAndroid?: string;
  obfuscatedAccountIdAndroid?: string;
  obfuscatedProfileIdAndroid?: string;
  //Amazon
  userIdAmazon?: string;
  userMarketplaceAmazon?: string;
  userJsonAmazon?: string;
  isCanceledAmazon?: boolean;
}
// file : types/appleSk2.ts

export const transactionSk2ToPurchaseMap = ({
  id,
  originalPurchaseDate,
  productID,
  purchaseDate,
  purchasedQuantity,
  originalID,
  verificationResult,
  appAccountToken // <---- I added this
}: TransactionSk2): Purchase => {
  const purchase: Purchase = {
    productId: productID,
    transactionId: String(id),
    transactionDate: purchaseDate, //??
    transactionReceipt: '', // Not available
    purchaseToken: '', //Not available
    quantityIOS: purchasedQuantity,
    originalTransactionDateIOS: originalPurchaseDate,
    originalTransactionIdentifierIOS: originalID,
    verificationResultIOS: verificationResult ?? '',
    appAccountToken: appAccountToken, // <----- I added this
  };
  return purchase;
};

Can you add this to the method ?

@Prathameshlabde
Copy link

#2455 Can anyone please suggest on this issue Please ?

@quentinNpApnl
Copy link
Contributor Author

#2455 Can anyone please suggest on this issue Please ?

I added a workaround on the issue

@fodjan-philip
Copy link

I saw that the appAccountToken was added to the ProductPurchase TS interface, which is also used in the event sent to the purchaseUpdatedListener. However it seems like the appAccountToken is always undefined in that case?

Our setup is quite simple and the appAccountToken also appears in the App Store Server Notifications, so I don't think we did anything wrong there:

// somewhere on payment page
await requestSubscription({ ...purchase, appAccountToken: "some-uuid" });

// somewhere else
purchaseUpdatedListener((purchase) => purchase.appAccountToken); // always undefined

@quentinnippert
Copy link
Contributor

@fodjan-philip There's probably missing properties on the data sent from the ios event. Are you using Storekit 2 ? What is the version number of react-native-iap ? Do you have the same problem on Android with the obfuscatedAccountId ?

@fodjan-philip
Copy link

@quentinnippert I am using StoreKit 2 and the most recent version of react-native-iap (12.10.8). obfuscatedAccountId on Android works as expected in the purchaseUpdateListener.

On iOS, I send the following data to requestSubscription:

sku: 'some-product',
appAccountToken: 'some-token'

But I only receive the following data in the purchaseUpdateListener:

originalTransactionDateIOS: 12345,
originalTransactionIdentifierIOS: '12345',
productId: 'some-product',
transactionDate: 12345,
transactionId: '54321'
transactionReceipt: '...'

@quentinnippert
Copy link
Contributor

@fodjan-philip I'll try to take a look at this as soon as I have time for it !

@fodjan-philip
Copy link

@quentinnippert I think there was a misunderstanding on my side. Somehow I thought StoreKit 2 is used by default, but if I understand it correctly, it has to be activated with a setup() call? I only found that part in the migration guide for 11.0.0 by accident (never looked at the migration guides before because I started with v12 right away).

So with StoreKit 1, is it expected that I can send an appAccountToken but never get it back in the purchaseUpdateListener?

@quentinnippert
Copy link
Contributor

@fodjan-philip Sorry for the delay.
I'm not sure if you'll get you'll get the appAccountToken using StoreKit 1. It's retrieved on my project using StoreKit 2 and the last version of react-native-iap. Also make sure theappAccountToken is on a uuid format. Then, If you're handling AppStore Server Notification, you need to make sure that you received the appAccountToken on your backend.

@caoyongfeng0214
Copy link

@quentinnippert I think there was a misunderstanding on my side. Somehow I thought StoreKit 2 is used by default, but if I understand it correctly, it has to be activated with a setup() call? I only found that part in the migration guide for 11.0.0 by accident (never looked at the migration guides before because I started with v12 right away).

So with StoreKit 1, is it expected that I can send an appAccountToken but never get it back in the purchaseUpdateListener?

i am using StoreKit 2. appAccountToken doesn't seem to be passed correctly because I can't always buy correctly when I use withOffer, it seems to be a signature verification error caused by the absence of appAccountToken.

@quentinnippert
Copy link
Contributor

@caoyongfeng0214 Can you send me your code ?
Are you sending a string in UUID format ?

@caoyongfeng0214
Copy link

@caoyongfeng0214 Can you send me your code ? Are you sending a string in UUID format ?

Yes, it is a string.

const uuidv4 = require('uuid').v4;

const appAccountToken = uuidv4();

@quentinnippert
Copy link
Contributor

@caoyongfeng0214 Can you send me your code ? Are you sending a string in UUID format ?

Yes, it is a string.

const uuidv4 = require('uuid').v4;

const appAccountToken = uuidv4();

I need to see how you make your purchase with react-native-iap

@caoyongfeng0214
Copy link

@caoyongfeng0214 Can you send me your code ? Are you sending a string in UUID format ?

Yes, it is a string.

const uuidv4 = require('uuid').v4;

const appAccountToken = uuidv4();

I need to see how you make your purchase with react-native-iap

This is my code:

const uuidv4 = require('uuid').v4;

const appAccountToken = uuidv4();

const signResult = await http.post('https://domain/signOffer', { userName: appAccountToken });
/**
signResult:
    {
        userName: 'appAccountToken',
        withOffer: {
            identifier:'vip_free_1_month',
            keyIdentifier:'KEY_ID',
            nonce:'a-uuid',
            signature:'xxbcdxxbdijdggd......',
            timestamp: 12345678
        }
    }
**/

requestSubscription({
    sku: 'vip_month_1',
    appAccountToken: signResult.userName,
    withOffer: signResult.withOffer
});

@quentinnippert
Copy link
Contributor

> > > > @caoyongfeng0214 Can you send me your code ? Are you sending a string in UUID format ?

Yes, it is a string.

const uuidv4 = require('uuid').v4;

const appAccountToken = uuidv4();

I need to see how you make your purchase with react-native-iap

This is my code:

const uuidv4 = require('uuid').v4;

const appAccountToken = uuidv4();

const signResult = await http.post('https://domain/signOffer', { userName: appAccountToken });
/**
signResult:
    {
        userName: 'appAccountToken',
        withOffer: {
            identifier:'vip_free_1_month',
            keyIdentifier:'KEY_ID',
            nonce:'a-uuid',
            signature:'xxbcdxxbdijdggd......',
            timestamp: 12345678
        }
    }
**/

requestSubscription({
    sku: 'vip_month_1',
    appAccountToken: signResult.userName,
    withOffer: signResult.withOffer
});

Are you using setup({storekitMode: 'STOREKIT2_MODE'}) on app launch ? (maybe in your App.js ?)

Also, make sure to setup your app store server notification on version 2 on appstore connect > select your app > app information > scroll to Appstore Server Notification > edit your endpoint.
Capture d’écran 2023-11-28 à 22 02 36

@caoyongfeng0214
Copy link

@caoyongfeng0214 Can you send me your code ? Are you sending a string in UUID format ?

Yes, it is a string.

const uuidv4 = require('uuid').v4;

const appAccountToken = uuidv4();

I need to see how you make your purchase with react-native-iap

This is my code:

const uuidv4 = require('uuid').v4;

const appAccountToken = uuidv4();

const signResult = await http.post('https://domain/signOffer', { userName: appAccountToken });
/**
signResult:
    {
        userName: 'appAccountToken',
        withOffer: {
            identifier:'vip_free_1_month',
            keyIdentifier:'KEY_ID',
            nonce:'a-uuid',
            signature:'xxbcdxxbdijdggd......',
            timestamp: 12345678
        }
    }
**/

requestSubscription({
    sku: 'vip_month_1',
    appAccountToken: signResult.userName,
    withOffer: signResult.withOffer
});

Are you using setup({storekitMode: 'STOREKIT2_MODE'}) on app launch ? (maybe in your App.js ?)

Also, make sure to setup your app store server notification on version 2 on appstore connect > select your app > app information > scroll to Appstore Server Notification > edit your endpoint. Capture d’écran 2023-11-28 à 22 02 36

Yes, appAccountToken is a uuid. setup({storekitMode: 'STOREKIT2_MODE'}) has been added to the App.js.

If not bring withOffer, the purchase can be completed.

If bring withOffer, the message Unable to Purchase will pop up. There is a good chance that the signature verification failed.

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

5 participants