Quantcast
Channel: Active questions tagged react-native+ios - Stack Overflow
Viewing all articles
Browse latest Browse all 17664

React Native In-App Purchase Implementation on iOS

$
0
0

Hello Stack Overflow community,

I am currently working on a React Native application with a Node.js backend, targeting both Android and iOS platforms. Specifically, I am integrating in-app purchase functionality for auto-renewable subscriptions on the iOS platform. To achieve this, I am utilizing the react-native-iap library, and my implementation is in JavaScript.

I have successfully added subscriptions in the Apple Developer Console, and I am able to fetch them into my app. However, I am encountering an issue during the subscription process on iOS. After clicking on the product in the sandbox UI, a popup with subscription details, including a subscribe button and price, appears. Upon clicking the subscribe button, the system prompts for sign-in, and after entering valid credentials, the transaction does not complete.

Additionally, I am facing challenges in obtaining the purchase receipt. As a newcomer to both React Native and in-app purchases, I would greatly appreciate any guidance or insights on how to overcome these issues.

Below is the relevant snippet of my code:

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;

I am currently facing challenges with the submission of my application, even after removing payment and subscription functionalities. I have attempted to submit the app without any payment-related features, yet it continues to face rejection.coz in app purchase business payment apple guidelines


Viewing all articles
Browse latest Browse all 17664

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>