dooboolab-community / react-native-iap

In App Purchase module for React Native!
https://react-native-iap.dooboolab.com
MIT License
2.81k stars 642 forks source link

RNIapModule never found in React Native Modules #1017

Closed simplesthing closed 4 years ago

simplesthing commented 4 years ago

Version of react-native-iap

4.4.9

Version of react-native

0.61.5

Platforms you faced the error (IOS or Android or both?)

Android

Expected behavior

React NativeModeuls shows RNIAP in list of modules

Actual behavior

RNIAp not found

Tested environment (Emulator? Real Device?)

Emulator and Real Device

Steps to reproduce the behavior

Using expo framework, ejected workflow, running both locally with expo start as well as on a packaged and distributed APK from google play store, both show no RNAIP module found.

simplesthing commented 4 years ago
import "react-native-gesture-handler";
import React from "react";
import { Alert } from "react-native";
import AnimatedSplash from "react-native-animated-splash-screen";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import * as Font from "expo-font";
import { Ionicons } from "@expo/vector-icons";
import { AccountProvider } from "./contexts/account";
import Login from "./components/Login/Login";
import MainWindow from "./components/MainWindow";
import Registration from "./components/Login/Registration";
import Constants from "expo-constants";
import RNIap, {
  InAppPurchase,
  PurchaseError,
  acknowledgePurchaseAndroid,
  consumePurchaseAndroid,
  finishTransaction,
  finishTransactionIOS,
  purchaseErrorListener,
  purchaseUpdatedListener,
} from "react-native-iap";

import { NativeModules } from 'react-native';
const { RNIapModule } = NativeModules;

function hasIAP() {
  return !!NativeModules.RNIapModule;
}

const Stack = createStackNavigator();

const expoManaged = () => {
  return Constants.appOwnership === "expo";
};

const LoginStack = () => (
  <Stack.Navigator initialRouteName="Log in">
    <Stack.Screen
      name="Log in"
      component={Login}
      options={{ headerShown: false }}
    />
    <Stack.Screen
      name="Register"
      component={Registration}
      options={{ headerTitleAlign: "center" }}
    />
  </Stack.Navigator>
);

let purchaseUpdateSubscription;
let purchaseErrorSubscription;

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isReady: false,
      user: null,
      productList: null,
      logs: [],
    };
  }

  async componentDidMount() {

    let log = this.state.logs;
    log.push('appOwnership: ' + Constants.appOwnership);
    log.push('hasIAP() ' + hasIAP());
    log.push(JSON.stringify(NativeModules));

    await Font.loadAsync({
      Roboto: require("native-base/Fonts/Roboto.ttf"),
      Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"),
      ...Ionicons.font,
    });

    this.setState({ isReady: true });

    if (!expoManaged()) {
      try {
        const connection = await RNIap.initConnection();
        //   const consume = await RNIap.consumeAllItemsAndroid(); <- this fails, e.refreshItems is null
        log.push("connection: ", connection);
      } catch (err) {
        log.push("connection error: " + err.code, err.message);
      }

      log.push("setup purchase listener");
      purchaseUpdateSubscription = purchaseUpdatedListener(
        async (InAppPurchase) => {
          const receipt = purchase.transactionReceipt;
          if (receipt) {
            try {
              const ackResult = await finishTransaction(purchase);
            } catch (ackErr) {
              log.push("ackErr: ", ackErr);
            }
          }
        }
      );

      log.push("setup pucrahse error listener");
      purchaseErrorSubscription = purchaseErrorListener(
        (error: PurchaseError) => {
          console.log("purchaseErrorListener", error);
          Alert.alert("purchase error", JSON.stringify(error));
        }
      );
    }

    this.setState({ logs: log });
  }

  componentWillUnmount() {
    if (purchaseUpdateSubscription) {
      purchaseUpdateSubscription.remove();
      purchaseUpdateSubscription = null;
    }
    if (purchaseErrorSubscription) {
      purchaseErrorSubscription.remove();
      purchaseErrorSubscription = null;
    }
    RNIap.endConnection();
  }

  getStoreProducts = async () => {
    const itemSkus = Platform.select({
      ios: [],
      android: [
        "test_ticket",
        "android.test.purchased",
        "android.test.canceled",
        "android.test.refunded",
        "android.test.item_unavailable",
      ],
    });

    let log = this.state.logs;
    log.push("try getProducts" + JSON.stringify(itemSkus));

    try {
      const products = await RNIap.getProducts(itemSkus);
      log.push("Products: ", JSON.stringify(products));
      this.setState({ productList: products, logs: log });
    } catch (err) {
      log.push("Products error: " + err.code, err.message);
      this.setState({ logs: log });
    }
  };

  requestPurchase = async (sku) => {
    let log = this.state.logs;
    log.push('try request a purchase with sku: ' + sku);

    if(!expoManaged()) {
      try {
        RNIap.requestPurchase(sku);
      } catch (err) {
        log.push("request a purchase error: " + err.code, err.message);
      }
    }

    this.setState({ logs: log });
  };

  onLogin = () => {
    this.setState({ user: "username" });
  };

  render() {
    const accountContext = {
      user: this.state.user,
      onLogin: this.onLogin,
      productList: this.state.productList,
      logs: this.state.logs,
      getStoreProducts: this.getStoreProducts,
      requestPurchase: this.requestPurchase,
    };

    return (
      <AnimatedSplash
        isLoaded={this.state.isReady}
        logoImage={require("./assets/sansar-logo-only.png")}
        backgroundColor={"#141414"}
        logoHeight={150}
        logoWidth={150}
      >
        <AccountProvider value={accountContext}>
          <NavigationContainer>
            <Stack.Navigator headerMode="none">
              {this.state.user ? (
                <Stack.Screen name="Sansar" component={MainWindow} />
              ) : (
                <Stack.Screen name="Auth" component={LoginStack} />
              )}
            </Stack.Navigator>
          </NavigationContainer>
        </AccountProvider>
      </AnimatedSplash>
    );
  }
}
simplesthing commented 4 years ago

Ended up using expo-iap library instead closing