Binding Card SDK for iOS

Overview

The OSL Pay BindCard SDK (the "Binding Card SDK") provides a secure payment-card binding service for integrator apps. Some merchants cannot store users' payment-card data because they do not hold the required financial licences. OSL holds the relevant licences and uses this SDK to help users bind cards while safeguarding card data.

You do not need to implement the card-binding UI or card-data storage. Configure the SDK and launch the card-binding flow. The Binding Card SDK exposes one core business method: OSLCardApp.bindCard.

For iOS, call OSLCardApp.setup once when the app starts to configure the runtime environment and risk-control capability. For each subsequent card-binding flow, call bindCard only.

Internal dependencies

The Binding Card SDK includes the proprietary OSLPayRiskSDK (Risk SDK) to collect required risk-control parameters. It is supplied as a separate dynamic xcframework with the Binding Card SDK. Link and embed both frameworks:

  • OSL_Card_SDK.xcframework: main Binding Card SDK
  • OSLPayRiskSDK.xcframework: Risk SDK and a dynamic runtime dependency of the main SDK

OSL_Card_SDK.xcframework already includes OSL_Card_SDK_Resources.bundle. Do not add an external resource bundle separately to the app target.

Integrate all remaining standard third-party dependencies through CocoaPods. See Add third-party dependencies for the required versions.

Card-binding flow

App 启动
   │
   ▼
Call OSLCardApp.setup() (configure the environment and initialize risk-control capability)
   │
   ▼
Your backend retrieves a single-use accessToken
   │
   ▼
Call OSLCardApp.bindCard()
   │
   ▼
The SDK loads and validates accessToken
   │
   ├── accessToken validation fails ──► onTokenInvalid (terminal callback); end the flow
   │
   ▼
Display the card-binding screen (the user enters payment-card details)
   │
   ├── API error ──► SDK Toast, or onToastShow when suppression applies
   │
   ├── Binding fails / user exits ──► onBindFailure (terminal callback); end the flow
   │
   ▼
Card binding succeeds
   │
   ▼
onBindSuccess(cardId) (terminal callback); end the flow
  1. When the app starts, call setup and specify the Sandbox or Production environment.
  2. Your backend retrieves a single-use accessToken through the OpenAPI and provides it to the app.
  3. The app calls bindCard; the SDK validates accessToken and displays the card-binding screen.
  4. If binding fails, the SDK displays a Toast by default. The user can correct the details and retry.
  5. When the flow ends, the SDK returns the final result through onTokenInvalid, onBindSuccess, or onBindFailure.

Integrate the OSL Pay BindCard SDK

1.Build environment

The current SDK and demo use the following environment:

  • iOS 14.0 or later
  • Swift 5 language mode
  • CocoaPods 1.16.2
  • The SDK enables BUILD_LIBRARY_FOR_DISTRIBUTION and supports Swift module stability.
  • The current binary is compiled with Apple Swift 6.3.1 (effective-5.10).

Use the latest stable Xcode version compatible with the SDK artifact. The demo target uses IPHONEOS_DEPLOYMENT_TARGET 14.0.

2.Add SDK binaries

Add the following files to your project, for example:

Vendor/OSL_Card_SDK/OSL_Card_SDK.xcframework
Vendor/OSL_Card_SDK/OSLPayRiskSDK.xcframework

In Xcode, select your app target and open General > Frameworks, Libraries, and Embedded Content. Add both xcframework and set Embed to Embed & Sign for each one.

Alternatively, verify the following in Build Phases:

  • Both xcframework appear inLink Binary With Libraries
  • Both xcframework appear in Embed Frameworks
  • Enable Code Sign On Copy
  • Enable Remove Headers On Copy

OSLPayRiskSDK.xcframework is a required dynamic runtime dependency. If you add only OSL_Card_SDK.xcframework, the app cannot load the dynamic library at startup.

3.Add third-party dependencies

Use dynamic CocoaPods frameworks:

platform :ios, '14.0'
inhibit_all_warnings!
source 'https://github.com/CocoaPods/Specs.git'

use_frameworks! :linkage => :dynamic

pre_install do |installer|
  Pod::Installer::Xcode::TargetValidator
    .send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
end

target 'YourAppTarget' do
  pod 'ForterSDK', :git => 'https://bitbucket.org/forter-mobile/forter-ios-sdk.git', :tag => '3.0.4'
  pod 'HandyJSON', :git => 'https://github.com/hxm705/HandyJSON.git', :commit => 'de8a7126d2270da55cea3cb45dadffcfd002dbbe'
  pod 'IQKeyboardManager', '6.5.3'
  pod 'CocoaLumberjack', '3.8.1'
  pod 'RxSwift', '6.5.0'
  pod 'ReactiveObjC', '3.1.1'
  pod 'Masonry', '1.1.0'
  pod 'SnapKit', '5.6.0'
  pod 'MMKV', '1.2.11'
  pod 'Kingfisher', '7.8.1'
  pod 'lottie-ios', '3.3.0'
  pod 'LYEmptyView', '1.3.1'
  pod 'KingfisherSVG', '1.0.0'
  pod 'Risk', '3.0.4'
  pod 'QMUIKit', '4.8.0'
  pod 'Moya', '15.0.0'
  pod 'Alamofire', '5.10.2'
  pod 'SwiftyJSON', '5.0.2'
  pod 'DeviceKit', '5.7.0'
  pod 'FingerprintJS', '1.6.0'
  pod 'SwiftyRSA', '1.7.0'
end

post_install do |installer|
  installer.generated_projects.each do |project|
    project.targets.each do |target|
      target.build_configurations.each do |config|
        config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0'
        config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
      end
    end
  end

  installer.aggregate_targets.each do |aggregate_target|
    aggregate_target.user_project.native_targets.each do |target|
      target.build_configurations.each do |config|
        config.build_settings['ENABLE_USER_SCRIPT_SANDBOXING'] = 'NO'
      end
    end
    aggregate_target.user_project.save
  end
end
Replace `YourAppTarget` with your actual app target, then run:

```bash
pod install

Open the .xcworkspace thereafter; do not open the .xcodeproj directly.

4.Initialize the SDK

Call setup once in AppDelegate 's application(_:didFinishLaunchingWithOptions:)

import UIKit
import OSL_Card_SDK

@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        OSLCardApp.setup(
            openSandBoxEnv: true,
            with: launchOptions,
            disableTrack: true
        )
        return true
    }
}

Parameter reference:

| Parameter        | Required | Description |
| ---------------- | -------- | -------------------------------------------------------------------------------------- |
| `openSandBoxEnv` |    No    | Whether to use Sandbox. Defaults to `false` (Production). Pass `true` during development and `false` in production. |
| `launchOptions`  |    No    | Launch options received by `AppDelegate`. Pass them through unchanged.|
| `disableTrack`   |    No    | Whether to disable SDK analytics. Defaults to `false`. When `true`, the SDK does not initialize or report analytics.|

5.Permissions and network configuration

The current demo does not require privacy-usage descriptions for camera, photo library, location, or similar capabilities in Info.plist.

The SDK uses HTTPS for network access. iOS does not require INTERNET or ACCESS_NETWORK_STATE permissions. If your host app uses a custom App Transport Security (ATS) policy, ensure that it does not block the HTTPS requests required by the SDK.

Usage

1.SDK method overview

The Binding Card SDK exposes the following core business methods:

OSLCardApp.bindCard(...)

OSLCardApp.setup(...) 是 App 生命周期配置方法,应在应用启动时调用一次,不应在每次绑卡前重复调用。

2.Launch card binding

All bindCard parameters except accessToken have default values. Full example:

import OSL_Card_SDK

OSLCardApp.bindCard(
    accessToken: accessToken,       // Required; single-use only
    businessType: "BUY",           // Optional; defaults to BUY
    language: "zh_CN",             // Optional; the SDK selects a language when omitted
    theme: "light",                // Optional: light / dark
    phone: false,                   // Optional; whether to show the phone-number field
    suppressedErrorCodes: nil,      // Optional; error codes to suppress
    suppressErrors: false,          // Optional; whether to suppress all errors
    onTokenInvalid: { errorCode, errorMessage in
        // accessToken validation failure (terminal)
    },
    onBindSuccess: { cardId in
        // Card-binding success (terminal)
    },
    onBindFailure: { errorCode, errorMessage in
        // Binding failure or user exit (terminal)
    },
    onToastShow: { errorCode, errorMessage in
        // Immediate callback for a suppressed error; handle it in your app
    }
)

Minimum invocation:

```swift
OSLCardApp.bindCard(
    accessToken: accessToken,
     onBindSuccess: { cardId in
        print("Bind card success: \(cardId)")
    }
)

> `accessToken` is a sensitive credential. Do not write it to logs, persistent storage, or source control. Each token is single-use; obtain a new token before calling `bindCard` again.

3.Parameter reference

## 

| Parameter            | Required | Description |
| -------------------- | -------- | ------------|
> `accessToken` is a sensitive credential. Do not write it to logs, persistent storage, or source control. Each token is single-use; obtain a new token before calling `bindCard` again.

## 3. Parameter reference

| Parameter            | Required | Description |
| -------------------- | -------- | ------------------------------------------------------------------------------------------- |
| `accessToken`        | **Yes**  | User-identity validation token. It is single-use; obtain a new token before the next `bindCard` call. |
| businessType         | No       | Business type. Defaults to BUY; available values depend on the services enabled for your merchant account, such as BUY and SELL. |
| language             | No       | SDK display language, for example zh_CN or en_US. See Supported SDK languages for valid values. |
| theme                | No       | UI theme. Valid values are light and dark. When nil, the SDK uses its default theme. |
| phone                | No       | Whether to display the phone-number field on the card-binding screen. Defaults to false. |
| suppressedErrorCodes | No       | List of error codes to suppress. When a code matches, the SDK does not display a Toast and invokes onToastShow. |
| suppressErrors       | No       | Whether to suppress all errors. Defaults to false. When true, the SDK does not display error Toasts and invokes onToastShow. |
| onTokenInvalid       | No       | Callback for accessToken validation failure. Returns errorCode and errorMessage (terminal callback). |
| onBindSuccess        | No       | Callback for successful card binding. Returns the bound cardId (terminal callback). |
| onBindFailure        | No       | Callback for binding failure or user exit. Returns errorCode and errorMessage (terminal callback). |
| onToastShow          | No       | Immediate callback for suppressed errors; handle the error message in your app. |

4.Callback behavior

The Binding Card SDK provides 2 callback types:

  • Terminal callbacks: onTokenInvalid,onBindSuccess,onBindFailure are invoked when the card-binding flow ends. At most one is invoked in a card-binding session.
  • Immediate callback: onToastShow is invoked as soon as a suppressed error occurs and may appear with a subsequent terminal callback in the same session.

Perform all UI updates on the main thread:

onBindFailure: { errorCode, errorMessage in
    Task { @MainActor in
        // Update UI state
    }
}

5.Error-handling strategy

| Scenario                                  | SDK behavior                                                   |
| ----------------------------------------- | -------------------------------------------------------------- |
| No suppression configured                 | The SDK displays a Toast with the error message.               |
| Error code matches `suppressedErrorCodes` | The SDK does not display a Toast and invokes `onToastShow`.    |
| `suppressErrors = true`                   | The SDK suppresses all error Toasts and invokes `onToastShow`. |

Supported SDK languages

Use the following identifiers for the language parameter:

Language code / IdentifierLanguage name
ar_SAالعربية
de_DEDeutsch
en_USEnglish
es_AREspañol (Internacional)
es_ESEspañol
fr_FRFrançais
in_IDBahasa Indonesia
it_ITItaliano
ja_JP日本語
nl_NLNederlands
pl_PLPolski
pt_BRPortuguês (Brasil)
pt_PTPortuguês (Portugal)
ru_RUрусский
sv_SESvenska
th_THไทย
tr_TRTürkçe
uk_UAУкраїнська
uz_UZoʻzbek
vi_VNTiếng Việt
zh_CN简体中文
zh_TW繁體中文

Official reference documentation

  1. Sandbox Test Guide
  2. Generate AccessToken
  3. OSL Pay Risk SDK


Did this page help you?