Applies to: Mobile Payments SDK - Android
Learn how to pair and manage card readers with the Mobile Payments SDK for Android.
Applies to: Mobile Payments SDK - Android
Learn how to pair and manage card readers with the Mobile Payments SDK for Android.
The Mobile Payments SDK's ReaderManager lets you pair and monitor changes in Square Readers.
Physical reader devices cannot be used in the Square Sandbox. For testing purposes, you can use the Mock Reader UI to pair simulated readers and process mock payments with your application in the Square Sandbox.
The Mobile Payments SDK offers a preconfigured reader settings screen, built from the SDK's public API, that you can use in your application by calling settingsManager.showSettings(). This screen includes two tabs. The Devices tab displays the model and connection status for readers paired to the merchant's phone or tablet and includes a button for pairing a new reader. The About tab displays information about the Mobile Payments SDK, authorized location, and environment used to take payments. Users can also enable or disable consent for performance and analytics tracking from this screen, if they are in a region where consent is required.
Use the SettingsManager to programmatically retrieve information about the current sdkEnvironment (PRODUCTION or SANDBOX) and the current sdkVersion. You can also retrieve PaymentSettings for offline payments with settingsManager.getPaymentSettings.
You can check whether the settings screen is currently displayed with settingsManager.isShowingSettings() and programmatically dismiss it with settingsManager.closeSettings(). This is useful for kiosks, or when your application needs to respond to external events while settings are open.

fun showSettings() { val settingsManager = MobilePaymentsSdk.settingsManager() settingsManager.showSettings { result -> when (result) { is Success -> { val settingsClosed = result.value logSettingsResult(settingsClosed) } is Failure -> { logSettingsFailure(result.errorCode, result.errorMessage) } } } }
For more control over your reader pairing and management screens, you can create your own using information from the SDK's ReaderManager, which provides methods for pairing and forgetting readers, accessing information about a particular reader, and listening for reader status updates.
Pair a new reader using readerManager.pairReader(). Only one reader pairing can be in progress at one time, so check the Boolean value readerManager.isPairingInProgress and only begin pairing if it's false. readerManager.pairReader consumes a callback to notify your application when pairing completes. Use this callback to update progress indicators in your application and provide notifications to users based on whether reader pairing is successful.
fun pairReader() { val readerManager = MobilePaymentsSdk.readerManager() pairingHandle = readerManager.pairReader { result -> when (result) { is Success -> { val readerFound = result.value logPairingResult(readerFound) } is Failure -> { logPairingFailure(result.errorCode, result.errorMessage) } } } } fun onPause() { pairingHandle?.stop() }
The pairing callback is guaranteed to be called when pairing ends, even if no reader was successfully paired. When pairing completes, this callback's success value is a Boolean for whether a card reader paired. If the value is true a card reader was found, reported to the callback provided using setReaderChangedCallback, and added to the list of paired readers accessed with ReaderManager.getReaders(). A false value means the pairing was canceled. If pairing fails for any reason, the error description contains a PairingErrorCode with details about the failure.
The Mobile Payments SDK also provides the setReaderChangedCallback, which is called when the status of a reader changes. Use this callback to notify your application when magstripe readers are inserted or removed, contactless and chip readers are paired or disconnected with Bluetooth, or the battery status changes.
fun observeReaderChanges() { val readerManager = MobilePaymentsSdk.readerManager() callbackReference = readerManager.setReaderChangedCallback { event -> val reader = event.reader val change = event.change val readerStatus = event.readerStatus when (change) { ADDED -> // show reader added message REMOVED -> // show reader removed message else -> // handle other reader status changes } } } fun onPause() { callbackReference?.clear() }
Paired readers are remembered by the Mobile Payments SDK, so when a new card reader is paired to the application, it remains paired and present in the list of readers provided by readerManager.getReaders() and will automatically reconnect when the authorized Square seller loads your application. If you want to stop pairing before it completes, you can do so with the returned pairingHandle by calling pairingHandle.stop().
The ReaderInfo class provides information about Square readers paired with your application. These properties include:
CONTACTLESS, EMV, or SWIPED).You can use this information to notify merchants when a reader is unpaired or its battery is low. You can create your own screens to display information about the status of readers or use a Square-provided settings screen for quick integration.
Different readers offer different card entry methods. For example, Square Reader for magstripe can only accept swiped cards, while Square Reader for contactless and chip can accept tapped cards, dipped cards, or digital wallets. The card entry methods supported are available within a reader's readerInfo.supportedCardEntryMethods. To track changes in the entry methods (for example, if the NFC connection to a contactless reader times out) register a callback with paymentManager.setAvailableCardEntryMethodChangedCallback.
private fun updateAvailableMethods(view: TextView) { val paymentManager = MobilePaymentsSdk.paymentManager() // Set up a callback to update the card entry methods when they change callbackRef = paymentManager.setAvailableCardEntryMethodChangedCallback { methods -> updateCardEntryMethods(view, methods) } // Update the card entry methods immediately updateCardEntryMethods(view, paymentManager.getAvailableCardEntryMethods()) } private fun updateCardEntryMethods(view: TextView, methods: Set<CardEntryMethod>) { view.text = when (methods.size) { 0 -> "Reader not connected" 1 -> when (methods.first()) { CardEntryMethod.SWIPED -> "Swipe to pay" CardEntryMethod.CONTACTLESS -> "Tap to pay" CardEntryMethod.EMV -> "Insert to pay" } // Etc.. } }
Your application can monitor the current status of connected readers with readerInfo.status to display updates and messages to users. The possible status values are:
Ready: The reader is paired, connected, and able to accept card payments.Ready until physically disconnected from the mobile device.ConnectingToSquare: The reader is establishing a connection to Square's servers.ConnectingToDevice: The reader is establishing a connection to the mobile device.Faulty: The reader has encountered a hardware or connection error and is in an unrecoverable state.ReaderUnavailable: The reader is connected but not able to take payments.If a reader is unavailable, check ReaderUnavailable.reason for specific details, which may include bluetooth failure, a blocking firmware update, or issues with the merchant’s Square account. Depending on the reason, you can prompt the user to take action, or retry the connection with Square's servers with readerManager.retryConnection().
readerInfo.status is available in Android Mobile Payments SDK version 2.3.0 and above. If your integration uses an earlier version of the SDK, monitor the status of connected readers with readerInfo.state. The available states are Connecting, UpdatingFirmware, Disconnected, or FailedToConnect.
fun getReaders() { val readerManager = MobilePaymentsSdk.readerManager() val readers = readerManager.getReaders() // All readers ready to take payments val availableReaders = readers.filter { it.status == Ready }.size // All readers accepting tap payments val contactlessReaders = readers.filter { it.supportedCardEntryMethods.contains(CONTACTLESS) } // A specific Square reader val specificReader = readers.find { it.serialNumber == "4815162342LS815" } // Etc.. }
The ReaderInfo.firmwareInfo property provides structured firmware data through the ReaderFirmwareInfo class, which includes:
version: String? — The current firmware version installed on the reader.updateStatus: FirmwareUpdateStatus — The current firmware update status, represented as a sealed class with the following values:None — No firmware update is available or in progress.Pending(updateDate: Date) — A firmware update is scheduled for the specified date.InProgress(updatePercentage: Int?) — A firmware update is currently being installed, with an optional progress percentage.Deprecation notice:
readerInfo.firmwareVersion is deprecated. Use readerInfo.firmwareInfo.version instead.readerInfo.firmwarePercent is deprecated. Use readerInfo.firmwareInfo.updateStatus instead.fun checkFirmwareStatus() { val readerManager = MobilePaymentsSdk.readerManager() val readers = readerManager.getReaders() for (reader in readers) { val firmwareInfo = reader.firmwareInfo println("Firmware version: ${firmwareInfo.version}") when (val status = firmwareInfo.updateStatus) { is FirmwareUpdateStatus.None -> println("Firmware is up to date") is FirmwareUpdateStatus.Pending -> println("Update scheduled for: ${status.updateDate}") is FirmwareUpdateStatus.InProgress -> println("Updating: ${status.updatePercentage ?: "unknown"}%") } } }
You can schedule firmware updates to occur at a preferred time of day using readerSettings.preferredFirmwareUpdateTime. This property accepts a TimeOfDay value with hour (0–23) and minute (0–59) properties. Setting this value allows sellers to schedule reader firmware updates during off-hours to avoid interruptions during business operations.
fun setFirmwareUpdateTime() { val readerManager = MobilePaymentsSdk.readerManager() val readerSettings = readerManager.readerSettings // Schedule firmware updates for 2:00 AM readerSettings.preferredFirmwareUpdateTime = TimeOfDay(hour = 2, minute = 0) }