Skip to content

theopolisme/react-native-stripe-terminal

Repository files navigation

react-native-stripe-terminal

React Native wrapper for the Stripe Terminal SDK version 2. (iOS & Android compatible!)

Getting started

First, follow all Stripe instructions under "Install the iOS SDK" and/or "Install the Android SDK" (depending on your platform). Then:

$ npm install git+https://github.com/theopolisme/react-native-stripe-terminal.git --save

Mostly automatic installation

$ react-native link react-native-stripe-terminal

Manual installation

iOS

  1. In XCode, in the project navigator, right click Libraries âžś Add Files to [your project's name]
  2. Go to node_modules âžś react-native-stripe-terminal and add RNStripeTerminal.xcodeproj
  3. In XCode, in the project navigator, select your project. Add libRNStripeTerminal.a to your project's Build Phases âžś Link Binary With Libraries
  4. Run your project (Cmd+R)

Android

  1. Open up android/app/src/main/java/[...]/MainApplication.java
  • Add import com.reactlibrary.RNStripeTerminalPackage; to the imports at the top of the file
  • Add new RNStripeTerminalPackage() to the list returned by the getPackages() method
  1. Append the following lines to android/settings.gradle:
    include ':react-native-stripe-terminal'
    project(':react-native-stripe-terminal').projectDir = new File(rootProject.projectDir, 	'../node_modules/react-native-stripe-terminal/android')
    
  2. Insert the following line inside the dependencies block in android/app/build.gradle:
      compile project(':react-native-stripe-terminal')
    

Usage

The StripeTerminal object is a singleton. You must first call StripeTerminal.initialize and provide a function to fetch the connection token (see Stripe docs).

You must also have a method of creating and supplying a Terminal Location ID.

Basic usage

import StripeTerminal, {
  readerUpdateTypes, // contains the reader firmware update types
  simulatedCardTypes, // contains the simulated card types
} from "react-native-stripe-terminal";

// First, initialize the SDK
StripeTerminal.initialize({
  fetchConnectionToken: () => {
    return fetch("https://your.endpoint/terminal", { method: "POST" })
      .then((resp) => resp.json())
      .then((data) => data.secret);
  },
});

// Get a terminal location ID fromyour backend/Stripe API. This is required to establish a connection
// to the reader.
const locationId = "tml_*********";

// Add a listener to handle when readers are discovered.
// You could display the readers to the user to select, or just
// auto-connect to the first available reader.
const discoverListener = StripeTerminal.addReadersDiscoveredListener(
  (readers) => {
    if (readers.length) {
      StripeTerminal.connectReader(readers[0].serialNumber, locationId).then(
        () => {
          // reader is connected
          // now safe to call `StripeTerminal.createPaymentIntent`
        }
      );
    }
  }
);

// When you're ready, scan for readers
StripeTerminal.discoverReaders(
  StripeTerminal.DiscoveryMethodBluetoothProximity,
  0 // Use 1 for "simulated" mode when running in an emulator
);

// After a reader is connected, create a payment intent.
//
// Note: In `react-native-stripe-terminal`, `createPayment`
// abstracts `createPaymentIntent`, collectPaymentMethod`, and
// `confirmPaymentIntent` into a single method. If any of them fail,
// the Promise will be rejected. A resolved promise means that the
// payment was authorized & posted to Stripe and awaits capture.
StripeTerminal.createPayment({ amount: 1200, currency: "usd" })
  .then((intent) => {
    console.log("Payment intent created", intent);
  })
  .catch((error) => {
    console.log(error);
  });

// simulator config utils(only on android)
StripeTerminal.getSimulatorConfiguration().then((config) => {
  console.log("simulator config", config);
});

StripeTerminal.setSimulatorConfiguration(
  readerUpdateTypes.AVAILABLE, // update type(optional - pass null)
  "4000000000000069", // test card number(optional - pass null)
  simulatedCardTypes.AMEX // simulated card type(optional - pass null)
)
  .then((config) => {
    console.log("new simulator config", config);
  })
  .catch((err) => {
    console.log(err);
  });

// reader firmware update utils
StripeTerminal.installUpdate()
  .then((u) => {
    if (u && Object.keys(u).length > 0) {
      console.log("Update installed", u);
    } else {
      console.log("No updates found");
    }
  })
  .catch((e) => {
    console.log("Update not installed", e);
  });

StripeTerminal.abortInstallUpdate()
  .then((u) => {
    if (u && Object.keys(u).length > 0) {
      console.log("Update aborted", u);
    } else {
      console.log("No updates found");
    }
  })
  .catch((e) => {
    console.log("Update not aborted", e);
  });

// You can use the following listeners to update your interface with
// instructions for the user.

// This firing without error does not mean the SDK is not still discovering. Just that it found readers.
// The SDK must be actively discovering in order to connect.
const discoverCompleteListener =
  StripeTerminal.addAbortDiscoverReadersCompletionListener(({ error }) => {
    console.log("AbortDiscoverReadersCompletionListener");
    if (error) {
      this.setState({
        displayText: "Discovery completed with error: " + error,
      });
    }
  });

// Handle changes in reader connection status
const connectionStatusListener =
  StripeTerminal.addDidChangeConnectionStatusListener((event) => {
    // Can check event.status against constants like:
    if (event.status === StripeTerminal.ConnectionStatusConnecting) {
      this.setState({ displayText: "Connecting..." });
    }
    if (event.status === StripeTerminal.ConnectionStatusConnected) {
      this.setState({ displayText: "Connected successfully" });
    }
  });

// Handle unexpected disconnects
const disconnectListener =
  StripeTerminal.addDidReportUnexpectedReaderDisconnectListener((reader) => {
    this.setState({
      displayText:
        "Unexpectedly disconnected from reader " + reader.serialNumber,
    });
  });

// Pass StripeTerminal logs to the Javascript console, if needed
const logListener = StripeTerminal.addLogListener((log) => {
  console.log("[StripeTerminal] -- " + log);
});

const inputListener = StripeTerminal.addDidRequestReaderInputListener(
  (text) => {
    // `text` is a prompt like "Retry Card".
    this.setState({ displayText: text });
  }
);

// update listeners(refer https://stripe.com/docs/terminal/payments/connect-reader?terminal-sdk-platform=android&reader-type=bluetooth#update-reader)
// trigered when there are optional updates available
const updateListener = StripeTerminalModule.addDidReportAvailableUpdateListener(
  (data) => {
    console.log("updateListener", data);
  }
);

// triggered when installing update(this is the first step for required updates)
const startInstallingUpdateListener =
  StripeTerminalModule.addDidStartInstallingUpdateListener((data) => {
    console.log("didStartInstallingUpdateListener", data);
  });

// reports update progress
const didReportReaderSoftwareUpdateProgressListener =
  StripeTerminalModule.addDidReportReaderSoftwareUpdateProgressListener(
    (data) => {
      console.log("didReportReaderSoftwareUpdateProgress", data);
    }
  );

// triggered after the update is installed or aborted
const finishInstallingUpdateListener =
  StripeTerminalModule.addDidFinishInstallingUpdateListener((data) => {
    console.log("didFinishInstallingUpdateListener", data);
  });

// Make sure you remove the listeners when you're done
// (e.g. in componentWillUnmount).
discoverListener.remove();
connectionStatusListener.remove();
disconnectListener.remove();
logListener.remove();
inputListener.remove();
updateListener.remove();
startInstallingUpdateListener.remove();
didReportReaderSoftwareUpdateProgressListener.remove();
finishInstallingUpdateListener.remove();

Hooks usage

If you're running React Native ^0.59 / React ^16.8.0, you can use Hooks to seamlessly integrate Stripe Terminal into your React Native application.

import StripeTerminal, {
  useStripeTerminal,
  useStripeTerminalCreatePayment,
} from "react-native-stripe-terminal";

// Somewhere early in your application...
StripeTerminal.initialize({
  fetchConnectionToken: () => {
    return fetch("https://your.endpoint/terminal", { method: "POST" })
      .then((resp) => resp.json())
      .then((data) => data.secret);
  },
});

// Then, inside your components...
function PaymentScreen() {
  const {
    connectionStatus,
    connectedReader,
    paymentStatus,
    cardInserted,
    readerInputOptions,
    readerInputPrompt,
  } = useStripeTerminalState();
}

// And when you're finally read to *collect* a payment...
function CollectPaymentScreen() {
  const {
    connectionStatus,
    connectedReader,
    paymentStatus,
    cardInserted,
    readerInputOptions,
    readerInputPrompt,
  } = useStripeTerminalCreatePayment({
    amount: 123,
    description: "Test payment",
    onSuccess: (result) => {
      Alert.alert("Payment received", JSON.stringify(result));
    },
    onFailure: (err) => {
      Alert.alert("Failed to create payment", JSON.stringify(err));
    },
  });
}

Acknowledgements

About

React Native bindings for the Stripe Terminal SDK. (Unofficial)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published