React Native での利用

React Native を利用したモバイルアプリケーションで PAY.JP を利用する場合は、 PAY.JP SDK React Nativeプラグイン をご利用ください。 これは PAY.JP Mobile SDK を React Native アプリケーションから呼び出すためのプラグインで、以下の機能が利用できます。

ライブラリの追加

プロジェクト構成

まず、React Native プロジェクトにプラグインを導入する手順について説明します。 npx react-native init AwesomeProject で作成される、以下のような構成の React Native プロジェクトを前提にしています。

.
├── App.js
├── __tests__
├── android
├── app.json
├── babel.config.js
├── index.js
├── ios
├── metro.config.js
├── node_modules
├── package.json
└── yarn.lock

なお、プラグインにはネイティブモジュールが含まれているため、現時点では Expo のManaged workflowには対応していません。

インストール

npm または yarn で最新のパッケージを追加します。

npm install --save payjp-react-native

ネイティブモジュールのセットアップ

次にネイティブモジュールのセットアップを行います。

React Native 0.60 以降のバージョンでは、Autolinking という機能により、パッケージのインストール時に自動でリンクされます。そのため、 ios ディレクトリに移動して pod install するだけでネイティブモジュールのセットアップが完了します。

cd ios
pod install

React Native 0.60 未満のバージョンの場合は、以下のように手動で react-native link を実行したのち、 pod install を行います。

npx react-native link payjp-react-native
cd ios
pod install

Swiftファイルとヘッダーの追加

iOS SDK は Swift で記述されているため、アプリのプロジェクトで Swift コードが呼び出せるように以下の作業を行います。

まず ios/AwesomeProject.xcodeproj を開きます。 左側のナビゲーターのアプリの AppDelegate.h などがある階層で右クリックし New File... を選択します。

新規で作成するファイルの種類を確認されるので、Swift ファイルを選択します。名前は何でもよく、ここでは Empty.swift とします(特に何も記述する必要はなく、作成したままで問題ありません)。

作成すると、Objective-C と Swift が混在するプロジェクトに必要なヘッダーファイルの作成を確認されます。 ここで Create Bridging Header を選択すると、Xcode がヘッダーファイルの設定を自動的に行います。

これでライブラリのセットアップは完了です。

SDKの初期化

カードフォームを利用する場合も、Apple Pay を利用する場合も、SDK の初期設定を行います。PAY.JP ダッシュボードのAPIページから取得した公開鍵を設定します。

以下のサンプルコードではテスト公開鍵を利用しています。

import { PayjpCore } from "payjp-react-native";

PayjpCore.init({ publicKey: 'pk_test_0383a1b8f91e8a6e3ea0e2a9' })
    .then(() => console.log('payjp init ok'))
    .catch(e => console.warn('payjp init error', e));

クレジットカード決済のためのカードフォームを利用する

ここでは、React Native アプリケーションからカードフォームを呼び出し、カード情報から支払いなどに必要なトークンを作成する方法を説明します(トークン化することでカード情報を直接扱うことなく安全に支払い処理を行うことができます)。

カードフォームイメージ

iOS Android

iOSの事前準備

カードフォームでは、クレジットカードをカメラで読み取る機能を提供しています。 この機能はデバイスのカメラを利用するため、iOS アプリの場合、なぜカメラ利用が必要なのかをユーザーに明示する必要があります(Android ではこの設定は不要です)。

Xcode で iOS のプロジェクト(ios/AwesomeProject.xcodeproj)を開きます。

Info.plistNSCameraUsageDescription というキーで説明を追加します。

これで、ユーザーがアプリで初めてカメラを利用する際に、ここで設定した文言が表示されるようになります。

カードフォームを呼び出す

PayjpCardForm.startCardForm() を呼び出して PAY.JP のカードフォームを起動します。

import React from "react";
import { View, Button } from "react-native";
import { PayjpCardForm } from "payjp-react-native";

const SampleScreen = () => {
  return (
    <>
      <Button
        title="カードを追加する"
        onPress={(): void => { PayjpCardForm.startCardForm({ cardFormType: "cardDisplay" }); }}
      />
    </>
  );
};

カードフォームは 2 種類の表示タイプを CardFormType によって指定できます。何も指定しない場合は multiLine が適用されます。

CardFormType iOS(CardFormViewType) Android(CardFormFace)
multiLine .labelStyled FACE_MULTI_LINE
cardDisplay .displayStyled FACE_CARD_DISPLAY

表示タイプについては iOS SDKの導入ガイドAndroid SDKの導入ガイド をご確認ください。

カードフォームの操作結果を受け取る

次に、ユーザーの操作によってカードフォームが更新されたときの処理を実装します。

PayjpCardForm.onCardFormUpdate() の引数にリスナー関数を含むオブジェクトを渡すことで、更新を受け取ることができます。

たとえば、ユーザーが入力を完了すると、カード情報からトークンが生成されます。 このトークンを使って支払いを作成したり顧客を作成したりといった処理を行います。

onCardFormUpdate() に渡すオブジェクトの onCardFormProducedToken にトークンをサーバーに送信する処理を記述します。

PayjpCardForm.onCardFormUpdate({
    onCardFormCanceled: () => {
        console.log("PAY.JP card form canceled");
    },
    onCardFormCompleted: () => {
        console.log("PAY.JP card form completed");
    },
    onCardFormProducedToken: token => {
        console.log("PAY.JP token => ", token);
        // トークンをサーバーに送信する
        sendTokenToServer(token);
    }
});

onCardFormProducedToken の他にも、カードフォームがキャンセルされたとき実行する onCardFormCanceled 、カードフォームが完了したとき実行する onCardFormCompleted があります。

コンポーネント内でリスナーを追加・削除する

PayjpCardForm.onCardFormUpdate() は追加したリスナーを解除する関数オブジェクトを返します。

React コンポーネント内で呼び出す場合、React Hooks や componentDidMount/componentWillUnmount などのライフサイクルメソッド内で、返却された関数を呼び出してメモリーリークを防ぐようにしてください。

以下は React Hooks の Effects を利用した例です。 useEffect の返すクリーンアップ関数内で登録したリスナーを削除します。

import React, { useEffect } from "react";
import { View, Button } from "react-native";
import { PayjpCardForm } from "payjp-react-native";

const SampleScreen = () => {
  useEffect(() => {
    const unsubscribeCardForm = PayjpCardForm.onCardFormUpdate(/** 省略 */);
    return () => {
      // クリーンアップ関数内で登録したリスナーを削除
      unsubscribeCardForm();
    };
  }, []);
  return (
    <>
      <Button
        title="カードを追加する"
        onPress={(): void => { PayjpCardForm.startCardForm(); }}
      />
    </>
  );
};

カードフォームを完了する

onCardFormProducedToken が呼び出されるとき、カードフォームは終了せずに待機している状態です。そのため、このまま完了するか、エラーを表示して再度ユーザーに入力してもらうかを指定する必要があります。

トークンをサーバーに送信しカードフォームを終了するには、 PayjpCardForm.completeCardForm() を呼び出します。

もし、何らかの問題(たとえば通信エラーなど)によってトークンの送信に失敗した場合は、 PayjpCardForm.showTokenProcessingError(message) を呼び出しカードフォームにエラーメッセージを表示します。

PayjpCardForm.onCardFormUpdate({
    onCardFormCanceled: () => {},
    onCardFormCompleted: () => {},
    onCardFormProducedToken: token => {
        sendTokenToServer(token)
          .then(() => {
            // トークンの送信に成功したらカードフォームを完了する
            return PayjpCardForm.completeCardForm();
          })
          .catch(e => {
            // エラーメッセージを表示する
            return PayjpCardForm.showTokenProcessingError(convertMessage(e))
          });
    }
});

カードフォームの見た目を変更する

iOS

iOS でカードフォームのスタイルを変更するには、 PayjpCardForm.setIOSCardFormStyle(style) を呼び出します。

import { Platform, PlatformColor } from "react-native";

const style = {
  labelTextColor: PlatformColor("label"),
  inputTextColor: "rgba(255, 0, 255, 1.0)",
  submitButtonColor: "#0055ff",
};

if (Platform.OS === "ios") {
  await PayjpCardForm.setIOSCardFormStyle(style);
}

各カラーは、React Native がサポートするカラー表現を用いて指定できます。指定できる形式については公式のリファレンスを参照してください。

スタイル属性と反映されるコンポーネントの対応については、iOS SDKの導入ガイドをご確認ください。

Android

Android では、カードフォームのスタイルは Theme によって制御されています。カードフォームが参照する Theme を上書きすることでカスタマイズできます。

カードフォームの色を変更する場合は、まず android/app/src/main/res/values/colors.xml に使用するカラーの宣言を追加します。カラーの指定については Android の公式リファレンスもあわせてご確認ください。

<resources>
    <color name="primaryColor">#ff5252</color>
    <color name="primaryLightColor">#ff867f</color>
    <color name="primaryDarkColor">#c50e29</color>
    <color name="secondaryColor">#ffc400</color>
    <color name="secondaryLightColor">#fff64f</color>
    <color name="secondaryDarkColor">#c79400</color>
    <color name="primaryTextColor">#424242</color>
    <color name="secondaryTextColor">#37474f</color>
</resources>

その他のリソースタイプ | Android デベロッパー | Android Developers

次に、 android/app/src/main/res/values/styles.xml でカードフォームの Theme を上書きする宣言を追加します。先に追加したカラーはここで参照します。

<resources>
    <!-- 省略 -->

    <!-- 以下を追加 -->
    <style name="Payjp.Theme.CardForm" parent="Payjp.Theme.BaseCardForm">
        <!-- 例 -->
        <item name="colorPrimary">@color/primaryColor</item>
        <item name="colorPrimaryDark">@color/primaryDarkColor</item>
        <item name="colorSecondary">@color/secondaryColor</item>
    </style>
</resources>

スタイル属性と反映されるコンポーネントの対応については、Android SDKの導入ガイドをご確認ください。

Apple Payのアプリ内決済に利用する

Apple Pay をアプリに組み込むにあたって、はじめにApple Pay の利用の準備をご確認ください。

また、ボタンの表示や UI については、Apple のガイドラインを必ず確認するようにしてください。

Introduction - Apple Pay - Human Interface Guidelines - Apple Developer

ここでは、SDK の初期設定をした後に、Apple Pay を利用して支払いに必要なトークンを作成する処理の実装手順について説明します。

Apple Payが利用可能かチェックする

実際に Apple Pay のペイメントシートをリクエストする前に、端末が Apple Pay を利用可能な状況かどうかを確認します。端末が Apple Pay をサポートしていない、ペアレンタルコントロールによって制限されているなどの場合、 PayjpApplePay.isApplePayAvailable() は Promise で false を返します。

PayjpApplePay.isApplePayAvailable()
  .then(available => {
    // trueならApple Payの支払いが可能
  });

Apple Payのペイメントシートを表示する

PayjpApplePay.makeApplePayToken() に商品の名称など支払いに必要な情報を渡して、ペイメントシートをリクエストします。 appleMerchantId には Xcode の設定で有効化したマーチャント ID を設定してください。

PayjpApplePay.makeApplePayToken({
    appleMerchantId: "merchant.com.example",
    currencyCode: "JPY",
    countryCode: "JP",
    summaryItemLabel: "PAY.JP T-shirt",
    summaryItemAmount: "100",
    requiredBillingAddress: false
});

Apple Payの操作結果を受け取る

PayjpApplePay.onApplePayUpdate() の引数にリスナー関数を含むオブジェクトを渡し、操作結果を受け取ります。

PayjpApplePay.onApplePayUpdate({
    onApplePayCompleted: () => console.log("PAY.JP ApplePay completed.") },
    onApplePayFailedRequestToken: error => {
        console.warn("error => ", error);
        PayjpApplePay.completeApplePay(false, error.errorMessage);
    },
    onApplePayProducedToken: token => {
        console.log("PAY.JP token => ", token);
        sendTokenToServer(token)
          .then(() => {
            return PayjpApplePay.completeApplePay(true);
          })
          .catch(e => {
            return PayjpApplePay.completeApplePay(false, convertMessage(e))
          });
    }
});

ユーザーが必要な情報を入力し Apple Pay による支払いが承認されると、Apple Pay のペイメントトークンが発行されます。PAY.JP SDK はこのペイメントトークンから PAY.JP での支払いなどに利用する PAY.JP トークンを作成します。

onApplePayProducedToken はこのトークンの作成に成功したとき呼び出されるリスナーで、引数にトークンが渡されます。このトークンは支払い処理に利用するため、リスナー内でサーバーに送信する処理を実装してください。

トークンの送信処理に成功した場合は PayjpCardForm.completeApplePay(isSuccess, errorMessage) の第1引数に true を、送信処理に失敗した場合は false を指定して呼び出します。

onApplePayFailedRequestToken は、Apple Pay のペイメントトークンから PAY.JP のトークンを生成する際に問題があったとき呼び出されるリスナーです。この場合も PayjpCardForm.completeApplePay(isSuccess, errorMessage) の第1引数に false を指定して呼び出すようにしてください。

onApplePayCompleted は、Apple Pay による支払いが完了したとき呼び出されるリスナーです。

onApplePayProducedToken あるいは onApplePayFailedRequestToken が呼び出されるとき、 Apple Payのペイメントシートは終了せずに待機している状態です。完了するには必ず PayjpCardForm.completeApplePay(isSuccess, errorMessage) を呼び出す必要があります。

注: iOSシミュレーターで実行時には、ペイメントトークンは空の値になりますので、実機で実行してください。

コンポーネント内でApple Payのリスナーの取り扱い

PayjpCardForm.onApplePayUpdate() は追加したリスナーを解除する関数オブジェクトを返します。

React コンポーネント内で呼び出す場合、カードフォームのリスナー同様、返却された関数を呼び出してリスナーを削除するようにしてください。

ソースコード・サンプルコード

ソースコード・サンプルアプリケーションは GitHub 上で公開されています。