Accepting payments in React Native

In this tutorial, we’ll be looking at how to accept payments within a React Native app.

An important aspect when creating an app or website is the ability to accept payments from its customers. Platforms such as the web, Android, and iOS already have well-supported APIs for payment gateways such as Stripe. But what about cross-platform frameworks like React Native?

Prerequisites

Basic knowledge of React Native is required. Although we’ll be using a bit of PHP, it’s optional because the code will be self-explanatory.

Development environment

You need to have PHP and MySQL installed on your machine. The easiest way to get the development environment is through Laravel Homestead. If you’re on Mac, you can get up and running even faster with Laravel Valet.

You also need a MySQL database manager for creating the database:

You also need to have an ngrok account for exposing the server to the internet.

Developer accounts

We will be using Stripe to process payments, so a Stripe account is required.

Optionally, you will also need to have the following if you want to use Google Pay and Apple Pay in production:

  • Google Play developer console account - you can actually use the Tipsi-Stripe library without a developer account if you use the test environment. But if you want to use it in production, you’ll need to have a Google Play developer console account which can accept payments.
  • Apple developer account - you need this if you want to use Apple Pay with Tipsi-Stripe. At the time of writing this tutorial, there are only a handful of countries in which Sandbox testing for Apple Pay is supported. This means you’ll have to use real credit cards for testing if you’re not living in one of those countries. As this tutorial won’t be covering how to set up Apple Pay on your developer account, be sure to read the Getting Started with Apple Pay guide.

Package versions

The following package versions are used in the app:

  • React Native 0.57.8
  • Tipsi-stripe 6.1.2

While the following are used in the backend:

  • Lumen framework 5.7
  • Stripe PHP 6.28

To ensure compatibility, start with the versions above before upgrading to the latest versions.

App overview

We’ll create a simple app which displays a product to be bought. The user can then pay for it with the credit card they have added to their Google Account. We will use Google Pay as a means for accepting the payment, and Stripe for processing it. If you’ve previously worked with Stripe for the web, the process is pretty much the same. Tipsi-Stripe provides a way to use either Google Pay, Apple Pay, or its custom React component for accepting the payment details. You will then use any of these methods to generate the token which you will submit to the app’s backend. This token allows you to charge the card added by the user.

Here’s what the app will look like:

You can find the source code on this GitHub repo.

Building the app

Start by creating a new React Native project and installing the dependencies:

    react-native init RNPay
    cd RNPay
    yarn add tipsi-stripe react-native-config axios
    react-native link

Once that’s done, add the config for enabling the Google Wallet API in the android/app/src/main/AndroidManifest.xml file. This allows you to use Google Pay within the app:

    <application>
      <meta-data
        android:name="com.google.android.gms.wallet.api.enabled"
        android:value="true" />
    </application>

Next, update the android/app/build.gradle file and add the path to React Native Config:

`apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"`

For iOS, please refer to the documentation:

Next, create a .env file at the root of the project directory and add your Stripe publishable key. If you’re testing, this can be the test credentials provided by Stripe. You can find your API keys here. Be sure to toggle Viewing Test Data if you want your test credentials:

    STRIPE_PUBLISHABLE_KEY=YOUR_STRIPE_PUBLISHABLE_KEY

Once that’s done, you’re now ready to work on the code. Start by opening the App.js file and add the following:

    import React, { Component } from 'react';
    import { View, Alert } from 'react-native';

    import stripe from 'tipsi-stripe';
    import Config from 'react-native-config';

    import ItemBox from './src/components/ItemBox';
    import pay from './src/helpers/pay';

    stripe.setOptions({
      publishableKey: Config.STRIPE_PUBLISHABLE_KEY,
      androidPayMode: 'test', // test || production
    });

The most important part in the above code is the setting of the options for Stripe. The publishableKey is basically the same key as the one you put on your JavaScript files when working on the web. androidPayMode is the mode to be used by Google Pay. test means that the requirements for using it won’t be as tight as when you’re on production. For example, the app doesn’t need to be uploaded in the Google Play Store. Your Google Play console developer account also don’t need to have Google Pay enabled. In fact, you don’t even need a developer account in order to try it out. You can find more info about it here.

Next, initialize the data to be used throughout the app. This includes the user’s access token which is used for authenticating the user’s request when we hit the endpoint for creating a charge. To simplify things we’re simply going to hardcode an existing access token that’s already in the database. I’ll show you how to create the database later on when we get to the backend:

    export default class App extends Component {

      constructor(props) {
        super(props);
        this.access_token = "AN EXISTING USER'S ACCESS TOKEN FROM YOUR DB";
        this.currency_code = 'USD'; // the currency to be used for processing the transaction
        // item data
        this.item = {
          title: 'Loop 720',
          price: 1,
          image: require('./src/images/loop720.jpg')
        };
      }

      state = {
        isPaying: false, // whether the user is currently paying for something 
        canPay: false // whether the user's device has the ability to pay using Google Pay
      }

      // next: add componentDidMount
    }

    const styles = {
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#FFF',
      }
    };

Next, we check if the user’s device can make payments with Google Pay:

    async componentDidMount() {
      const device_supported = await stripe.deviceSupportsAndroidPay();
      const can_make_android_pay_payments = await stripe.canMakeAndroidPayPayments();

      if (device_supported && can_make_android_pay_payments) {
        this.setState({
          canPay: true
        });
      }
    }

For the app’s UI we’re simply going to render a single item:

    render() {
      return (
        <View style={styles.container}>
          <ItemBox
            {...this.item}
            canPay={this.state.canPay}
            isPaying={this.state.isPaying}
            payAction={this.payItem} />
        </View>
      );
    }

Here’s the code for the ItemBox component:

    // src/components/ItemBox.js
    import React, { Component } from 'react';
    import { View, Text, Button, ActivityIndicator, Image } from 'react-native';

    const ItemBox = ({ title, price, image, canPay, isPaying, payAction }) => {

      return (
        <View>
          <Image
            style={styles.image}
            source={image} />

          <View style={styles.textContainer}>
            <Text style={styles.title}>{title}</Text>
          </View>

          <View style={styles.textContainer}>
            <Text style={styles.price}>${price.toFixed(2)}</Text>
          </View>

          {
            isPaying &&
            <ActivityIndicator size="large" color="#0000ff" />
          }

          <View style={styles.buttonContainer}>
          {
            canPay && !isPaying &&
            <Button
              onPress={payAction}
              title="Buy Now"
              color="#841584"
            />
          }

          {
            !canPay &&
            <View style={styles.alertContainer}>
              <Text style={styles.errorText}>Can't accept payments</Text>
            </View>
          }
          </View>

        </View>
      );

    }

    export default ItemBox;

    const styles = {
      image: {
        width: 170,
        height: 150
      },
      textContainer: {
        alignItems: 'center'
      },
      title: {
        fontSize: 20
      },
      price: {
        fontSize: 23,
        fontWeight: 'bold'
      },
      buttonContainer: {
        margin: 10
      },
      alertContainer: {
        width: 150
      },
      errorText: {
        color: 'red'
      }
    };

Back to the App.js file, add the function for paying for the item. This gets executed when the Buy Now button from the ItemBox component is clicked:

    // App.js
    payItem = async () => {

      this.setState({
        isPaying: true // show loader instead of the button
      });

      const token = await stripe.paymentRequestWithNativePay({
        total_price: this.item.price.toFixed(2),
        currency_code: this.currency_code,
        line_items: [
          {
            currency_code: this.currency_code,
            description: this.item.title,
            total_price: this.item.price.toFixed(2),
            unit_price: this.item.price.toFixed(2),
            quantity: '1',
          }
        ]
      });

      // next: add code for committing the charge into the server
    }

If you want to capture shipping information, you need to set the shipping_address_required option and set its value to true. Optionally, you can also set the shipping_countries to an array of country codes to limit the countries you want to ship to:

    shipping_countries: ['US', 'PH', 'SG']

Here’s what the value of token looks like when the request is successful:

    {  
       "card":{  
          "currency":null,
          "fingerprint":"xxxxxxxxxx",
          "funding":"credit",
          "addressZip":null,
          "brand":"MasterCard",
          "cardId":"card_xxxxxxxxxxx",
          "number":null,
          "addressState":null,
          "country":"US",
          "cvc":null,
          "expMonth":7,
          "addressLine1":null,
          "expYear":3040,
          "addressCountry":null,
          "name":"Wern Ancheta",
          "last4":"11xx",
          "addressLine2":null,
          "addressCity":null
       },
       "created":1546997773000,
       "used":false,
       "extra":{  
          "shippingContact":{  
             "postalCode":"2500",
             "name":"Wern Ancheta",
             "locality":"San Juan",
             "countryCode":"PH",
             "administrativeArea":"La Union",
             "address1":"Forest street"
          },
          "billingContact":{  

          }
       },
       "livemode":false,
       "tokenId":"tok_xxxxxxxx"
    }

For more examples, please refer to the example folder in Tipsi-Stripe’s GitHub repo. And for more info on how to use them, check out the following:

Do note that if you plan on using the paymentRequestWithNativePay method, you have to first determine the platform the app is running on because the options you need to pass to the method will differ based on the platform. This is one advantage of the paymentRequestWithCardForm because of its platform-agnostic API.

Next, send the request for creating a charge to the server:

    const response = await pay(this.item.price, this.item.title, this.access_token, token.tokenId);
    if (response) {
      Alert.alert("Done!", "Payment successful");
    } else {
      Alert.alert("Error occurred", "Something went wrong while processing payment. Please try again.");
    }

    this.setState({
      isPaying: false // show the Buy Now button again
    });

Next, create a src/helpers/pay.js file and add the following. This sends a POST request to the server which includes the relevant details for the payment transaction:

    import axios from 'axios';

    const endpoint = 'https://YOUR_NGROK_URL/charge';

    const pay = async (amount, description, access_token, token_id) => {
      const data = {
        'amount': amount,
        'description': description,
        'access_token': access_token,
        'token_id': token_id // the token generated by Stripe
      };

      const headers = {
        'Content-Type': 'application/json',
      };

      let response = false;
      try {
        let response_data = await axios.post(endpoint, data, { headers });
        return true;
      } catch (e) {
        console.log('server error: ', e);
      }

      return response;      
    }

    export default pay;

In the above code, we’re only sending four pieces of data to the server. But you can actually send more if you like. Note that you can actually fetch the same data returned by stripe.paymentRequestWithNativePay method call in the server by making a request to the Stripe API. This means you don’t actually need to submit things like the shipping address or the customer’s name in your request. So most likely, the additional data you submit here will be specific to your application.

Add the backend code

This part assumes that you’ve already set up your machine with either Laravel Homestead or Laravel Valet. This will give you the composer command which is used below to generate a new Lumen project:

    composer create-project --prefer-dist laravel/lumen RNPayBackend

If you can’t run composer globally, be sure to move it to your local bin folder or add it to your PATH.

Next, navigate inside the generated RNPayBackend directory and add the database config:

    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=rnpay
    DB_USERNAME=your_username
    DB_PASSWORD=your_password

The above config assumes that you have already created a database using a database manager of your choice. So be sure to create one with the same name as the value given to DB_DATABASE.

Also, add your Stripe secret key to the .env file:

    STRIPE_SECRET_KEY=YOUR_STRIPE_SECRET_KEY

Next, create a new database migration file. These files allow you to write some code for updating the database structure:

    php artisan make:migration create_users_table

Navigate inside the database/migrations directory and you will see the generated file. Add the following code to it:

    <?php
    use Illuminate\Support\Facades\Schema;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Database\Migrations\Migration;

    class CreateUsersTable extends Migration
    {
        public function up()
        {
            Schema::create('users', function (Blueprint $table) {
                $table->increments('id');
                $table->string('access_token'); // the user's access token
                $table->string('stripe_customer_id')->nullable(); 
                $table->timestamps(); // created_at and updated_at timestamp fields
            });
        }

        public function down()
        {
            Schema::dropIfExists('users');
        }
    }

Migrate the database using the new file. This creates a users table with the fields you specified above:

    php artisan migrate

Next, access the database using a MySQL database manager and add a dummy data in the users table. Leave the stripe_customer_id as blank and copy the access_token to the App.js file.

Next, install the Stripe PHP library:

    composer require stripe/stripe-php

While that’s doing its thing, update the bootstrap/app.php file and uncomment the following line. This enables us to use Facades. In simple terms, Facades are easy to remember class names which allow us to access underlying functionality such as logging or fetching data from the database:

    $app->withFacades();

Next, add the route for processing payments to the routes/web.php file. This is the endpoint that we’re hitting in the app earlier. This uses a controller to process the request:

    $router->post('/charge', 'PaymentController@createCharge');

Create the controller at app/Http/Controllers/PaymentController.php and add the following:

    <?php

    namespace App\Http\Controllers;
    use DB; // for talking to the database
    use Illuminate\Support\Facades\Log; // for logging
    use Illuminate\Http\Request; // for getting request data

    class PaymentController extends Controller
    {

      public function __construct() {
        \Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET_KEY')); 
      }

      // next: add code for creating a charge
    }

In the above code, we’ve added a __construct method. This sets the Stripe API key that we’re going to use. This gets executed everytime any of the methods in the PaymentController gets called.

Next, add the method for creating a charge. This gets executed every time a POST request is made to the /charge route. Here we pass the data which came from the app to Stripe’s API method for creating a charge. If the charge is successful, we return the success response to the app:

    public function createCharge(Request $request) {

      // get the data that was passed from the app  
      $amount = (int) $request->input('amount') * 100; // amount should be in cents
      $description = $request->input('description');
      $access_token = $request->input('access_token');
      $token = $request->input('token_id');

      // get the Stripe customer ID based on the access token
      $user = DB::table('users')
          ->where('access_token', $access_token)
          ->select('id', 'stripe_customer_id')
          ->first();

      // construct the data required by Stripe for creating a charge
      $payment = [
        'amount' => $amount, 
        'currency' => 'usd',
        'description' => $description,
        'customer' => $user->stripe_customer_id
      ];

      if (empty($user->stripe_customer_id)) {
        // next: add code for creating a Stripe customer
      }

      try {
        $charge = \Stripe\Charge::create($payment);
        return ['status' => 'ok']; // if the charge was successful
      } catch (\Exception $e) {
        Log::info("Cannot create charge for Stripe customer: " . $user->id);
      }

      return ['status' => 'not_ok']; // if the charge wasn't successful
    }

If there’s no Stripe customer ID associated with the user, it means that a Stripe customer hasn’t been created for the user yet. So to associate a customer with the provided payment info, we need to make a separate request to the Stripe API to create a customer. This is a necessary step for associating a payment from a specific customer. Even though the Stripe API allows you to just pass the $token_id when creating a charge, it isn’t really recommended. Especially if you expect to receive payments from the same person in the future:

    try {
      $customer = \Stripe\Customer::create([
        "source" => $token // the payment token received from the app
      ]);

      // update the user to include the Stripe customer ID
      DB::table('users')
        ->where('access_token', $access_token)
        ->update([
          'stripe_customer_id' => $customer->id
        ]);

      $payment['customer'] = $customer->id; // assign the ID of the newly created customer to the payment
    } catch (\Exception $e) {
      Log::info("Cannot create Stripe customer for user: " . $user->id);
    }

Lastly, expose the server to the internet using ngrok. If you use Laravel Valet, first you have to change the default top-level domain to be the same as the one we’re using:

    valet domain test

Next, navigate to the root of RNPayBackend and execute valet park. This will register rnpaybackend.test on your local host which you can then expose it using ngrok:

    ngrok http -host-header=rewrite rnpaybackend.test:80

If you used Laravel Homestead, you can log in to your Homestead machine via vagrant ssh and run share rnpay.test. This will use ngrok to expose the server.

Once that’s done, you can update the src/helpers/pay.js file in the app with the HTTPS URL from ngrok.

At this point, the app should be fully functional. Go ahead and run it:

    react-native run-android

Conclusion

In this tutorial, we learned how to use the Tipsi-Stripe library and the Lumen PHP framework to accept payments within a React Native app.

You can find the full source code on this GitHub repo.

#javascript #reactjs #react-native #laravel #php #ios

What is GEEK

Buddha Community

Accepting payments in React Native
Autumn  Blick

Autumn Blick

1598839687

How native is React Native? | React Native vs Native App Development

If you are undertaking a mobile app development for your start-up or enterprise, you are likely wondering whether to use React Native. As a popular development framework, React Native helps you to develop near-native mobile apps. However, you are probably also wondering how close you can get to a native app by using React Native. How native is React Native?

In the article, we discuss the similarities between native mobile development and development using React Native. We also touch upon where they differ and how to bridge the gaps. Read on.

A brief introduction to React Native

Let’s briefly set the context first. We will briefly touch upon what React Native is and how it differs from earlier hybrid frameworks.

React Native is a popular JavaScript framework that Facebook has created. You can use this open-source framework to code natively rendering Android and iOS mobile apps. You can use it to develop web apps too.

Facebook has developed React Native based on React, its JavaScript library. The first release of React Native came in March 2015. At the time of writing this article, the latest stable release of React Native is 0.62.0, and it was released in March 2020.

Although relatively new, React Native has acquired a high degree of popularity. The “Stack Overflow Developer Survey 2019” report identifies it as the 8th most loved framework. Facebook, Walmart, and Bloomberg are some of the top companies that use React Native.

The popularity of React Native comes from its advantages. Some of its advantages are as follows:

  • Performance: It delivers optimal performance.
  • Cross-platform development: You can develop both Android and iOS apps with it. The reuse of code expedites development and reduces costs.
  • UI design: React Native enables you to design simple and responsive UI for your mobile app.
  • 3rd party plugins: This framework supports 3rd party plugins.
  • Developer community: A vibrant community of developers support React Native.

Why React Native is fundamentally different from earlier hybrid frameworks

Are you wondering whether React Native is just another of those hybrid frameworks like Ionic or Cordova? It’s not! React Native is fundamentally different from these earlier hybrid frameworks.

React Native is very close to native. Consider the following aspects as described on the React Native website:

  • Access to many native platforms features: The primitives of React Native render to native platform UI. This means that your React Native app will use many native platform APIs as native apps would do.
  • Near-native user experience: React Native provides several native components, and these are platform agnostic.
  • The ease of accessing native APIs: React Native uses a declarative UI paradigm. This enables React Native to interact easily with native platform APIs since React Native wraps existing native code.

Due to these factors, React Native offers many more advantages compared to those earlier hybrid frameworks. We now review them.

#android app #frontend #ios app #mobile app development #benefits of react native #is react native good for mobile app development #native vs #pros and cons of react native #react mobile development #react native development #react native experience #react native framework #react native ios vs android #react native pros and cons #react native vs android #react native vs native #react native vs native performance #react vs native #why react native #why use react native

Juned Ghanchi

1621573085

React Native App Developers India, React Native App Development Company

Expand your user base by using react-native apps developed by our expert team for various platforms like Android, Android TV, iOS, macOS, tvOS, the Web, Windows, and UWP.

We help businesses to scale up the process and achieve greater performance by providing the best react native app development services. Our skilled and experienced team’s apps have delivered all the expected results for our clients across the world.

To achieve growth for your business, hire react native app developers in India. You can count on us for all the technical services and support.

#react native app development company india #react native app developers india #hire react native developers india #react native app development company #react native app developers #hire react native developers

Hire Dedicated React Native Developer

Have you ever thought of having your own app that runs smoothly over multiple platforms?

React Native is an open-source cross-platform mobile application framework which is a great option to create mobile apps for both Android and iOS. Hire Dedicated React Native Developer from top React Native development company, HourlyDeveloper.io to design a spectacular React Native application for your business.

Consult with experts:- https://bit.ly/2A8L4vz

#hire dedicated react native developer #react native development company #react native development services #react native development #react native developer #react native

Hire Dedicated React Native Developers - WebClues Infotech

Being one of the emerging frameworks for app development the need to develop react native apps has increased over the years.

Looking for a react native developer?

Worry not! WebClues infotech offers services to Hire React Native Developers for your app development needs. We at WebClues Infotech offer a wide range of Web & Mobile App Development services based o your business or Startup requirement for Android and iOS apps.

WebClues Infotech also has a flexible method of cost calculation for hiring react native developers such as Hourly, Weekly, or Project Basis.

Want to get your app idea into reality with a react native framework?

Get in touch with us.

Hire React Native Developer Now: https://www.webcluesinfotech.com/hire-react-native-app-developer/

For inquiry: https://www.webcluesinfotech.com/contact-us/

Email: sales@webcluesinfotech.com

#hire react native developers #hire dedicated react native developers #hire react native developer #hiring a react native developer #hire freelance react native developers #hire react native developers in 1 hour

Factors affecting the cost of hiring a React Native developer in USA - TopDevelopers.co

Want to develop app using React Native? Here are the tips that will help to reduce the cost of react native app development for you.
Cost is a major factor in helping entrepreneurs take decisions about investing in developing an app and the decision to hire react native app developers in USA can prove to be fruitful in the long run. Using react native for app development ensures a wide range of benefits to your business. Understanding your business and working on the aspects to strengthen business processes through a cost-efficient mobile app will be the key to success.

#best react native development companies from the us #top react native app development companies in usa #cost of hiring a react native developer in usa #top-notch react native developer in usa #best react native developers usa #react native