Stack Overflow 社区您好,
我目前正在开发一个带有 Node.js 后端的 React Native 应用程序,针对 Android 和 iOS 平台。具体来说,我正在 iOS 平台上集成自动续订订阅的应用内购买功能。为了实现这一目标,我使用了 react-native-iap 库,并且我的实现是用 JavaScript 实现的。
我已在 Apple 开发者控制台中成功添加订阅,并且可以将它们提取到我的应用程序中。但是,我在 iOS 上的订阅过程中遇到了问题。单击沙盒 UI 中的产品后,会出现一个包含订阅详细信息的弹出窗口,包括订阅按钮和价格。点击订阅按钮后,系统会提示登录,输入有效凭据后,交易并未完成。
此外,我在获取购买收据方面面临挑战。作为 React Native 和应用内购买的新手,我将非常感谢任何有关如何克服这些问题的指导或见解。
下面是我的代码的相关片段:
import React, { useEffect, useState } from 'react';
import { View, Text, Button, StyleSheet, Alert, Platform } from 'react-native';
import {
useIAP,
validateReceiptIos,
finishTransaction,
purchaseErrorListener,
purchaseUpdatedListener,
clearTransactionIOS,
} from 'react-native-iap';
import axios from 'axios';
import { ITUNES_SHARED_SECRET } from "@env";
const SubscriptionScreen = ({ navigation }) => {
const {
requestSubscription,
getSubscriptions,
currentPurchase,
purchaseHistory,
} = useIAP();
const [subscriptionStatus, setSubscriptionStatus] = useState(false);
const [loading, setLoading] = useState(false);
useEffect(() => {
handleGetSubscriptions();
setupPurchaseListeners(); // Setup purchase listeners on mount
}, []);
useEffect(() => {
if (purchaseHistory && purchaseHistory.length > 0) {
const isSubscribed = purchaseHistory.some((purchase) =>
subscriptionSkus.includes(purchase.productId)
);
if (isSubscribed) {
setSubscriptionStatus(true);
}
}
}, [purchaseHistory]);
const subscriptionSkus = Platform.select({
# ios: ['subscriptionProductID
'],
});
const handleGetSubscriptions = async () => {
try {
await getSubscriptions({ skus: subscriptionSkus });
} catch (error) {
console.error('Error getting subscriptions:', error);
}
};
const handleBuySubscription = async (productId) => {
try {
setLoading(true);
// Request subscription
const purchase = await requestSubscription({
sku: productId,
...(Platform.OS === 'ios' && {
andDangerouslyFinishTransactionAutomaticallyIOS: false,
}),
});
// Note: finishTransaction should be handled within purchaseUpdatedListener
if (purchase.transactionState === 'Purchased') {
const receipt = purchase.transactionReceipt;
await handleValidateReceipt(receipt);
navigation.navigate('IndexPage');
} else {
console.warn('Transaction state:', purchase.transactionState);
}
} catch (err) {
console.error(err.code, err.message);
} finally {
setLoading(false);
}
};
const handleValidateReceipt = async (receipt) => {
try {
const isTestEnvironment = false;
const response = await validateReceiptIos(
{
'receipt-data': receipt,
password: ITUNES_SHARED_SECRET,
},
isTestEnvironment
);
if (response && response.status === 0) {
const serverValidationResult = await validateReceiptOnServer(receipt);
if (serverValidationResult.valid) {
setSubscriptionStatus(true);
Alert.alert('Subscription Purchased', 'Thank you for subscribing!');
} else {
console.warn('Server validation failed');
}
} else {
console.warn('Receipt validation failed');
}
} catch (error) {
console.error('Error during receipt validation:', error);
}
};
const validateReceiptOnServer = async (receipt) => {
try {
const response = await axios.post('YOUR_SERVER_ENDPOINT', { receipt });
return response.data;
} catch (error) {
console.error('Error validating receipt on server:', error);
return { valid: false };
}
};
const setupPurchaseListeners = () => {
// Listen for purchase errors
const purchaseErrorSubscription = purchaseErrorListener((error) => {
console.warn('purchaseErrorListener', error);
});
// Listen for purchase updates
const purchaseUpdateSubscription = purchaseUpdatedListener((purchase) => {
console.log('purchaseUpdatedListener', purchase);
if (purchase.transactionState === 'Purchased') {
const receipt = purchase.transactionReceipt;
handleValidateReceipt(receipt);
finishTransaction({ purchase, isConsumable: false });
}
});
return () => {
// Remove the listeners on unmount
purchaseErrorSubscription.remove();
purchaseUpdateSubscription.remove();
};
};
useEffect(() => {
const checkCurrentPurchase = async () => {
if (currentPurchase) {
const receipt = currentPurchase.transactionReceipt;
if (receipt) {
await handleValidateReceipt(receipt);
try {
await finishTransaction({
purchase: currentPurchase,
isConsumable: false,
});
} catch (err) {
console.warn(err.code, err.message);
}
}
}
};
checkCurrentPurchase();
}, [currentPurchase, finishTransaction]);
const handleClearTransactions = async () => {
try {
await clearTransactionIOS();
console.log('Cleared pending transactions.');
} catch (error) {
console.error('Error while clearing transactions:', error);
}
};
return (
<View style={styles.container}>
<Text>{subscriptionStatus ? 'Subscribed' : 'Not Subscribed'}</Text>
{subscriptionSkus.map((sku) => (
<Button
key={sku}
title={`Purchase ${sku}`}
onPress={() => handleBuySubscription(sku)}
/>
))}
<Button title="Clear Transactions" onPress={handleClearTransactions} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
export default SubscriptionScreen;
即使删除了支付和订阅功能,我目前在提交申请方面也面临着挑战。我尝试提交没有任何支付相关功能的应用程序,但它仍然面临拒绝。 因为应用程序内购买业务支付苹果指南
你能解决你的问题吗?在应用程序中购买 React Native 的香草是一件令人痛苦的事情。互联网上的文档非常糟糕