クレジットカード入力フォームを作る際のtips

[サロン前日・当日予約アプリPopcorn](https://play.google.com/store/apps/details?id=com.coubic.popcorn&hl=ja)ではクレジットカード（VISA, MasterCard）による事前決済を導入しています。
本記事では、Androidアプリにクレジットカード入力フォームを作った際の細かいtipsを紹介します。

# カード番号を4桁入力するごとに自動でハイフンを入れる

Visa, MasterCardのカード番号は16桁なので、そのまま数字が並ぶとユーザー的には見づらく、誤入力もしやすいです。
なので、4桁おきに自動でハイフンが入るようなEditTextを作りました。

```java
private static final Pattern pattern1 = Pattern.compile("[0-9]{4}");
private static final Pattern pattern2 = Pattern.compile("[0-9]{4}-[0-9]{4}");
private static final Pattern pattern3 = Pattern.compile("[0-9]{4}-[0-9]{4}-[0-9]{4}");
private static final Pattern pattern4 = Pattern.compile("[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4}");

private TextWatcher mCardNumberTextWatcher = new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (before == 0) {
            if (pattern1.matcher(s).matches()) {
                setText(s + "-");
                setSelection(getEditableText().toString().length());
            }
            if (pattern2.matcher(s).matches()) {
                setText(s + "-");
                setSelection(getEditableText().toString().length());
            }
            if (pattern3.matcher(s).matches()) {
                setText(s + "-");
                setSelection(getEditableText().toString().length());
            }
        } else {
            if (pattern1.matcher(s).matches()) {
                setText(s.subSequence(0, s.length()-1));
                setSelection(getEditableText().toString().length());
            }
            if (pattern2.matcher(s).matches()) {
                setText(s.subSequence(0, s.length()-1));
                setSelection(getEditableText().toString().length());
            }
            if (pattern3.matcher(s).matches()) {
                setText(s.subSequence(0, s.length()-1));
                setSelection(getEditableText().toString().length());
            }
        }
    }
    @Override
    public void afterTextChanged(Editable s) {}
};


// EditTextにtext watcherをセット
editText.addTextChangedListener(mCardNumberTextWatcher);
```

# クライアントでバリデーションする

サーバーでのバリデーションはもちろん必須ですが、通信する以前にクライアントでもできるバリデーションがあります。

## カード番号一桁目をチェックする

カード番号はブランドごとに先頭の数字が決まっています。VISAは4, MasterCardは5で始まるため、これ以外の数字が入力されたらユーザーに「このブランドはサポートされていません」などと警告しましょう。

## カード番号の桁数チェック

カード番号はブランドごとに桁数が決まっています。先頭の一桁目でブランドを特定したら、EditTextの最大桁数をセットしましょう（自動でハイフンを挿入する場合は、ハイフンも含めた長さにする）

|ブランド|桁数|
|---|---|
|Visa|16|
|MasterCard|16|
|JCB|16|
|American Express|15|
|Diners|14|

## セキュリティコード（CVC, CVV）の桁数チェック

カード裏面のセキュリティコードも桁数がブランドごとに決まっています（American Expressが4桁、その他が3桁）。
こちらも誤入力（特に間違って連打してしまうなど）を防ぐために、EditTextの最大桁数を指定しましょう。

# Card.IOを導入する

そもそもクレジットカード番号を手動で入れる必要がない手段もあります。PayPalが提供しているCard.IOというクレジットカード自動読み込みのSDKを使います。

[card-io/card.io-Android-SDK](https://github.com/card-io/card.io-Android-SDK)

スマートフォンのカメラをクレジットカードに向けるだけで、自動でカード番号や有効期限を読み取ってくれます。読み取りの成功率は高いですが、いくつかのカードで試したところ一部カードの色や数字の凹凸によっては苦手なカードがありそうです（特に数字が平坦なカードが苦手そうでした）

# 参考

- [Wikipedia: クレジットカードの番号](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AC%E3%82%B8%E3%83%83%E3%83%88%E3%82%AB%E3%83%BC%E3%83%89%E3%81%AE%E7%95%AA%E5%8F%B7)
- [クレジットカード・セキュリティコード（CVV2/CVC2）](http://www.cardservice.co.jp/service/creditcard/csc.html)