Tích hợp SDK iOS Native
Thư viện TingeePaySDK giúp các ứng dụng iOS Native dễ dàng nhúng màn hình thanh toán trực quan dưới dạng Bottom Sheet hoặc Toàn màn hình.
1. Cài đặt SDK
Bạn có thể cài đặt TingeePaySDK cho ứng dụng iOS bằng một trong hai cách dưới đây:
- Swift Package Manager (SPM)
- XCFramework (Thủ công)
Đây là phương thức cài đặt được khuyến nghị.
- Mở dự án của bạn trên Xcode.
- Chọn File > Add Packages... (hoặc Add Package Dependencies...).
- Nhập URL của kho lưu trữ Github chứa TingeePay SDK:
https://github.com/tingeedev/tingee-pay-sdk-ios.git - Chọn quy tắc phiên bản (ví dụ: Up to Next Major Version) và nhấn Add Package.
Nếu bạn không sử dụng SPM, bạn có thể tích hợp thủ công file XCFramework:
- Tải về gói: TingeePaySDK.xcframework.zip (nén từ thư mục
TingeePaySDK.xcframework). - Giải nén và kéo thả thư mục
TingeePaySDK.xcframeworkvào dự án Xcode của bạn (đảm bảo chọn Copy items if needed và Create groups). - Chọn target ứng dụng của bạn, đi tới tab General.
- Tại mục Frameworks, Libraries, and Embedded Content, tìm
TingeePaySDK.xcframeworkvà cấu hình là Embed & Sign.
2. Cấu hình quyền hệ thống
Để hỗ trợ tính năng lưu mã QR thanh toán vào album ảnh của thiết bị (khi người dùng bấm nút "Tải mã QR" trên giao diện cổng), bạn bắt buộc phải cấu hình quyền truy cập thư viện ảnh trong tệp Info.plist.
Mở tệp Info.plist dưới dạng Source Code và thêm khóa sau:
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Ứng dụng cần quyền để lưu mã QR thanh toán vào thư viện ảnh của bạn.</string>
[!WARNING] Nếu thiếu cấu hình này, ứng dụng sẽ bị crash ngay lập tức khi người dùng nhấn nút lưu mã QR trên màn hình thanh toán.
3. Hướng dẫn Tích hợp nhanh
Tùy theo cấu trúc dự án của bạn là UIKit hay SwiftUI, hãy tham khảo hướng dẫn tương ứng:
- UIKit (Swift)
- SwiftUI
Tại UIViewController nơi bạn muốn gọi thanh toán (ví dụ: nút thanh toán được bấm):
import UIKit
import TingeePaySDK
class CheckoutViewController: UIViewController {
func openPayment(checkoutUrlString: String) {
guard let checkoutUrl = URL(string: checkoutUrlString) else { return }
// Gọi SDK để hiển thị cổng thanh toán
TingeePay.presentCheckout(
from: self,
checkoutUrl: checkoutUrl,
style: .bottomSheet, // Hoặc .fullScreen
delegate: self
)
}
}
Đối với SwiftUI, bạn nên viết một cấu trúc wrapper conforming tới UIViewControllerRepresentable để dễ dàng tái sử dụng và quản lý các sự kiện trả về.
Bước 1: Khai báo wrapper đại diện cho SDK
import SwiftUI
import TingeePaySDK
struct TingeePayView: UIViewControllerRepresentable {
let checkoutUrl: URL
var themeColor: String? = nil
var style: TingeePayStyle = .fullScreen
var onFinished: ((TingeePaymentResult) -> Void)?
var onCancelled: (() -> Void)?
var onFailed: ((Error) -> Void)?
class Coordinator: NSObject, TingeePayCheckoutDelegate {
var parent: TingeePayView
init(parent: TingeePayView) {
self.parent = parent
}
func tingeePayCheckoutDidFinish(with result: TingeePaymentResult) {
parent.onFinished?(result)
}
func tingeePayCheckoutDidCancel() {
parent.onCancelled?()
}
func tingeePayCheckoutDidFail(with error: Error) {
parent.onFailed?(error)
}
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
func makeUIViewController(context: Context) -> TingeePayCheckoutViewController {
let vc = TingeePayCheckoutViewController(
checkoutUrl: checkoutUrl,
themeColor: themeColor,
style: style
)
vc.delegate = context.coordinator
return vc
}
func updateUIViewController(_ uiViewController: TingeePayCheckoutViewController, context: Context) {}
}
Bước 2: Sử dụng wrapper trong View của bạn
import SwiftUI
struct ContentView: View {
@State private var showPayment = false
let checkoutUrl = URL(string: "https://pay.tingee.vn/your-order-id")!
var body: some View {
Button("Thanh toán với Tingee") {
showPayment = true
}
.sheet(isPresented: $showPayment) {
TingeePayView(
checkoutUrl: checkoutUrl,
themeColor: "#FF5733", // Tùy chọn màu sắc
style: .fullScreen, // Hoặc .bottomSheet
onFinished: { result in
print("Kết quả: \(result.status.rawValue)")
showPayment = false
},
onCancelled: {
print("Người dùng đã huỷ thanh toán")
showPayment = false
},
onFailed: { error in
print("Lỗi tải trang: \(error.localizedDescription)")
showPayment = false
}
)
}
}
}
4. Lắng nghe & Xử lý kết quả
Để nhận các sự kiện từ màn hình thanh toán, bạn cần tuân thủ và kế thừa protocol TingeePayCheckoutDelegate:
extension CheckoutViewController: TingeePayCheckoutDelegate {
/// Sự kiện: Thanh toán hoàn tất hoặc kết thúc (Thành công, Lỗi, Hết hạn...)
func tingeePayCheckoutDidFinish(with result: TingeePaymentResult) {
print("Trạng thái thanh toán: \(result.status.rawValue)")
print("Mã đơn hàng: \(result.orderId ?? "")")
switch result.status {
case .success:
// Xử lý khi thanh toán thành công (ví dụ: Chuyển màn hình cảm ơn)
print("Thanh toán thành công!")
case .failed:
// Giao dịch thanh toán thất bại
print("Lỗi thanh toán: \(result.errorMessage ?? "")")
case .cancelled:
// Giao dịch bị hủy bỏ trên cổng
print("Giao dịch đã bị huỷ.")
case .expired:
// Hết hạn thời gian thanh toán
print("Đơn hàng đã hết hạn thanh toán.")
case .error:
// Lỗi hệ thống phát sinh
print("Lỗi hệ thống cổng thanh toán.")
}
}
/// Sự kiện: Người dùng chủ động nhấn nút "Đóng" (X) hoặc vuốt tắt Bottom Sheet để thoát
func tingeePayCheckoutDidCancel() {
print("Người dùng đã thoát màn hình thanh toán.")
}
/// Sự kiện: Lỗi phát sinh khi SDK cố gắng tải cổng thanh toán (ví dụ: Sai định dạng URL, Mất kết nối Internet...)
func tingeePayCheckoutDidFail(with error: Error) {
print("Lỗi khởi tạo/tải màn hình thanh toán: \(error.localizedDescription)")
}
}
5. Mô hình dữ liệu
TingeePaymentResult
Đối tượng chứa kết quả giao dịch được SDK trả về qua callback tingeePayCheckoutDidFinish.
| Thuộc tính | Kiểu dữ liệu | Mô tả |
|---|---|---|
status | TingeePaymentStatus | Trạng thái cuối cùng của giao dịch. |
orderId | String? | Mã đơn hàng trên hệ thống của bạn (Mã đã truyền vào khi tạo link thanh toán). |
errorMessage | String? | Thông báo lỗi chi tiết (nếu có). |
TingeePaymentStatus
Là một Enum đại diện cho các trạng thái giao dịch:
.success: Giao dịch thành công..failed: Giao dịch thất bại..cancelled: Giao dịch bị hủy..expired: Giao dịch hết hạn thanh toán..error: Giao dịch gặp lỗi hệ thống.
6. Xử lý sự cố thường gặp
Nút "Tải mã QR" không hoạt động
- Nguyên nhân: Chưa cấu hình key
NSPhotoLibraryAddUsageDescriptiontrong tệpInfo.plist. - Cách khắc phục: Xem lại bước cấu hình quyền hệ thống và bổ sung key này vào file plist của bạn.
Test trên môi trường Sandbox
- SDK Mobile tự động chuyển môi trường dựa vào URL. Nếu
checkoutUrlbắt đầu bằng URL Sandbox của Tingee, SDK sẽ tự hiểu và hiển thị giao diện Sandbox.