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) を呼び出します。 RGBA(0.0〜1.0)あるいは16進数カラーコードを設定することで各コンポーネントの色を変更することができます。16進数カラーコードで指定する場合は、React Nativeの processColor(hex) 関数を呼び出してください。

import { processColor } from "react-native";

const style = {
  labelTextColor: {
      r: 0.0,
      g: 0.4,
      b: 0.8,
      a: 0.6
  },
  inputTextColor: processColor("#004488"),
  submitButtonColor: processColor("#0055ff")
};

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

スタイル属性と反映されるコンポーネントの対応については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上で公開されています。