I am building a react native app and using react-native-iap
package for integrating IAP and subscriptions.
Here is my code:
const PurchaseIAP = () => {
const acknowledgePurchase = useCallback(async purchase => {
if (Platform.OS === 'android') {
try {
if (purchase && !purchase.isAcknowledgedAndroid) {
if (!purchase.purchaseToken) {
throw new Error('Purchase token is missing');
}
await acknowledgePurchaseAndroid({token: purchase.purchaseToken});
} else {
console.log(
'Purchase already acknowledged or invalid purchase object:',
purchase,
);
}
} catch (error) {
console.warn('Failed to acknowledge purchase:', error);
}
}
}, []);
const handlePurchaseUpdate = useCallback(
async purchase => {
console.log('Purchase update received:', purchase);
const receipt = purchase.transactionReceipt;
if (receipt) {
try {
if (Platform.OS === 'android') {
await acknowledgePurchase(purchase);
}
console.log('Purchase updated and acknowledged:', purchase);
const ackResult = await finishTransaction({
purchase,
isConsumable: true,
});
console.log('Transaction finished:', ackResult);
setLoading(true);
Alert.alert('Purchase Successful', 'Thank you for your purchase!', [
{
text: 'OK',
onPress: () => {
setLoading(false);
setTransactionFinished(true);
},
},
]);
} catch (ackErr) {
console.warn('Failed to finish transaction:', ackErr);
setTransactionFinished(false);
Alert.alert('Transaction Error', 'Failed to complete transaction.');
}
} else {
console.warn('Transaction receipt is missing:', purchase);
}
},
[acknowledgePurchase],
);
useEffect(() => {
const purchaseUpdateSubscription =
purchaseUpdatedListener(handlePurchaseUpdate);
return () => {
if (purchaseUpdateSubscription) {
purchaseUpdateSubscription.remove();
}
};
}, [handlePurchaseUpdate]);
useEffect(() => {
const initializeIAP = async () => {
try {
const result = await initConnection();
if (result) {
setIsIapReady(true);
console.log('IAP connection initialized');
await getAvailableProductsAndSubscriptions();
if (Platform.OS === 'android') {
await flushFailedPurchasesCachedAsPendingAndroid();
}
}
} catch (err) {
console.warn('Failed to initialize IAP', err);
showAlert('IAP Error', 'Failed to initialize in-app purchases.');
}
};
const getAvailableProductsAndSubscriptions = async () => {
if (getItemsRequest.current) {
return;
}
setLoading(true);
getItemsRequest.current = true;
try {
const productResult = await getProducts({skus: productIds});
const subscriptionResult = await getSubscriptions({
skus: subscriptionIds,
});
setProducts([...productResult, ...subscriptionResult]);
console.log('Products:', productResult);
console.log('Subscriptions:', subscriptionResult);
} catch (err) {
console.warn('Failed to get products or subscriptions', err);
console.log(
'Error',
'Failed to fetch product or subscription details.',
);
} finally {
setLoading(false);
getItemsRequest.current = false;
}
};
initializeIAP();
const purchaseErrorSubscription = purchaseErrorListener(purchaseError => {
console.log('Purchase error', purchaseError);
if (!alertVisible) {
showAlert('Purchase Error', purchaseError.message);
}
setAlertVisible(false);
setTransactionFinished(false);
// Handle error
});
return () => {
if (purchaseErrorSubscription) {
purchaseErrorSubscription.remove();
}
endConnection();
};
}, [showAlert, alertVisible, navigation, token]);
const handlePurchase = async product => {
if (!isIapReady) {
if (!alertVisible) {
showAlert('IAP not ready', 'Please wait for IAP to initialize.');
}
return;
}
if (products.length === 0) {
if (!alertVisible) {
showAlert('No Products', 'No products available for purchase.');
}
return;
}
try {
if (product.productType === 'subs' && Platform.OS === 'android') {
// console.log('Attempting to purchase subscription:', product.productId);
const offerToken = getOfferToken(product);
if (!offerToken) {
if (!alertVisible) {
showAlert(
'Offer Token Missing',
'No valid offer token found for this SKU.',
);
}
return;
}
console.log('productId', product.productId);
console.log('offerToken', offerToken);
await subscribe(product.productId, offerToken);
} else {
await makePurchase(product.productId);
}
} catch (err) {
console.warn('Purchase Failed', err);
if (!alertVisible) {
showAlert('Purchase failed', err.message);
}
}
};
const makePurchase = async sku => {
let request;
if (Platform.OS === 'android') {
request = {
skus: [sku],
obfuscatedAccountIdAndroid: token,
};
} else if (Platform.OS === 'ios') {
request = {
sku: sku,
appAccountToken: token,
};
}
console.log('purchase request 209', request);
try {
const purchase = await requestPurchase(request);
console.log('Purchase Result:', purchase);
if (!alertVisible) {
showAlert('Purchase Successful', 'Thank you for your purchase!');
}
setTransactionFinished(true);
} catch (err) {
console.warn('Purchase Failed', err);
setAlertVisible(false);
if (err.code !== 'E_USER_CANCELLED') {
Alert.alert('Purchase failed', err.message);
setAlertVisible(false);
} else {
console.log('Purchase error', err);
}
}
};
const subscribe = async (sku, offerToken) => {
try {
let subscriptionRequest;
if (Platform.OS === 'android') {
subscriptionRequest = {
sku,
...(offerToken && {subscriptionOffers: [{sku, offerToken}]}),
obfuscatedAccountIdAndroid: token,
};
} else if (Platform.OS === 'ios') {
subscriptionRequest = {
sku,
...(offerToken && {subscriptionOffers: [{sku, offerToken}]}),
appAccountToken: token,
};
}
console.log('Subscription Request:', subscriptionRequest);
const purchase = await requestSubscription(subscriptionRequest);
console.log('Subscription Purchase Result:', purchase);
if (!alertVisible) {
showAlert('Subscription Successful', 'Thank you for subscribing!');
}
setTransactionFinished(true);
} catch (err) {
console.warn('Purchase Failed', err);
console.error('Error details:', JSON.stringify(err, null, 2));
console.error('Error code:', err.code);
console.error('Error message:', err.message);
setAlertVisible(false);
if (err.code !== 'E_USER_CANCELLED') {
Alert.alert('Purchase failed', `${err.message}nCode: ${err.code}`);
} else {
console.log('User cancelled the purchase', err);
}
}
};
WARN Failed to finish transaction: [Error: Google is indicating that we have some issue connecting to payment.]
and also I am acknowledging purchase still I am getting acknowledged purchase = false.
"acknowledged":false
I tried googling complete method from initConnection IAP to completing transaction, but I don’t know where I am lacking and what causing error.
Axis Patel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.