BEX Full SDK — Entegrasyon Kılavuzu
Bu doküman, iOS uygulamanıza BEX Full SDK’nın entegrasyonu için hazırlanmıştır.
Gereksinimler
- Min. iOS: 15.0
- Dil: Swift
- Framework'ler: UIKit ve SwiftUI desteklenmektedir.
- Cihazlar: iPhone ve iPad.
- Dağıtım: Yalnızca Swift Package Manager.
Hızlı Başlangıç
SDK'yı yalnızca birkaç satır kodla entegre edin:
UIKit
let token = try await BKMExpress.initialize(context: context)
BKMExpress.pay(token: token, data: paymentData, on: self) { result in ... }
SwiftUI
.bkmExpressPaymentSheet(token: $token, data: paymentData) { result in ... }
Kurulum
Swift Package Manager
Seçenek 1: Xcode üzerinden
Projenizin "Package Dependencies" sekmesinden aşağıdaki URL ve sürüm bilgisiyle paketi ekleyin:
https://github.com/BKMExpress/iOS-Full-SDK.git
Seçenek 2: Package.swift üzerinden (başka bir Swift Package içinde kullanılacaksa)
Package.swift dosyanızdaki dependencies listesine bağımlılığı ekleyin:
.package(url: "https://github.com/BKMExpress/iOS-Full-SDK.git", branch: "main")
Ardından bağımlılığı kullanmak istediğiniz target'ın dependencies listesine SDK'nin product'ını ekleyin:
"BKMExpressSDK"
Temel Entegrasyon
Adım 1: SDK'yı İmport Edin
import BKMExpressSDK
Adım 2: SDK'yı Başlatın
Kendi sunucularınızdan entegrasyon sonucunda elde edeceğiniz bilgilerle InitializationContext'i doldurun ve initialize(context:) çağrısı yapın:
let token = try await BKMExpress.initialize(
context: .init(
authToken: "your_auth_token", // Auth tokeniniz.
merchantID: "your_merchant_id", // Entegrasyon sonucunda size verilen merchant identifier.
merchantUserID: "your_user_id", // Kullanıcınızı tanımlamak için kullandığınız identifier.
gsmNo: .init("5XXXXXXXXX")!, // Kullanıcıya ait Türkiye telefon numarası.
currencyCode: "TRY", // ISO 4217 para birimi kodu.
mode: .test // Ortam modu: .test, .preprod veya .production.
)
)
Adım 3: Akışı Başlatın
Ödeme veya kart seçimi akışını başlatın:
// Ödeme
BKMExpress.pay(token: token, data: paymentData, on: self) { result in
// Sonuca göre aksiyon alın.
}
// Kart Seçimi
BKMExpress.selectCard(token: token, on: self) { result in
// Sonuca göre aksiyon alın.
}
SDK akışı herhangi bir nedenle tamamlandığında kendini otomatik olarak dismiss eder. Ekstra dismiss çağrısı yapılmasına gerek yoktur.
Tam Entegrasyon Örneği
UIKit — Ödeme
final class CheckoutViewController: UIViewController {
private func payButtonTapped() {
Task {
do {
// 1. SDK'yı başlatın.
let token = try await BKMExpress.initialize(
context: .init(
authToken: "your_auth_token",
merchantID: "your_merchant_id",
merchantUserID: "your_user_id",
gsmNo: .init("5XXXXXXXXX")!,
currencyCode: "TRY",
mode: .test
)
)
// 2. Ödeme verilerini hazırlayın.
let paymentData = BKMExpress.PaymentData(
amount: 99.90,
security: .tds,
installmentCount: .init(1)!,
orderID: "order_123",
successUrl: "https://merchant.example.com/payment/callback/success",
failUrl: "https://merchant.example.com/payment/callback/fail"
)
// 3. Ödeme akışını başlatın.
BKMExpress.pay(
token: token,
data: paymentData,
theme: .init(), // Opsiyonel: tema özelleştirmesi.
style: .sheet, // .sheet veya .fullScreen.
on: self
) { result in
switch result {
case .completed:
print("Ödeme başarılı.")
case .cancelled:
print("Ödeme iptal edildi.")
case .failed(let failure):
print("Ödeme başarısız: \(failure.message)")
}
}
} catch {
showAlert("BKM Express başlatılamadı: \(error.localizedDescription)")
}
}
}
}
UIKit — Kart Seçimi
final class CardSelectionViewController: UIViewController {
private func selectCardButtonTapped() {
Task {
do {
let token = try await BKMExpress.initialize(
context: .init(
authToken: "your_auth_token",
merchantID: "your_merchant_id",
merchantUserID: "your_user_id",
gsmNo: .init("5XXXXXXXXX")!,
currencyCode: "TRY",
mode: .test
)
)
BKMExpress.selectCard(
token: token,
theme: .init(),
style: .sheet,
on: self
) { result in
switch result {
case .selected(let card):
print("Seçilen kart: \(card.alias)")
case .cancelled:
print("Kart seçimi iptal edildi.")
case .failed(let failure):
print("Hata: \(failure.message)")
}
}
} catch {
showAlert("BKM Express başlatılamadı.")
}
}
}
}
SwiftUI — Ödeme
struct CheckoutScreen: View {
@State private var bkmExpressToken: BKMExpress.InitializationToken?
var body: some View {
VStack {
// View içeriğiniz.
Button("BKM Express ile Öde") {
Task { await startPayment() }
}
}
.bkmExpressPaymentSheet(
token: $bkmExpressToken,
data: BKMExpress.PaymentData(
amount: 99.90,
security: .tds,
installmentCount: .init(1)!,
orderID: "order_123",
successUrl: "https://merchant.example.com/payment/callback/success",
failUrl: "https://merchant.example.com/payment/callback/fail"
),
theme: { $0.buttonCornerRadius = .capsule }, // Opsiyonel.
style: .sheet
) { result in
switch result {
case .completed:
print("Ödeme başarılı.")
case .cancelled:
print("Ödeme iptal edildi.")
case .failed(let failure):
print("Ödeme başarısız: \(failure.message)")
}
}
}
private func startPayment() async {
do {
bkmExpressToken = try await BKMExpress.initialize(
context: .init(
authToken: "your_auth_token",
merchantID: "your_merchant_id",
merchantUserID: "your_user_id",
gsmNo: .init("5XXXXXXXXX")!,
currencyCode: "TRY",
mode: .test
)
)
} catch {
showAlert("BKM Express başlatılamadı.")
}
}
}
SwiftUI'da SDK akışı tamamlandığında token'a otomatik olarak
nilset edilir. Ekstra bir aksiyona gerek yoktur.
SwiftUI — Kart Seçimi
struct CardSelectionScreen: View {
@State private var bkmExpressToken: BKMExpress.InitializationToken?
var body: some View {
VStack {
Button("BKM Express Kartınızı Eşleştirin") {
Task { await startCardSelection() }
}
}
.bkmExpressCardSelectionSheet(
token: $bkmExpressToken,
theme: { $0.buttonCornerRadius = .capsule }, // Opsiyonel.
style: .sheet
) { result in
switch result {
case .selected(let card):
print("Seçilen kart: \(card.alias)")
case .cancelled:
print("İptal edildi.")
case .failed(let failure):
print("Hata: \(failure.message)")
}
}
}
private func startCardSelection() async {
do {
bkmExpressToken = try await BKMExpress.initialize(
context: .init(
authToken: "your_auth_token",
merchantID: "your_merchant_id",
merchantUserID: "your_user_id",
gsmNo: .init("5XXXXXXXXX")!,
currencyCode: "TRY",
mode: .test
)
)
} catch {
showAlert("BKM Express başlatılamadı.")
}
}
}
API Referansı
BKMExpress
SDK'nın ana namespace'i.
initialize(context:)
SDK oturumu başlatır ve akışı başlatmak için gereken token'ı döner.
static func initialize(context: InitializationContext) async throws(Failure) -> InitializationToken
Parametreler:
context: Oturum için gerekli bilgileri içerenInitializationContext.
Döndürür: InitializationToken — akışı başlatmak için kullanılan token.
Fırlatır: BKMExpress.Failure — hata durumunda.
pay(token:data:theme:style:on:onFinished:)
Ödeme akışını başlatır (closure versiyonu).
static func pay(
token: InitializationToken,
data: PaymentData,
theme: Theme = .init(),
style: PresentationStyle = .sheet,
on controller: UIViewController,
onFinished: @escaping (PaymentResult) -> Void
)
Parametreler:
token:initialize(context:)metodundan elde edilen token.data: Ödeme işlemine dair bilgileri içerenPaymentData.theme: SDK görünümünü özelleştiren tema. Opsiyonel; varsayılan tema kullanılır.style: Sunum biçimi..sheetveya.fullScreen.on: SDK'yı present edecekUIViewController.onFinished: SDK tamamlandığında çağırılacak closure.PaymentResultiletilir.
pay(token:data:theme:style:on:delegate:)
Ödeme akışını başlatır (delegate versiyonu).
static func pay(
token: InitializationToken,
data: PaymentData,
theme: Theme = .init(),
style: PresentationStyle = .sheet,
on controller: UIViewController,
delegate: PaymentDelegate
)
Parametreler:
token:initialize(context:)metodundan elde edilen token.data: Ödeme işlemine dair bilgileri içerenPaymentData.theme: SDK görünümünü özelleştiren tema. Opsiyonel.style: Sunum biçimi..sheetveya.fullScreen.on: SDK'yı present edecekUIViewController.delegate: SDK tamamlandığındabkmExpressPaymentFinished(with:)metodu çağırılacakPaymentDelegate.
selectCard(token:theme:style:on:onFinished:)
Kart seçimi akışını başlatır (closure versiyonu).
static func selectCard(
token: InitializationToken,
theme: Theme = .init(),
style: PresentationStyle = .sheet,
on controller: UIViewController,
onFinished: @escaping (CardSelectionResult) -> Void
)
Parametreler:
token:initialize(context:)metodundan elde edilen token.theme: SDK görünümünü özelleştiren tema. Opsiyonel.style: Sunum biçimi..sheetveya.fullScreen.on: SDK'yı present edecekUIViewController.onFinished: SDK tamamlandığında çağırılacak closure.CardSelectionResultiletilir.
selectCard(token:theme:style:on:delegate:)
Kart seçimi akışını başlatır (delegate versiyonu).
static func selectCard(
token: InitializationToken,
theme: Theme = .init(),
style: PresentationStyle = .sheet,
on controller: UIViewController,
delegate: CardSelectionDelegate
)
Parametreler:
token:initialize(context:)metodundan elde edilen token.theme: SDK görünümünü özelleştiren tema. Opsiyonel.style: Sunum biçimi..sheetveya.fullScreen.on: SDK'yı present edecekUIViewController.delegate: SDK tamamlandığındabkmExpressCardSelectionFinished(with:)metodu çağırılacakCardSelectionDelegate.
InitializationContext
SDK oturumu başlatmak için gereken bilgileri içeren veri yapısıdır.
BKMExpress.InitializationContext(
authToken: String, // Auth tokeniniz.
merchantID: String, // Merchant identifier'ınız.
merchantUserID: String, // Kullanıcı identifier'ınız.
gsmNo: GSMNO, // Kullanıcıya ait telefon numarası.
currencyCode: String, // ISO 4217 para birimi kodu (örn. "TRY").
mode: Mode // Ortam modu.
)
Parametreler:
authToken: Kendi sunucularınızdan elde edeceğiniz auth tokeni.merchantID: Entegrasyon sonucunda size verilen merchant identifier.merchantUserID: Kullanıcınızı tanımlamak için kullandığınız identifier.gsmNo: Kullanıcıya ait geçerli bir Türkiye telefon numarası (GSMNOinstance'ı).currencyCode: ISO 4217 standardında 3 haneli para birimi kodu. Yerleşik sabitler:BKMExpress.CurrencyCode.TRY,.USD,.EUR.mode: Ortam modu. Test esnasında.testveya.preprod, üretimde.productionkullanılmalıdır.
GSMNO
SDK tarafından desteklenen, geçerli bir Türkiye telefon numarasını temsil eden veri yapısıdır.
BKMExpress.GSMNO(_ rawValue: String)
Kurallar:
- 10 haneden oluşmalıdır.
- Yalnızca rakamlardan oluşmalıdır.
5rakamıyla başlamalıdır.
Koşullar sağlanmadığında init nil döner (InitializationError fırlatmaz). Failable init kullanımı:
guard let gsmNo = BKMExpress.GSMNO("5XXXXXXXXX") else {
// Geçersiz numara.
return
}
PaymentData
Ödeme işlemi için gerekli bilgileri içeren veri yapısıdır.
BKMExpress.PaymentData(
amount: Decimal,
security: PaymentSecurity,
installmentCount: InstallmentCount,
orderID: String,
successUrl: String,
failUrl: String
)
Parametreler:
amount: Ödeme tutarı.security: Güvenlik mekanizması..otp,.tdsveya.none.installmentCount: Taksit sayısı (InstallmentCountinstance'ı, pozitif tam sayı).orderID: Siparişinizi tanımlayan identifier.
Satıcı backend bildirim URL’leri: successUrl ve failUrl, ödeme işleminin sunucu tarafında
tamamlanması veya başarısız kalması durumunda satıcı backend’inizin bilgilendirilmesi için
kullanılır. SDK bu adresleri ödeme işlemi isteklerinde kullanır.
successUrl: Ödeme süreci başarıyla tamamlandığında satıcı backend’inize yönlendirilecek veya çağrılacak bildirim adresi. Tam, erişilebilir bir URL (ör. HTTPS) olmalıdır. Varsayılan:""(boş string).failUrl: Ödeme süreci başarısız olduğunda, iptal edildiğinde veya tamamlanamadığında satıcı backend’inize iletilecek bildirim adresi. Varsayılan:""(boş string).
PaymentResult
Ödeme akışının nasıl tamamlandığını belirten enum'dur.
enum BKMExpress.PaymentResult {
case completed // Ödeme başarıyla tamamlandı.
case cancelled // Kullanıcı akışı iptal etti.
case failed(Failure) // Hata oluştu.
}
Örnek:
BKMExpress.pay(token: token, data: paymentData, on: self) { result in
switch result {
case .completed:
navigateToSuccessScreen()
case .cancelled:
print("Kullanıcı ödemeyi iptal etti.")
case .failed(let failure):
showError(failure.message)
}
}
CardSelectionResult
Kart seçimi akışının nasıl tamamlandığını belirten enum'dur.
enum BKMExpress.CardSelectionResult {
case selected(Card) // Kullanıcı bir kart seçti.
case cancelled // Kullanıcı akışı iptal etti.
case failed(Failure) // Hata oluştu.
}
Örnek:
BKMExpress.selectCard(token: token, on: self) { result in
switch result {
case .selected(let card):
print("Kart seçildi: \(card.alias), \(card.maskedCardNumber)")
case .cancelled:
print("Kart seçimi iptal edildi.")
case .failed(let failure):
showError(failure.message)
}
}
Failure
SDK'da oluşan bir hatayı temsil eden veri yapısıdır.
struct BKMExpress.Failure: LocalizedError {
let kind: Kind // Hata türü: .session, .encryption, .server(code:)
let message: String // Kullanıcıya gösterilebilecek hata mesajı.
let reason: String? // Teknik hata detayı. Opsiyonel.
var code: Int? // Sunucu hata kodu. Yalnızca .server türü hatalar için dolu gelir.
}
Hata Türleri:
.session: Oturum hatası..encryption: Şifreleme hatası..server(code:): Sunucu taraflı hata.codeile HTTP hata kodu erişilebilir.
PaymentDelegate
Ödeme akışı tamamlandığında bildirim almak için kullanılan protokoldür.
public protocol PaymentDelegate: AnyObject {
func bkmExpressPaymentFinished(with result: BKMExpress.PaymentResult)
}
Örnek:
extension CheckoutViewController: BKMExpress.PaymentDelegate {
func bkmExpressPaymentFinished(with result: BKMExpress.PaymentResult) {
switch result {
case .completed: navigateToSuccessScreen()
case .cancelled: break
case .failed(let failure): showError(failure.message)
}
}
}
CardSelectionDelegate
Kart seçimi akışı tamamlandığında bildirim almak için kullanılan protokoldür.
public protocol CardSelectionDelegate: AnyObject {
func bkmExpressCardSelectionFinished(with result: BKMExpress.CardSelectionResult)
}
Örnek:
extension MyViewController: BKMExpress.CardSelectionDelegate {
func bkmExpressCardSelectionFinished(with result: BKMExpress.CardSelectionResult) {
switch result {
case .selected(let card): useCard(card)
case .cancelled: break
case .failed(let failure): showError(failure.message)
}
}
}
Card
BKM Express'e kayıtlı bir kartı temsil eden veri yapısıdır. CardSelectionResult.selected ile iletilir.
struct BKMExpress.Card {
let id: ID // Benzersiz kart identifier'ı.
let alias: String // Kullanıcının karta verdiği ad.
let maskedCardNumber: String // Maskelenmiş kart numarası.
let imageURL: URL? // Kart görseli URL'i. Opsiyonel.
let bankInformation: BankInformation
let bin: String
let createTime: Date
}
struct BKMExpress.Card.BankInformation {
let bankShortName: String
let cardType: String
let cardScheme: String
let cardBrand: String
let bankCode: String
}
PresentationStyle
SDK'nın nasıl gösterileceğini belirler.
enum BKMExpress.PresentationStyle {
case sheet // Modal sheet olarak gösterir.
case fullScreen // Tam ekran olarak gösterir.
}
Mode
SDK'nın hangi ortama istek atacağını belirler.
enum BKMExpress.Mode {
case test // Test ortamı.
case preprod // Ön üretim ortamı.
case production // Üretim ortamı.
}
Tema Özelleştirme
Genel Bakış
SDK, tint rengi ve buton köşe yarıçapı özelleştirmesini destekler. Tüm özelleştirmeler opsiyoneldir; yapılmadığında SDK varsayılan teması kullanılır.
Temel Kullanım
var theme = BKMExpress.Theme()
theme.tint = UIColor(red: 0.12, green: 0.47, blue: 0.71, alpha: 1) // Marka renginiz.
theme.buttonCornerRadius = .custom(8) // Köşe yarıçapı.
Özelleştirme Seçenekleri
Tint Rengi
SDK genelinde kullanılan vurgu rengidir.
theme.tint = .systemBlue // Sistem mavisi.
theme.tint = UIColor(...) // Özel renk.
Buton Köşe Yarıçapı
theme.buttonCornerRadius = .custom(12) // Belirli bir piksel değeri (varsayılan: 12).
theme.buttonCornerRadius = .capsule // Tam yuvarlak (hap şekli).
SwiftUI Modifier ile Özelleştirme
SwiftUI modifier'larında tema bir closure aracılığıyla değiştirilir:
.bkmExpressPaymentSheet(
token: $token,
data: paymentData,
theme: { theme in
theme.tint = UIColor(red: 0.85, green: 0.11, blue: 0.11, alpha: 1)
theme.buttonCornerRadius = .capsule
}
) { result in ... }
Kısmi Özelleştirme
Yalnızca değiştirmek istediğiniz özellikleri belirtmeniz yeterlidir:
var theme = BKMExpress.Theme()
theme.tint = .red // Sadece tint değiştirilir; köşe yarıçapı varsayılan kalır.
Tam Örnek
// UIKit
var theme = BKMExpress.Theme()
theme.tint = UIColor(red: 0.85, green: 0.11, blue: 0.11, alpha: 1)
theme.buttonCornerRadius = .capsule
BKMExpress.pay(token: token, data: paymentData, theme: theme, style: .sheet, on: self) { result in
// ...
}
// SwiftUI
.bkmExpressPaymentSheet(
token: $token,
data: paymentData,
theme: { $0.buttonCornerRadius = .custom(8) }
) { result in ... }
Gelişmiş Kullanım
Hata Yönetimi Kalıpları
Ağ Hatasında Yeniden Deneme
BKMExpress.pay(token: token, data: paymentData, on: self) { result in
if case .failed(let failure) = result, failure.kind == .session {
showRetryDialog(message: failure.message) {
Task { await self.startPayment() }
}
}
}
Tüm Sonuç Türlerini Yönetme
BKMExpress.pay(token: token, data: paymentData, on: self) { result in
switch result {
case .completed:
navigateToSuccessScreen()
case .cancelled:
// Kullanıcı akıştan çıktı; ekstra aksiyon gerekmez.
break
case .failed(let failure):
switch failure.kind {
case .session:
showError("Oturum hatası oluştu.")
case .encryption:
showError("Şifreleme hatası oluştu.")
case .server(let code):
showError("Sunucu hatası: \(code)")
}
}
}
Analitik Takibi
BKMExpress.pay(token: token, data: paymentData, on: self) { result in
switch result {
case .completed:
Analytics.track("payment_success")
case .cancelled:
Analytics.track("payment_cancelled")
case .failed(let failure):
Analytics.track("payment_error", properties: [
"kind": "\(failure.kind)",
"message": failure.message
])
}
}
En İyi Pratikler
1. Token Güvenliği
❌ Yapmayın — token'ı kaynak koduna gömmek:
let token = "sk_live_abc123..." // HATALI!
✅ Yapın — kendi backend'inizden çekin:
let authToken = try await yourAPI.requestBKMExpressToken()
2. Doğru Ortamı Kullanın
✅ Yapın — geliştirme ve test sırasında test ortamı kullanın:
mode: .test // veya .preprod
✅ Yapın — uygulamanızı App Store'a göndermeden önce production ortamına geçin:
mode: .production
3. Telefon Numarasını Doğrulayın
✅ Yapın — GSMNO failable init'ini kullanın:
guard let gsmNo = BKMExpress.GSMNO(userInputPhoneNumber) else {
showError("Lütfen geçerli bir telefon numarası girin.")
return
}
4. Tüm Sonuçları Yönetin
✅ Yapın — her zaman completed, cancelled ve failed durumlarını ele alın:
{ result in
switch result {
case .completed: /* ... */
case .cancelled: /* ... */
case .failed: /* ... */
}
}
Sorun Giderme
"BKM Express başlatılamadı" Hatası
Problem: initialize(context:) çağrısı hata fırlattı.
Çözümler:
authTokendeğerinin boş veya süresi dolmuş olmadığını kontrol edin.merchantIDvemerchantUserIDdeğerlerinin doğru olduğunu doğrulayın.- Cihazın internet bağlantısı olduğunu kontrol edin.
modeparametresinin kullandığınız token ortamıyla eşleştiğinden emin olun.
Akış Başlamıyor
Problem: pay veya selectCard çağrıldı ancak SDK görünmüyor.
Çözümler:
initialize(context:)çağrısının başarıyla tamamlandığından emin olun.on:parametresine iletilenUIViewController'ın aktif olduğunu kontrol edin.on:parametresine iletilen controller'ın zaten başka bir modal sunup sunmadığını kontrol edin.
SwiftUI'da Akış Başlamıyor
Problem: Token state'e atandı ancak SDK görünmüyor.
Çözümler:
tokenbinding'inin@Stateya da@Publishedolarak tanımlandığından emin olun.- Modifier'ın doğru view üzerinde uygulandığını kontrol edin.
- Token'ın
nil'den geçerli bir değere set edildiğini,nil'e değil, doğrulayın.
Derleme Hatası: 'BKMExpressSDK' Bulunamadı
Çözümler:
- SDK bağımlılığının
Package.swiftya da Xcode "Package Dependencies" ekranına eklendiğini doğrulayın. - Paketi resolve edin (Xcode: File → Packages → Resolve Package Versions).
- Projeyi temizleyip yeniden derleyin (Xcode: Product → Clean Build Folder).