react-native-iap
react-native-iap copied to clipboard
`appAccountToken` missing on the return of the `getAvailablePurchases` method
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 ?
https://github.com/dooboolab-community/react-native-iap/issues/2455 Can anyone please suggest on this issue Please ?
#2455 Can anyone please suggest on this issue Please ?
I added a workaround on the issue
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
@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 ?
@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: '...'
@fodjan-philip I'll try to take a look at this as soon as I have time for it !
@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?
@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.
@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
appAccountTokenbut never get it back in thepurchaseUpdateListener?
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.
@caoyongfeng0214 Can you send me your code ? Are you sending a string in UUID format ?
@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();
@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 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
});
> > > > @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-iapThis 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.
@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-iapThis 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 yourApp.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.
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.
