Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Acknowledge purchase in Android failed #12

Open
valentin-debris opened this issue Nov 15, 2024 · 0 comments
Open

Acknowledge purchase in Android failed #12

valentin-debris opened this issue Nov 15, 2024 · 0 comments

Comments

@valentin-debris
Copy link

Description

Hello, I was contact by someone to upgrade his application to meet the Google requirement (using Google Play Billing >= 6.0.1 and API 34).
The app was on Expo@49 using the module expo-in-app-purchases which is abandonned, so I upgraded it to Expo@51 and want to use this repo (I tried with "react-native-iap" but always faced the error E_IAP_NOT_AVAILABLE on start-up).
Integrate this repo was pretty simple based on the sample here, but I faced a big issue.

The process almost works, the popup to pay appears, the dev card works and the test command is visible in Google Play Order, but after 3 minutes, the order is cancelled and refunded. The problem is that the order is not acknoledge by the app, so Google cancel it.

In the console log, I have the following error [Error: Received 2 arguments, but 1 was expected], which is trigger by calling finishTransaction().
After digging your code, the error is generated by return ExpoIapModule.consumeProduct(purchase.purchaseToken, developerPayloadAndroid); (here)
I never dev in kotlin but it seems this fonction consumeProduct only have one parameter, so I removed the last one (developerPayloadAndroid), and now the error disappeared and seems to aknoledge the payment (it wasn't cancelled after 3 minutes)

Expected Behavior

The payment is acknowledged and Google doesn't cancel it.

Environment:

  • expo-iap: 2.1.0
  • react-native: 0.74.5
  • expo : 51.0.39
  • Platform : Android 14 on real device

The app is very simple (only 1 item to buy) so I don't know if the fix I proposed is safe.


Additional Context

Here is the full code of my function, based on your example

import {
  initConnection,
  endConnection,
  finishTransaction,
  getProducts,
  purchaseErrorListener,
  purchaseUpdatedListener,
  requestPurchase,
} from 'expo-iap';

import { useEffect, useState, useRef } from 'react';
import { InteractionManager, Platform } from 'react-native';

export default (callback = () => {}) => {
  const items = Platform.select({
    ios: ['token_1'],
    android: ['token'],
  });

  const [connected, setConnected] = useState(false);
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(false);

  const packIDRef = useRef();

  useEffect(() => {
    const initIAP = async () => {
      if (await initConnection()) {
        setConnected(true);
      }

      const products = await getProducts(items);
      setProducts(products);
    };

    initIAP();

    return () => {
      endConnection();
    };
  }, []);

  useEffect(() => {
    const purchaseUpdatedSubs = purchaseUpdatedListener((purchase) => {
      const ackPurchase = async (purchase) => {
        try {
          await finishTransaction({ //<============== WHERE THE EROR COMES FROM
            purchase,
            isConsumable: true
          });
        } catch (e) {
          console.log(e);
        }
      };

      InteractionManager.runAfterInteractions(async () => {
        const receipt = purchase && purchase.transactionReceipt;

        if (receipt) {
          await ackPurchase(purchase);
          setLoading(false);
        }
      });
    });

    const purchaseErrorSubs = purchaseErrorListener((error) => {
      InteractionManager.runAfterInteractions(() => {
        setLoading(false);
      });
    });

    return () => {
      purchaseUpdatedSubs.remove();
      purchaseErrorSubs.remove();
      endConnection();
    };
  }, [packIDRef]);

  const buy = async (productId, packID) => {
    setLoading(true);
    packIDRef.current = packID;
    try {
      requestPurchase({ skus: [productId] });
    } catch (err) {
      setLoading(false);
    }
  };

  return { buy, products, loading };
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant