iOS 上的 React Native 应用内购买实现

问题描述 投票:0回答:1

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;

即使删除了支付和订阅功能,我目前在提交申请方面也面临着挑战。我尝试提交没有任何支付相关功能的应用程序,但它仍然面临拒绝。 因为应用程序内购买业务支付苹果指南

ios react-native in-app-purchase react-native-iap in-app-purchase-receipt
1个回答
0
投票

你能解决你的问题吗?在应用程序中购买 React Native 的香草是一件令人痛苦的事情。互联网上的文档非常糟糕

© www.soinside.com 2019 - 2024. All rights reserved.