Skip to main content

iOS SDK Quick Start Guide

This quick guide provides a concise, start-to-finish walkthrough for getting from registration to a successful payment using the TapOnMobile SDK, so you can understand the main steps and act quickly without reading the full documentation.

Introduction

To check the full documentation, go to the next section and skip this Quick Start section.

Overall view:

  • 1. Start:
    • 1.1 Perform initialization once:
      • Check device compatibility.
      • Initialize SDK with environment & version.
    • 1.2 Registration:
      • Link the current device to a merchant user via backoffice.
    • 1.3 Login (if session is not valid: login not done, session expired...):
      • Start an active session with secure code.
  • 2. Usage:
    • 2.1 Get Terminal Information
    • 2.2 Allow localization permission:
      • Required for NFC proximity detection.
    • 2.3 Wait until prepare device is completed:
      • Device must be fully prepared before any transaction.
    • 2.4 Perform transactions:
      • Execute payments (sale, refund, etc.)
    • 2.5 Session Expiration
  • 3. End:
    • 3.1 Logout (if session is valid):
      • End current session gracefully.
    • 3.2 Unregister (can be called after registration is completed)
      • Unlink device from merchant.

Prerequisites: Worldline TapOnMobile SDK library integrated (Swift package manager or static frameworks).

Start

Initialization

This must be called to see if the device is capable to use the main functionalities. If the result is failure, the device is not supported and the library will not work:

TapOnMobile.shared.isTapToPaySupported()
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { result in
switch result {
case .success:
print("Is supported success.")
case .failure(let error):
print("Is supported failure: \(error)")
}
}
.store(in: &disposables)

The function initialization(...) is required to be called once:

TapOnMobile.shared.initialization(
environment: .sandboxTODO,
appVersion: TODO, // example: "1.0.0"
language: TapOnMobileLanguage // Available languages for TapOnMobile-UI
)
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { result in
switch result {
case .success:
print("Initialization success.")
case .failure(let error):
print("Initialization failure: \(error)")
}
}
.store(in: &disposables)

Registration (token)

Apart from registering the device with the Merchant portal with TapOnMobile.shared.beginRegistration(), the user can be registered with a token. The only thing required is a registrationCode (scanning a QR code can be useful to obtain it) and a secure code:

The "code" variable must be entered in the portal:

var isLoading = false // if true this should indicate a loading progress

var registrationCode: String = // replace this with your token, it can be useful to scan a QR code and convert it to a String

verifyRegistrationCode(registrationCode: registrationCode)


// Verify that the registrationCode has a good format and it is ready to be used
func verifyRegistrationCode(registrationCode: String) {
isLoading = true
TapOnMobile.shared.verifyRegistrationToken(registrationToken: registrationCode)
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { result in
switch result {
case .success(let isValid):
if isValid {
beginTokenRegistration(registrationCode: registrationCode)
} else {
isLoading = false
print("Verifiying device registration: Error Token not valid")
}
case .failure(let error):
isLoading = false
print("Verifiying device registration: Error \(error)")
}
}
.store(in: &disposables)
}

// Start the registration process, if success the user should enter a secure code

func beginTokenRegistration(registrationCode: String) {
isLoading = true
TapOnMobile.shared.beginTokenRegistration(registrationToken: registrationCode)
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { result in
self.isLoading = false
switch result {
case .success:
completeRegistration(registrationCode: registrationCode, pin: "1234") // the user should enter a secure code
case .failure(let error):
isLoading = false
print("Begining device registration: Error \(error)")
}
}
.store(in: &disposables)
}

// After beginTokenRegistration(...) is success, complete the registration

func completeRegistration(registrationCode: String, pin: String) {
isLoading = true

TapOnMobile.shared.endTokenRegistration(registrationToken: registrationCode, pin: pin)
.receive(on: DispatchQueue.main)
.sink { result in
isLoading = false
switch result {
case .success:
print("Registration complete.")
case .failure(let error):
print("Finisihg device registration: Error \(error)")
}
}
.store(in: &disposables)

// To know if the device is currently registered:

TapOnMobile.shared.isDeviceRegistered()
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
switch result {
case .success(let registered):
print("Device is registered: \(registered)")
case .failure(let error):
print("Device is registered failure: \(error)")
}

}

Device registered

Once registered, you can check the registration status using:

TapOnMobile.shared.isDeviceRegistered()
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
switch result {
case .success(let registered):
print("Device is registered: \(registered)")
case .failure(let error):
print("Device is registered failure: \(error)")
}
}

Login

Once the user has a device, the user must start an active session:

TapOnMobile.shared.doLogin(pin: pin)
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
switch result {
case .success:
print("Login success.")
case .failure(let error):
print("Login failure: \(error)")
}
}
.store(in: &disposables)

Usage

Get Terminal Information

To get useful information about the terminal this can be used:

TapOnMobile.shared.getTerminalInfo(
)
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
switch result {
case .success(let terminalInfo):
print("Get terminal info obtained.")
// Check terminalInfo variable to access useful data
case .failure(let error):
print("Get terminal info failure: \(error)")
}
}

Location Permission

Required for transactions.
If isLocationDenied() gives true, the user can't use the main SDK functionalities. It should be explained to the user that the location services must be granted to use the App and also a button or some sort of navigation should be shown to the user to redirect the user to the Settings and enable the location permission, since requestLocation() will not work. If this gives false, isLocationAuthorized() can then be checked.If isLocationAuthorized() gives true, the user can use the main SDK functionalities.If both give false, requestLocation() can be called. If the user accepts isLocationAuthorized() will return true:

let isAuthorized = TapOnMobile.shared.isLocationAuthorized()
let isDenied = TapOnMobile.shared.isLocationDenied()

TapOnMobile.shared.requestLocation()
.receive(on: DispatchQueue.main)
.sink { result in
switch result {
case .success:
print("request location - Success")
case .failure(let error):
print("Request location - Error: \(error)")
}
}
.store(in: &disposables)

Prepare device

Calling prepareDevice() is required to complete before performing any transaction, the progress is being reported in real time. Add a listener before calling prepareDevice() and remove the listener when no more events are needed:

class ExampleClass: PrepareDeviceListener {

init() {
TapOnMobile.shared.removeAllPrepareDeviceListeners()
TapOnMobile.shared.addPrepareDeviceListener(self)
TapOnMobile.shared.prepareDevice()
}

public func onPercentageUpdated(percentage: Int) {
print("Prepare device progress: \(percentage)%")
}

public func onError(error: TapOnMobileError) {
print("Prepare device failure: \(error)")
}

public func onCompleted() {
TapOnMobile.shared.removePrepareDeviceListener(self)
print("Prepare device completed.")
}
}

Sale

Everything is ready now, the user can perform a transaction:

TapOnMobile.shared.doPayment(
currency: currency,
requestedAmount: amount,
reference: reference,
tipAmount: tipAmount,
container: getRootViewController(),
checkoutId: checkoutId
)
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
switch result {
case .success(let paymentProcessEvent):
switch paymentProcessEvent {
case .completed(let transactionDetail):
let transactionId = transactionDetail.transactionId
print("Payment complete with transaction id: \(transactionId)")
default:
print("Payment update: \(paymentProcessEvent)")
}
case .failure(let error):
print("Payment error: \(error)")
}
}
.store(in: &disposables)

Session Expiration

When the session expires, the SDK broadcasts a notification allowing you to track expiration in real time. You can also retrieve the exact expiration timestamp to proactively handle session renewal before it expires. When the session expires, users must authenticate again by calling doLogin(pin:) to continue using the application.

NOTE: There are 3 ways to know if the session is expired. One is to get an error while performing a transaction indicating that the session is expired. The other two are described in here:

// Get session expiration manually
TapOnMobile.shared.getSessionExpiration()
.sink { result in
if case .success(let timestamp) = result {
print("Session expires: \(Date(timeIntervalSince1970: timestamp))")
}
}
.store(in: &disposables)

//
// Listen for expiration real time events
//
NotificationCenter.default.addObserver(
self,
selector: #selector(sessionExpired),
name: TapOnMobile.SESSION_EXPIRED_NOTIFICATION,
object: nil
)

@objc func sessionExpired() {
// Session has expired and the user must login again
// The user should be prompted to login again and navigate to login screen
// In the login screen this could be called, as described in the previous login section:
/*
TapOnMobile.shared.doLogin(pin: pin)
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { [weak self] result in
switch result {
case .success:
print("Login success.")
case .failure(let error):
print("Login failure: \(error)")
}
}
.store(in: &disposables)
*/
}

End

Logout

TapOnMobile.shared.doLogout()
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { result in
switch result {
case .success:
print("Logout completed")
case .failure(let error):
print("Logout failure: \(error)")
}
}
.store(in: \&disposables)
``


### Unregister

Removes the link between the device and the user. Perform registration again to make a new link:

```swift
TapOnMobile.shared.unregister()
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.sink { result in
switch result {
case .success:
print("Unregister completed")
case .failure(let error):
print("Unregister failure: \(error)")
}
}
.store(in: &disposables)