*New - iOS ECR SDK

Use the NamiECR SDK to integrate payment functionality into iOS and iPadOS applications. The SDK supports native Swift and Objective‑C.
Follow the steps in this guide to initialize the SDK, connect to a terminal, perform transactions, and handle responses.

For environment setup and SDK details. refer to iOS ECR SDK Library.

Supported Connections (iOS SDK)

PlatformConnection TypesNotes
iOSTCP/IP (Wi‑Fi / LAN)Stable network integration using IP + Port
iOSScan & Auto‑ConnectRequires ECR Adapter 2.4 service on POS terminal

Transaction Flow (iOS SDK)

Initialize SDK → Configure POS → Connect Device (TCP/IP or Scan) → Register (txnType 17) → Start Session (txnType 18) → Execute Transaction → Receive Response → Parse Response → Disconnect

iOS SDK Integration

Step 1: Initialize SDK

  • Ensure Xcode 14+, Swift 5.7+, and iOS 13.0 or later.
  • Connect the Nami terminal to Wi‑Fi.
  • Use the following code to initiate SDK:
import NamiECRSDK

Step 2: Choose Connection Method

The SDK supports two connection methods:

  • Direct TCP connection using terminal IP address and port
  • Automatic discovery by scanning available terminals

Option A: Direct TCP Connection

Call connectTCP() with the terminal IP address and port.

  • Handle success by showing connection status.
  • Handle failure by enabling scan and stop buttons.
ECRSDK.shared.connectTCP(ip: ip, port: port) { status, result in
    DispatchQueue.main.async {
        if status {
            let statusVC = self.storyboard?.instantiateViewController(
                identifier: "ConnectionStatusViewController"
            ) as! ConnectionStatusViewController
            NamiECRNavigationManager.shared.pushViewController(destinationVC: statusVC)
        } else {
            self.scanButton.isEnabled = true
            self.stopButton.isEnabled = true
            self.showToast(message: String(data: result ?? Data(), encoding: .utf8) ?? "No data")
        }
    }
}

Option B: Scan and Auto Connect

Scan available terminals and select a device from the list.

  • Once the device is selected, the SDK automatically establishes the connection.
  • No additional connectTCP() call is required.

Note: Scan and auto‑connect functionality requires the ECR Adapter 2.4 service to be available on the POS terminal.

Step 3: Scan Device

  • Start scanning for available terminals:
class  ConnectionsSettingViewController:ServiceDiscoveryDelegate{
ECRSDK.shared.scanDevice(delegate: self)
}

Step 4: Scan Complete

  • Handle scan completion.
  • Select the device from the list.
  • Push connection status view on success.
  • Show error toast on failure.

Use the following code to complete scanning.

class ConnectionsSettingViewController:ServiceDiscoveryDelegate{
func onScanCompleted(services: [String]) {
    showAlertWithList(devices: services) { device in
        ECRSDK.shared.onSelectDevice(deviceName: device, port: UInt16(self.portNumberTextField.text!)!) { status, result in
            self.handleConnectionResponse(status: status, result: result)
        }
    } onCancel: { isCancelled in }
}
}

Step 5: Select Device

Use the following code to select a device and connect to the terminal.

ECRSDK.shared.onSelectDevice(deviceName: device, port: UInt16(self.portNumberTextField.text!)!) { status, result in
    DispatchQueue.main.async {
        if status {
            let statusVC = self.storyboard?.instantiateViewController(
                identifier: "ConnectionStatusViewController"
            ) as! ConnectionStatusViewController
            NamiECRNavigationManager.shared.pushViewController(destinationVC: statusVC)
        } else {
            self.scanButton.isEnabled = true
            self.stopButton.isEnabled = true
            self.showToast(message: String(data: result ?? Data(), encoding: .utf8) ?? "No data")
        }
    }
}

Step 6: Stop and Disconnect

  • Stop scanning:
ECRSDK.shared.stopScan()
  • Disconnect terminal:
ECRDataManager.shared.isConnectionEstablished = false
ECRSDK.shared.disconnectTCP()

Step 7: Initiate Payment

Follow these steps to initiate a payment:

A) Set CRN

Set the Cash Register Number (CRN, 8‑digit numeric):

GlobalDataPrefrences.shared.lastCRN = cashRegisterNumberTextfield.text

B) Configure Terminal Printer

Set terminal printing preferences:

0 = Disable

1 = Enable

ECRDataManager.shared.enableTerminalPrinter = 0 // or 1

C) Compute Signature

Compute SHA‑256 signature for the transaction request:

let szSignature = ECRSDK.shared.computeSha256Hash(
    ecrTransactionReferenceNumber + GlobalDataPrefrences.shared.lastConnectedTerminalId!
)

D) Generate ECR Reference Number

Use the following method to get the ECR transaction reference number:

private func getECRTransactionReferenceNumber() -> String {
    let referenceNumber = ECRDataManager.shared.formattedEcrRefNumber()
    return GlobalDataPrefrences.shared.lastCRN! + (referenceNumber as String)
}

E) Get Timestamp

Format the current date and time:

private func getFormattedCurrentDate() -> String {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "ddMMyyHHmmss"
    dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
    return dateFormatter.string(from: Date())
}

F) Build Transaction Request

Build the input request data:

buildInputRequestData(
    for: selectedTransactionType,
    dateTimeStamp: dateTimeStamp,
    etpInput: etpInput,
    ecrTransactionReferenceNumber: ecrTransactionReferenceNumber
)

G) Convert to Hex and Execute

  • Convert to Hex.
    public func asciiToHex(_ input: String) -> String {
        return input.map { String(format: "%02x", $0.asciiValue ?? 0) }.joined()
    }
  • Use the following code to call doTransaction():
ECRSDK.shared.doTransaction(
    inputReqData: hexData as NSString,
    selectedTransactionType: selectedTransactionType.rawValue,
    szSignature: szSignature as NSString
) { status, response in
    DispatchQueue.main.async {
        self.hideLoaderWithAnimatedImageView()
        self.handleTransactionResponse(
            status: status,
            response: response,
            selectedTransactionType: selectedTransactionType
        )
    }
}

Transaction Types

Transaction TypeRequired DataElement Description
PurchasedateTimeStamp;amount;etpInput;ecrRefNo!Amount must be converted to 12‑digit string (e.g., 10.25 → 000000001025).
Purchase with NaqddateTimeStamp;totalAmount;naqdAmount;etpInput;ecrRefNo!totalAmount = total purchase; naqdAmount = cashback.
RefunddateTimeStamp;amount;rrn;etpInput;originalDate;ecrRefNo!Requires refund amount, 12‑digit RRN, and original date.
AuthorizationdateTimeStamp;authAmount;etpInput;ecrRefNo!Authorization amount from AuthorizationTransactionCell.
AdvicedateTimeStamp;authAmount;rrn;transactionDate;approvalCode;partialFlag;etpInput;ecrRefNo!partialFlag: 1 = Partial, 0 = Full.
Auth ExtensiondateTimeStamp;rrn;transactionDate;approvalCode;etpInput;ecrRefNo!Requires RRN, transaction date, and approval code.
Auth VoiddateTimeStamp;authAmount;rrn;transactionDate;approvalCode;etpInput;ecrRefNo!Requires original amount, RRN, date, and approval code.
Cash AdvancedateTimeStamp;authAmount;etpInput;ecrRefNo!Cash advance amount.
DuplicatedateTimeStamp;previousECR;ecrRefNo!Previous ECR reference number.
ReversaldateTimeStamp;rrn;etpInput;ecrRefNo!Requires 12‑digit RRN.
ReconciliationdateTimeStamp;etpInput;ecrRefNo!Simple string built from three parameters.

Handle Response

  • Response is returned in completion handler.
  • Decrypt with ECRCrypto.encryptDecrypt().
  • Parse JSON into TransactionResponse.
  • Display response items in ResponseListingViewController.
  • Show error alerts if parsing fails.
private func handleTransactionResponse(status: Bool, response: Data?, selectedTransactionType: SupportedTransactions) {
    guard status else {
        showAlert(message: "Transaction failed")
        return
    }
    guard let responseData = response,
          let responseHexCryptoString = String(data: responseData, encoding: .utf8) else {
        showAlert(message: "Transaction failed to convert response")
        return
    }
    let plainHexText = ECRCrypto.encryptDecrypt(responseHexCryptoString)
    let decoder = JSONDecoder()
    if let data = plainHexText.data(using: .utf8),
       let transactionResponse = try? decoder.decode(TransactionResponse.self, from: data) {
        displayResponseReceived(for: selectedTransactionType, with: [transactionResponse.responseBody])
    }
}