[iOS] card.ioを使ってクレジットカードをスキャンする

ios

クレジットカードをカメラでスキャンしたい

こんにちは!モバイルアプリサービス部の加藤潤です。
クレジットカードを使って決済するアプリを作る場合、使用するクレジットカードの情報(番号とか有効期限とか)をユーザーが手入力するのは面倒だったりします。
iPhoneのカメラを使ってスキャンして自動入力出来たら素敵だなぁ〜と思って探したところ、card.io SDK for iOSが良さそうだったので試してみました。

card.io SDK for iOSとは

PayPalによって提供されている、iOSアプリにクレジットカードのスキャン機能を簡単に組み込むことが出来るSDKです。 MITライセンスで公開されています。iOSだけでなく、Android用のSDKもあります。

検証環境

今回検証を行った環境は以下となります。

  • Xcode Version 8.2.1(8C1002)
  • Swift 3.0.2
  • CocoaPods バージョン1.1.1

導入手順

CocoaPodsで以下の手順でインストールしました。

  1. pod initでPodfileを作成
  2. 作成したPodfileにpod 'CardIO'の行を追加
    最終的にPodfileは以下のようになりました。

    source 'https://github.com/CocoaPods/Specs.git'
    platform :ios, '8.0'
    
    target ターゲット名 do
      pod 'CardIO'
    end
    
    
  3. pod installを実行
    ※記事執筆時点の最新バージョンは5.4.1でした。

Bridging-Headerを作成(Swiftから使う場合)

今回はSwiftのコードからcard.ioを使うのでBridging-Headerファイルを作成する必要があります。
Objective-Cから使う場合、この作業は不要です。

プロジェクトを右クリックして「New File...」を選択

new_file

iOS > Source > Header Fileを選択

header_file

ファイル名を入力

今回はプロジェクト名が「SwiftCreditCardScanner」だったのでファイル名は「SwiftCreditCardScanner-Bridging-Header」にしました。

header_file_name

作成したBridging-Headerファイルを指定する

プロジェクトまたはターゲットの「Objective-C Bridging Header」の項目に作成したヘッダファイル名を入力します。 bridging_header

CardIO.hをimportする

最後にヘッダファイルに#import "CardIO.h"を追加します。これでSwiftのコードからcard.ioのクラス群にアクセスできるようになりました。

//
//  SwiftCreditCardScanner-Bridging-Header.h
//  SwiftCreditCardScanner
//

#ifndef SwiftCreditCardScanner_Bridging_Header_h
#define SwiftCreditCardScanner_Bridging_Header_h

#import "CardIO.h" // この行を追加する

#endif /* SwiftCreditCardScanner_Bridging_Header_h */

NSCameraUsageDescriptionにカメラを使う目的を記述

カメラを使うので用途をInfo.plistに記載しましょう。

NSCameraUsageDescription

card.ioを使ってみる

card.ioをアプリに組み込む場合、以下の2通りの方法があります。

  • CardIOPaymentViewControllerを使う方法
  • CardIOViewを使う方法

CardIOPaymentViewControllerはUIViewControllerのサブクラス(より正確にはUINavigationControllerのサブクラス)で、クレジットカードをスキャンする画面はもちろん、キャンセルボタンやうまくカードが読み取れなかった場合の手動入力機能を提供しています。 対して、CardIOViewはUIViewのサブクラスとなっていて、クレジットカードをスキャンするビューのみ提供しています。こちらにはキャンセルボタンや手動入力機能は無い為、必要に応じて自分で実装する必要がありますが、カスタマイズ性が高いのが特徴となっています。

準備

CardIOPaymentViewControllerやCardIOViewを使うにあたって行っておいた方が良い作業があります。 それは「カメラが使えるかどうかの確認」と CardIO SDKのリソースの事前読み込みです。 以下のようにCardIOUtilities.canReadCardWithCamera()でカメラが使えるかどうかか取得できるので、カメラが使えない場合はメッセージを表示するなり、スキャンボタンを非表示にすると良いでしょう。
CardIOUtilities.preloadCardIO()はCardIO SDKのリソースを読み込む処理で、あらかじめリソースを読み込んでおくことでスキャン起動の遅延を防止しています。

override func viewDidLoad() {
    super.viewDidLoad()

    if !CardIOUtilities.canReadCardWithCamera() {
        // カメラが使えない場合。
        // ここでスキャンボタンを非表示にする処理等を行う
    } else {
        // スキャンの遅延防止のためにCardIO SDKのリソースをあらかじめ読み込む
        CardIOUtilities.preloadCardIO()
    }
}

CardIOPaymentViewControllerを使う方法

CardIOPaymentViewControllerを使う方法は非常に簡単です。 以下のようにCardIOPaymentViewControllerを生成して表示するだけです。 生成時にデリゲートを設定することでCardIOPaymentViewControllerDelegateのメソッドを通じてイベントをハンドリングできるようになります。

let vc = CardIOPaymentViewController(paymentDelegate: self)!
present(vc, animated: true)

CardIOPaymentViewControllerDelegate

CardIOPaymentViewControllerDelegateには以下のメソッドが定義されていて、 キャンセルボタンタップのハンドリングや、カード情報が受け取れるようになっています。

func userDidCancel(_ paymentViewController: CardIOPaymentViewController!) {
    // キャンセルボタンをタップした時に呼ばれる。
    dismiss(animated: true)
}

func userDidProvide(_ cardInfo: CardIOCreditCardInfo!, in paymentViewController: CardIOPaymentViewController!) {
    // カード番号のスキャン後にセキュリティーコードを手入力して完了ボタンをタップした場合や、全て手入力して完了ボタンをタップした場合に呼ばれる。
    print(cardInfo.cardNumber)  // カード番号 XXXXXXXXXXXXXXXX
    print(cardInfo.expiryMonth) // 有効期限(月)ex.) 5
    print(cardInfo.expiryYear)  // 有効期限(年)ex.) 2020
    print(cardInfo.cvv)         // セキュリティーコード XXX
    dismiss(animated: true)
}

スクリーンショット

スクリーンショットをいくつか載せておきます。

  • スキャン画面

CardIOPaymentViewController_scan

  • VISAのカードをスキャンした後の画面(セキュリティーコードは手入力)

CardIOPaymentViewController_after_scan

  • 「手動で入力」ボタンをタップすると表示される手入力画面。入力中にカードのブランドが判定され右端にアイコンが表示されます。

CardIOPaymentViewController_master

  • 手入力画面で全ての項目を入力すると完了ボタンがタップできるようになります。

CardIOPaymentViewController_manually

CardIOViewを使う方法

CardIOViewを使う場合はCardIOViewを生成して任意のビューにaddSubviewします。 忘れずにデリゲートを設定するようにしましょう。 CardIOViewはプロパティで諸々カスタマイズできます。 以下の例では枠線の色やスキャンのビューに表示される文言を設定しています。

let cardIOView = CardIOView(frame: view.bounds)
cardIOView.hideCardIOLogo = true // スキャンのビューの右上に表示されるロゴを非表示にする
cardIOView.scanInstructions = "枠内にカード全体が入るようにしてください" // 文言設定
cardIOView.guideColor = UIColor.orange // 枠線の色をオレンジに
cardIOView.delegate = self
view.addSubview(cardIOView)

CardIOViewDelegate

CardIOViewDelegateには以下のメソッドが定義されていて、スキャンしたカードの情報が受け取れます。 スキャンが終わったのでremoveFromSuperview()を呼んでCardIOViewをビュー階層から削除しています。

func cardIOView(_ cardIOView: CardIOView!, didScanCard cardInfo: CardIOCreditCardInfo!) {
    cardIOView.removeFromSuperview()
    print(cardInfo.cardNumber)  // カード番号 XXXXXXXXXXXXXXXX
    print(cardInfo.expiryMonth) // 有効期限(月)ex.) 5
    print(cardInfo.expiryYear)  // 有効期限(年)ex.) 2020
}

スクリーンショット

設定した文言や枠線の色が反映されていることが確認できます。

CardIOView

おわりに

今回はcard.ioを使ってクレジットカードをスキャンしてみました。
非常に手軽に組み込むことができました。手持ちのカードで何回かスキャンしてみましたが、有効期限の読み取り精度は50%ほどでしたが、カード番号はほぼ100%読み取ることができました。
精度については画面の輝度やカードによっても変わってくるかもしれません。皆さんも試してみてはいかがでしょうか。

参考

card.io SDK for iOS

AWS Cloud Roadshow 2017 福岡