*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)
| Platform | Connection Types | Notes |
|---|---|---|
| iOS | TCP/IP (Wi‑Fi / LAN) | Stable network integration using IP + Port |
| iOS | Scan & Auto‑Connect | Requires 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 Type | Required Data | Element Description |
|---|---|---|
| Purchase | dateTimeStamp;amount;etpInput;ecrRefNo! | Amount must be converted to 12‑digit string (e.g., 10.25 → 000000001025). |
| Purchase with Naqd | dateTimeStamp;totalAmount;naqdAmount;etpInput;ecrRefNo! | totalAmount = total purchase; naqdAmount = cashback. |
| Refund | dateTimeStamp;amount;rrn;etpInput;originalDate;ecrRefNo! | Requires refund amount, 12‑digit RRN, and original date. |
| Authorization | dateTimeStamp;authAmount;etpInput;ecrRefNo! | Authorization amount from AuthorizationTransactionCell. |
| Advice | dateTimeStamp;authAmount;rrn;transactionDate;approvalCode;partialFlag;etpInput;ecrRefNo! | partialFlag: 1 = Partial, 0 = Full. |
| Auth Extension | dateTimeStamp;rrn;transactionDate;approvalCode;etpInput;ecrRefNo! | Requires RRN, transaction date, and approval code. |
| Auth Void | dateTimeStamp;authAmount;rrn;transactionDate;approvalCode;etpInput;ecrRefNo! | Requires original amount, RRN, date, and approval code. |
| Cash Advance | dateTimeStamp;authAmount;etpInput;ecrRefNo! | Cash advance amount. |
| Duplicate | dateTimeStamp;previousECR;ecrRefNo! | Previous ECR reference number. |
| Reversal | dateTimeStamp;rrn;etpInput;ecrRefNo! | Requires 12‑digit RRN. |
| Reconciliation | dateTimeStamp;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])
}
}
Updated 1 day ago
