Tìm hiểu về Stripe: thư viện thực hiện thanh toán thẻ tín dụng (credit card) trong ứng dụng iOS

I. Giới thiệu

Trong thế giới phẳng ngày nay, thanh toán bằng thẻ tín dụng được rất nhiều người lựa chọn sử dụng trên thế giới (trừ Việt Nam ta ra). Vì vậy, việc tích hợp khả năng thanh toán bằng thẻ tín dụng trong ứng dụng di động là việc cần thiết đối với các ứng dụng có phát sinh giao dịch với người dùng. Trong bài viết này, tôi xin giới thiệu Stripe - một thư viện rất mạnh mẽ giúp chúng ta tích hợp chức năng thanh toán thẻ tín dụng vào ứng dụng iOS.

Nhắc đến chuyện thanh toán trong ứng dụng, có thể các bạn sẽ tự hỏi vì sao không thanh toán bằng tính năng In-App Purchase được Apple tích hợp sẵn, và với quá trình review app ngặt nghèo của Apple, liệu app của chúng ta có bị reject và không được đưa lên Appstore hay không? Đây là câu trả lời:

  • Thứ nhất: sử dụng tính năng In-App Purchase, chúng ta sẽ phải chia 30% tiền cho Apple, có ai muốn chia tiền như vậy không?
  • Thứ hai: Trong điều khoản Apple đã quy định, các nội dung kỹ thuật số (digital content) đều phải được thanh toán bằng In-App Purchase, còn các sản phẩm khác chúng ta có thể thanh toán bằng phương pháp khác. Ví dụ thế này, chúng ta có 1 game, và người chơi phải bỏ tiền ra để mua vàng để nâng đồ, hoặc mua thêm màn chơi, vũ khí, ... thì chúng ta phải dùng In-App Purchase, còn khi chúng ta có một ứng dụng bán hàng online, thì quần áo, giày dép chúng ta bán có thể được thanh toán bằng thẻ tín dụng.

Ok, vậy là đã rõ chuyện có được thanh toán bằng credit card hay không. Sau đây chúng ta sẽ bắt đầu tìm hiểu về Stripe

II. Nội dung

1. Cách Stripe hoạt động

Đầu tiên, chúng ta sẽ tìm hiểu cách chúng ta giao tiếp với Stripe, cụ thể là các bước để chúng ta thực hiện giao dịch. Để có thể giao dịch, chúng ta cần có ứng dụng trên iOS, và web server để tương tác với Stripe. Các bước của quá trình giao dịch lần lượt trải qua 6 bước:

  • Bước 1: Ứng dụng di động gửi thông tin thẻ tín dụng (gồm email, số thẻ tín dụng, ngày hết hạn, CVC và lượng tiền giao dịch) lên Stripe.
  • Bước 2: Trong trường hợp thông tin thẻ tín dụng hợp lệ, Stripe trả về cho ứng dụng 1 đoạn mã Token. Tại thời điểm này việc giao dịch chưa được thực hiện.
  • Bước 3: Ứng dụng gửi token lên web server.
  • Bước 4: Web server nhận token từ ứng dụng và gửi token này lên Stripe để thực hiện giao dịch, lúc này việc giao dịch mới thực sự diễn ra.
  • Bước 5: Stripe trả về response cho web server kết quả giao dịch.
  • Bước 6: Web server trả về cho ứng dụng kết quả giao dịch.

Các bạn có thể xem các bước của quá trình giao dịch qua sơ đồ sau:

2. Tạo tài khoản Stripe

Để có thể giao tiếp với server của Stripe, đầu tiên chúng ta cần tạo tài khoản Stripe. Các bạn bấm vào đây và làm theo các bước để tạo tài khoản. Sau khi tạo tài khoản xong, vào phần API, chúng ta sẽ lấy được Publishable key và Secret key

3. Demo

a. Tạo project

Đầu tiên, các bạn có thể download starter project tại đây Tôi đã tạo sẵn file Podfile với các thư viện cần thiết để sử dụng trong project. Các bạn mở Terminal và gõ lệnh sau để cài đặt các thư viện:

pod install

Nếu máy bạn chưa cài CocoaPods, các bạn có thể cài đặt CocoaPods bằng lệnh sau:

sudo gem install cocoapods

Sau khi cài đặt các thư viện trong pod, chúng ta mở StripeTutorial.xcworkspace và bắt đầu code.

b. Configure Stripe API key

Mở file AppDelegate.swift, thêm thư viện Stripe:

import Stripe

Tiếp theo, chúng ta thêm code sau để configure API key:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        Stripe.setDefaultPublishableKey("pk_test_GFTqKrQq7Gk8SgieSk90z17l")
        return true
    }

Các bạn chú ý đổi PublishableKey bằng key mà chúng ta nhận được khi đăng ký trên trang của Stripe.

c. Gửi thông tin credit card lên Stripe server

Mở file Main.storyboard, mở Assistant editor và kéo thả các outlet, action vào ViewController.swift cho các textfield và button của chúng ta như sau:


import UIKit
import Alamofire
import Stripe

class ViewController: UIViewController {

    @IBOutlet weak var emailTextField: UITextField!
    
    @IBOutlet weak var cardNumberTextField: UITextField!
    
    @IBOutlet weak var expireDateTextField: UITextField!
    
    @IBOutlet weak var cvcTextField: UITextField!
    
    @IBOutlet weak var amountTextfield: UITextField!
    
    @IBAction func onNextButtonClicked(_ sender: Any) {
        
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

Tiếp theo, chúng ta thêm code vào hàm onNextButtonClicked(_ sender: ) để thực hiện code gửi thông tin credit card lên Stripe:

    @IBAction func onNextButtonClicked(_ sender: Any) {
        // 1
        let tripCardParams = STPCardParams()
        
        guard expireDateTextField.text?.isEmpty == false else {
            return
        }
        
        let expireDate = expireDateTextField.text?.components(separatedBy: "/")
        let expMonth = UInt(Int(expireDate![0])!)
        let expYear = UInt(Int(expireDate![1])!)
        
        tripCardParams.number = cardNumberTextField.text
        tripCardParams.cvc = cvcTextField.text
        tripCardParams.expMonth = expMonth
        tripCardParams.expYear = expYear
        
        // 2
        if (STPCardValidator.validationState(forCard: tripCardParams) == .valid) {
            // 3
            STPAPIClient.shared().createToken(withCard: tripCardParams, completion: { (token, error) in
                // 4
                if error != nil {
                    self.handleError(error: error!)
                    return
                }
                // 5
                self.postStripeToken(token: token!)
            })
        }
    }
    
    func handleError(error: Error) {
    
    }
    
    func postStripeToken(token: STPToken) {
        
    }

Trong đoạn code trên:

  1. Tạo instance tripCardParams và gán các thông tin của credit card cho tripCardParams
  2. Kiểm tra các thông tin của credit card trên Stripe
  3. Gửi request lên Stripe để lấy về token
  4. Trường hợp request không thành công, chúng ta gọi hàm handleError(error: ) để xử lý lỗi
  5. Trường hợp lấy được token, chúng ta gọi hàm postStripeToken(token: ) để thực hiện thanh toán credit card

Bây giờ chúng ta implement hàm handleError(error: ):

    func handleError(error: Error) {
        let alert = UIAlertController(title: "Please Try Again", message: (error as NSError).localizedDescription, preferredStyle: .alert)
        let okAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
        alert.addAction(okAction)
        present(alert, animated: true, completion: nil)
    }

Tiếp theo, chúng ta cần implement nốt hàm postStripeToken(token: ), tuy nhiên chúng ta cần thêm server để gửi làm việc này

d. Configure web server

Đầu tiên, các bạn vào đây chọn bản thích hợp, download và cài đặt XAMPP.

Sau khi cài đặt và chạy XAMPP, chúng ta có được server như hình sau:

Tiếp theo, các bạn download server files tại đây. Đây là code server với chức năng nhận token từ app, thực hiện giao dịch với Stripe và trả về kết quả giao dịch cho app.

Sau khi download các file cần thiết, các bạn copy thư mục "donate" vừa download vào thư mục "Applications/XAMPP/htdocs". Mở file payment.php bằng editor và sửa secret key bằng secret key của các bạn trên trang Stripe:

\Stripe\Stripe::setApiKey("sk_test_V4HDxzIPpBNK3heoMrXjfTTC");

Ok, vậy là web server đã có, bây giờ chúng ta implement hàm postStripeToken(token: ):

    func postStripeToken(token: STPToken) {
        // 1
        let url = "http://localhost/donate/payment.php"
        // 2
        let params = ["stripeToken": token.tokenId,
                      "amount": Int(amountTextfield.text!) as Any,
                      "currency": "usd",
                      "description": emailTextField.text as Any] as [String : Any]
        // 3
        Alamofire.request(url, method: .post, parameters: params, encoding: URLEncoding.default, headers: nil).responseJSON { (response) in
            // 4
            if let result = response.result.value {
                let JSON = result as! Dictionary<String, String>
                let alert = UIAlertController(title: JSON["status"], message: JSON["message"], preferredStyle: .alert)
                let okAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
                alert.addAction(okAction)
                self.present(alert, animated: true, completion: nil)
                print(JSON)
            }
        }
    }

Trong đoạn code bên trên:

  1. url của web server. Nếu các bạn tạo web server khác, hãy thay đổi địa chỉ url tương ứng
  2. Lấy các parameter để đẩy lên web server, server sẽ đẩy các thông tin này lên Stripe để thực hiện giao dịch
  3. Sử dụng Alamofire để post thông tin credit card lên server
  4. Hiển thị Alert kết quả giao dịch credit card

e. Dùng thử app

Chúng ta build app để thử chức năng giao dịch. Các bạn có thể sử dụng credit card với number 4242424242424242, các giá trị CVC, email và amount các bạn có thể điền bất kỳ, còn expire date là một giá trị nào đấy trong tương lai để test. Ví dụ như hình sau:

Vậy là chúng ta đã thực hiện được giao dịch credit card. Để kiểm tra thông tin, các bạn có thể sử dụng Dashbroad của Stripe (https://dashboard.stripe.com/test/dashboard) để xem thông tin các giao dịch

Vậy là chúng ta đã hoàn thành việc giao dịch credit card trong ứng dụng, tôi xin kết thúc bài viết tại đây.

III. Kết luận

Trên đây, tôi đã giới thiệu đến các bạn Stripe - thư viện rất mạnh mẽ giúp chúng ta thực hiện việc thanh toán credit card trong ứng dụng iOS. Hi vọng bài viết này có ích cho các bạn.

Cuối cùng, xin cảm ơn các bạn đã theo dõi bài viết này. Have a nice day ^_^!