skip to Main Content

I am trying to implement Android Billing 4.0.0 on my Android React Native app.

I have tried implementing the below line into my build.gradle (app):

implementation 'com.android.billingclient:billing:4.0.0' 

However, my React Native In App Purchase (RNIAP) has stopped working when I include the above line.

On my JS code I have the following line (you can see the full file below if needed):

const products = await RNIap.getProducts(itemSkus);

However, when I add this line the RNIap.getProducts await never returns anything and the code following this line is not executed. This line seems to get stuck.

When I remove the above line, the RNIap.getProducts works and displays the In App Purchase. However, if i remove the above line, Google Play Console displays ‘please upgrade to billing library version 4 or newer to publish this app’ – and therefore i can’t upload the new app.

I know it’s not an emulator issue as I have published the app with the above line and in the live environment the IAP is still not returned.

I have included the below in my AndroidManifest.xml

<uses-permission android:name="com.android.vending.BILLING" />

Everything works correctly on iOS.

Below is my code:

(Note: i have changed the package name & in-app purchase name for security reasons)

iap.js

import React, { Component } from "react";
import {
    View,
    Text,
    StyleSheet,
    Platform,
    PixelRatio,
} from "react-native";
import {Header,Left,Right,Icon,Content,Grid,Row,Col,Container,H1,Button,Footer} from 'native-base';
import LinearGradient from 'react-native-linear-gradient';

//Redux imports
import { connect } from "react-redux";
import { toggle } from '../../Reducers/toggle';

//In-app Purchase import
import * as RNIap from 'react-native-iap';

const itemSkus = Platform.select({
  ios: [
    'example.for_stackoverflow.ios',
  ],
  android: [
    'example.for_stackoverflow.android',
  ],
});


class Iap extends Component {
  constructor(props) {
    console.log(itemSkus);
    super(props);

    this.state = {
      productList: [],
      receipt: '',
      availableItemsMessage: '',
    };
  }

  state = {
    toggle: this.props.toggle.togglePremium || false,
  };


  handleChange = ( toggle ) => {
    this.setState({ toggle });
  };

  async componentDidMount() {
    try {
      const result = await RNIap.initConnection();
      console.log('result', result);
    } catch (err) {
      console.warn(err.code, err.message);
    }
    this.getItems();
  }

  //after purcahse to to the finish transaction page.
  goToNext = () => {
    this.props.navigation.navigate('Logout', {
      receipt: this.state.receipt,
    });
  }

  getItems = async() => {
    try {
      console.log(itemSkus + ' check itemSkus');
      const products = await RNIap.getProducts(itemSkus);
      //const subscriptions = await RNIap.getSubscriptions(itemSkus);
      // const products = await RNIap.getSubscriptions(itemSkus);
      console.log(products +  'check Products');
      this.setState({ productList: products });
    } catch (err) {
      console.log(err.message + ' err.message');
      console.warn(err.code, err.message);
    }
  }

  buyItem = async(sku) => {
  //console.info('buyItem: ' + sku);
  // const purchase = await RNIap.buyProduct(sku);
  // const products = await RNIap.buySubscription(sku);
  // const purchase = await RNIap.buyProductWithoutFinishTransaction(sku);
  try {
    const purchase: any = await RNIap.buyProduct(sku);
    this.setState({ receipt: purchase.transactionReceipt }, () => this.goToNext());
  } catch (err) {
    //console.warn(err.code, err.message);
    const subscription = RNIap.addAdditionalSuccessPurchaseListenerIOS(async (purchase) => {
      this.setState({ receipt: purchase.transactionReceipt }, () => this.goToNext());
      subscription.remove();
    });
  }
}


  getPurchases = async() => {
  try {
    console.log('get hit, and when??');
    const purchases = await RNIap.getAvailablePurchases();
    let restoredTitles = '';
    let coins = CoinStore.getCount();
    purchases.forEach(purchase => {
      if (purchase.productId == '4dot6OVER01') {
        this.setState({ togglePremium: true });
        restoredTitles += 'Premium Version';
      }
      else if (purchase.productId == 'android.test.purchased') {
        console.log(purchase.productId);
        this.setState({ togglePremium: true });
        restoredTitles += 'Premium Version';
      }
    })
    Alert.alert('Restore Successful', 'You successfully restored the following purchases: ' + restoredTitles);
  } catch(err) {
    //console.warn(err); // standardized err.code and err.message available
    Alert.alert(err.message);
  }
}


    static navigationOptions = {
      drawerIcon : ({tintColor}) => (
        <Icon name="ios-star-outline" style={{fontSize: 24, color: tintColor}} />
      )
    }

    getPrice = (priceString) => {
      const price = JSON.parse(priceString);
      //return (<H1 style={styles.textHeaderNumber}>${price}</H1>)
      return(<Text style={styles.buttonTextBackWhite}>${price}</Text>)
    }

    getTitle = (titleString) => {

      const title = JSON.parse(titleString);
      return(<Row><H1 style={styles.textHeader}>{title}</H1></Row>)
    }

    getDescription = (descString) => {

      const desc = JSON.parse(descString);
      return(<Row><Text style={styles.textDesc}>{desc}</Text></Row>)
    }

    render() {
      const purchase = this.props.toggle.togglePremium;
      const { productList, receipt, availableItemsMessage } = this.state;
      console.log(productList + ' check productList');
      const receipt100 = receipt.substring(0, 100);
        return (

                <Col size={1}>



                      <Row><Text style={styles.textHeader}>Cricket Over Counter Premium</Text></Row>
                      <Row><Text style={styles.textDesc}>Cricket Umpire Over and Ball Counter upgrade to premium to allow all features for the entire innings!</Text></Row>


                  {

                    productList.map((product, i) => {
                      console.log(product + ' check product.');
                      return (
                        <Row key={i} style={{
                          flexDirection: 'column', alignItems: 'center',
                        }}>

                          <Button rounded large warning style={styles.largeButtonGreen}
                              onPress={() => this.buyItem(product.productId)} >
                              {this.getPrice(JSON.stringify(product.price))}
                            </Button>
                        </Row>
                  );
              })
            }


                </Col>
        );
    }
}

const mapStateToProps = state => ({
  toggle: state.toggle,
});

export default connect(mapStateToProps)(Iap);

package.json

{
  "name": "ExampleForStackOverflow",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "@invertase/react-native-apple-authentication": "^2.1.2",
    "@react-native-async-storage/async-storage": "^1.13.4",
    "@react-native-firebase/app": "^10.8.0",
    "@react-native-firebase/auth": "^10.8.0",
    "@react-native-firebase/firestore": "^10.8.0",
    "@react-native-google-signin/google-signin": "^7.0.0-alpha.3",
    "@react-native-picker/picker": "^1.16.7",
    "@react-navigation/drawer": "^5.12.3",
    "@react-navigation/native": "^5.9.2",
    "native-base": "^2.15.2",
    "react": "16.13.1",
    "react-compose": "^2.0.0",
    "react-native": "0.63.5",
    "react-native-animatable": "^1.3.3",
    "react-native-apple-authentication": "^2.0.0",
    "react-native-cli": "^2.0.1",
    "react-native-dotenv": "^3.3.1",
    "react-native-draggable-flatlist": "^3.0.7",
    "react-native-elements": "^3.2.0",
    "react-native-gesture-handler": "^1.10.1",
    "react-native-haptic-feedback": "^1.11.0",
    "react-native-iap": "^5.2.14",
    "react-native-keep-awake": "^4.0.0",
    "react-native-linear-gradient": "^2.5.6",
    "react-native-reanimated": "^1.13.4",
    "react-native-restart": "0.0.24",
    "react-native-safe-area-context": "^3.1.9",
    "react-native-safe-area-view": "^1.1.1",
    "react-native-screens": "^2.17.1",
    "react-native-scroll-into-view": "^2.0.2",
    "react-native-splash-screen": "^3.2.0",
    "react-native-swipe-list-view": "^3.2.9",
    "react-native-swipeable-item": "^2.0.2",
    "react-native-switch": "^2.0.0",
    "react-native-vector-icons": "^8.0.0",
    "react-native-webview": "^11.2.3",
    "react-navigation": "^4.4.3",
    "react-navigation-drawer": "^2.6.0",
    "react-redux": "^7.2.2",
    "redux": "^4.0.5",
    "redux-devtools-extension": "^2.13.8",
    "redux-logger": "^3.0.6",
    "redux-persist": "^6.0.0",
    "redux-thunk": "^2.3.0",
    "tcomb-form-native": "^0.6.20"
  },
  "devDependencies": {
    "@babel/core": "^7.8.4",
    "@babel/runtime": "^7.8.4",
    "@react-native-community/eslint-config": "^1.1.0",
    "babel-jest": "^25.1.0",
    "eslint": "^6.5.1",
    "jest": "^25.1.0",
    "metro-react-native-babel-preset": "^0.59.0",
    "react-test-renderer": "16.13.1"
  },
  "jest": {
    "preset": "react-native"
  }
}

Hopefully someone has experienced a similar issue and can help me with a solution.

Thanks,
Andrew

2

Answers


  1. Chosen as BEST ANSWER

    I figured out the issue.

    I am on "react-native 0.63.5. I had react-native-iap 5.2.14 installed - which doesn't support Android Billing Library 4.0.0.

    Because i'm on a React Native versions less than 0.65, i have to update my react-native-iap package to v7.5.6 (as thats the newest version that supports react native <0.65 AND android billing library 4.0.0.

    So for anyone that might come across this issue:

    RN < 0.65 - upgrade to react-native-iap 7.5.6. do this by updating react-native-iap version on your package.json file and running npm install

    RN >= 0.65 - try updating to the latest stable version of react-native-iap by updating react-native-iap version on your package.json file and running npm install


  2. Yes it works for me with billing library version 4.0.0 and 7.5.6 version is also stable for iOS and android ,if any query please comment !

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search