Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
## Changelog

### v2026.4.1 Apr 22, 2026

* Upgrade Android and iOS native SDK to `2.5.0`
* Add `SettingsManager.isShowingSettings()` to check whether the Settings screen is currently presented
* Add `SettingsManager.closeSettings()` to programmatically dismiss the Settings screen
* Add `ReaderManager.readerSettings()` which returns a new `ReaderSettings` object (`isReducedChargingModeEnabled`, `preferredFirmwareUpdateTime`). Adds a new `TimeOfDay` type (`hour`, `minute`) used by `preferredFirmwareUpdateTime`
* **Breaking:** `ReaderInfo.firmwareVersion` and `ReaderInfo.firmwarePercent` have been replaced by a single `ReaderInfo.firmwareInfo` object of shape `{ version, updatePercentage }`, mirroring the 2.5.0 native API
* **Breaking (Android):** Removed `ALIPAY`, `CASH_APP`, `SUICA`, `ID`, and `QUICPAY` from the mapped `Card.Brand` values — these were removed in native SDK `2.5.0`

### v2026.3.4 Mar 25, 2026

* Fix `AdditionalPaymentMethods` mapping to support combining multiple methods (e.g. `TAP_TO_PAY` + `KEYED`) on Android.
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ The SDK follows a standard React Native bridge pattern with four feature manager

## Platform Constraints

- **iOS**: Min deployment target 16. Depends on `SquareMobilePaymentsSDK ~> 2.4.0` and `MockReaderUI ~> 2.4.0`.
- **iOS**: Min deployment target 16. Depends on `SquareMobilePaymentsSDK ~> 2.5.0` and `MockReaderUI ~> 2.5.0`.
- **Android**: Min SDK 28, Compile/Target SDK 35. Kotlin 2.2.21. Proguard must be disabled (`minifyEnabled: false`).
- **Kotlin 2.2.x**: React Native 0.75.x Gradle plugin doesn't natively support Kotlin 2.2.x — requires `patch-package` workaround (see `docs/KOTLIN_COMPATIBILITY.md`).
- Not compatible with Expo Go (requires native code).
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

Mobile Payments SDK for React Native supports the following SDK versions:

* [iOS](https://developer.squareup.com/docs/mobile-payments-sdk/ios#1-install-the-sdk-and-dependencies): 2.4.0 and above
* [Android](https://developer.squareup.com/docs/mobile-payments-sdk/android#1-install-the-sdk-and-dependencies): 2.4.0 and above
* [iOS](https://developer.squareup.com/docs/mobile-payments-sdk/ios#1-install-the-sdk-and-dependencies): 2.5.0 and above
* [Android](https://developer.squareup.com/docs/mobile-payments-sdk/android#1-install-the-sdk-and-dependencies): 2.5.0 and above

## Review requirements
Before getting started, please review the Requirements and Limitations and Device Compatibility sections to ensure that the SDK can be used in your project:
Expand All @@ -14,7 +14,7 @@ Before getting started, please review the Requirements and Limitations and Devic

## Android: Kotlin 2.2.x Compatibility

Mobile Payments SDK 2.4.0 requires Kotlin 2.2.21, which is not yet supported by React Native's Gradle plugin (0.75.x and earlier). Android builds will fail unless you apply a small patch to your project. See the [Kotlin Compatibility Workaround](docs/KOTLIN_COMPATIBILITY.md) for step-by-step instructions.
Mobile Payments SDK 2.5.0 requires Kotlin 2.2.21, which is not yet supported by React Native's Gradle plugin (0.75.x and earlier). Android builds will fail unless you apply a small patch to your project. See the [Kotlin Compatibility Workaround](docs/KOTLIN_COMPATIBILITY.md) for step-by-step instructions.

## Installation
```sh
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ repositories {
}

def kotlin_version = getExtOrDefault("kotlinVersion")
def squareSdkVersion = "2.4.0"
def squareSdkVersion = "2.5.0"

dependencies {
// For < 0.71, this will be from the local maven repo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,22 @@ class MobilePaymentsSdkReactNativeModule(private val reactContext: ReactApplicat
promise.resolve(settingsManager.getSdkSettings().sdkVersion)
}

@ReactMethod
fun isShowingSettings(promise: Promise) {
reactContext.runOnUiQueueThread {
val settingsManager = MobilePaymentsSdk.settingsManager()
promise.resolve(settingsManager.isShowingSettings())
}
}

@ReactMethod
fun closeSettings(promise: Promise) {
reactContext.runOnUiQueueThread {
val settingsManager = MobilePaymentsSdk.settingsManager()
promise.resolve(settingsManager.closeSettings())
}
}

@ReactMethod
fun showMockReaderUI(promise: Promise) {
if (!MobilePaymentsSdk.isSandboxEnvironment()) {
Expand Down Expand Up @@ -330,7 +346,7 @@ class MobilePaymentsSdkReactNativeModule(private val reactContext: ReactApplicat

// pairReader
@ReactMethod
private fun pairReader(promise: Promise) {
fun pairReader(promise: Promise) {
if(pairingHandler != null) {
promise.reject("PAIRING_IN_PROGRESS", "A pairing is already in progress")
}
Expand All @@ -351,7 +367,7 @@ class MobilePaymentsSdkReactNativeModule(private val reactContext: ReactApplicat
}

@ReactMethod
private fun stopPairing(promise: Promise) {
fun stopPairing(promise: Promise) {
if(pairingHandler != null) {
pairingHandler?.stop()
pairingHandler = null;
Expand All @@ -360,6 +376,12 @@ class MobilePaymentsSdkReactNativeModule(private val reactContext: ReactApplicat
}
// ---

@ReactMethod
fun readerSettings(promise: Promise) {
val readerManager = MobilePaymentsSdk.readerManager()
promise.resolve(readerManager.readerSettings.toReaderSettingsMap())
}

private fun emitEvent(reactContext: ReactContext, eventName: String, map: WritableMap) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
Expand Down
45 changes: 38 additions & 7 deletions android/src/main/java/com/mobilepaymentssdkreactnative/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import com.squareup.sdk.mobilepayments.authorization.AuthorizedLocation
import com.squareup.sdk.mobilepayments.cardreader.CardEntryMethod
import com.squareup.sdk.mobilepayments.cardreader.ReaderChangedEvent
import com.squareup.sdk.mobilepayments.cardreader.ReaderInfo
import com.squareup.sdk.mobilepayments.cardreader.ReaderSettings
import com.squareup.sdk.mobilepayments.core.TimeOfDay
import com.squareup.sdk.mobilepayments.core.Result.Failure
import com.squareup.sdk.mobilepayments.payment.AdditionalPaymentMethod
import com.squareup.sdk.mobilepayments.payment.AdditionalPaymentMethod.Type
Expand Down Expand Up @@ -292,15 +294,10 @@ private fun Card.Brand.toBrandString(): String =
Card.Brand.JCB -> "JCB"
Card.Brand.CHINA_UNIONPAY -> "CHINA_UNIONPAY"
Card.Brand.SQUARE_GIFT_CARD -> "SQUARE_GIFT_CARD"
Card.Brand.ALIPAY -> "ALIPAY"
Card.Brand.CASH_APP -> "CASH_APP"
Card.Brand.EFTPOS -> "EFTPOS"
Card.Brand.FELICA -> "FELICA"
Card.Brand.INTERAC -> "INTERAC"
Card.Brand.SQUARE_CAPITAL_CARD -> "SQUARE_CAPITAL_CARD"
Card.Brand.SUICA -> "SUICA"
Card.Brand.ID -> "ID"
Card.Brand.QUICPAY -> "QUICPAY"
}

private fun Card.CoBrand.toCoBrandString(): String =
Expand Down Expand Up @@ -356,8 +353,10 @@ fun ReaderInfo.toReaderInfoMap(): WritableMap {
putString("serialNumber", serialNumber)
putString("name", name)
putMap("batteryStatus", batteryStatus?.toBatteryStatusMap())
putString("firmwareVersion", firmwareVersion)
putInt("firmwarePercent", firmwarePercent ?: 0)
putMap(
"firmwareInfo",
firmwareInfo.toFirmwareInfoMap()
)
putArray("supportedCardEntryMethods", WritableNativeArray().apply {
supportedCardEntryMethods.forEach {
pushString(it.toEntryMethodString())
Expand All @@ -368,6 +367,22 @@ fun ReaderInfo.toReaderInfoMap(): WritableMap {
}
}

fun ReaderInfo.ReaderFirmwareInfo.toFirmwareInfoMap(): WritableMap {
return WritableNativeMap().apply {
putString("version", version)
putInt("updatePercentage", updateStatus.toPercent() ?: 0)
putString("failureReason", null)
}
Comment thread
Armaxis marked this conversation as resolved.
}

fun ReaderInfo.FirmwareUpdateStatus.toPercent() : Int? {
return when(this) {
is ReaderInfo.FirmwareUpdateStatus.None -> null
is ReaderInfo.FirmwareUpdateStatus.InProgress -> this.updatePercentage
is ReaderInfo.FirmwareUpdateStatus.Pending -> null
}
}

fun CardEntryMethod.toEntryMethodString(): String {
return when(this) {
CardEntryMethod.EMV -> "EMV"
Expand Down Expand Up @@ -453,3 +468,19 @@ fun ReaderChangedEvent.Change.toChangeString(): String {
ReaderChangedEvent.Change.REMOVED -> "REMOVED"
}
}

fun ReaderSettings.toReaderSettingsMap(): WritableMap {
return WritableNativeMap().apply {
putBoolean("isReducedChargingModeEnabled", isReducedChargingModeEnabled)
putMap("preferredFirmwareUpdateTime", preferredFirmwareUpdateTime
?.toTimeOfDayMap()
)
}
}

fun TimeOfDay.toTimeOfDayMap(): WritableMap {
return WritableNativeMap().apply {
putInt("hour", hour)
putInt("minute", minute)
}
}
6 changes: 3 additions & 3 deletions docs/KOTLIN_COMPATIBILITY.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Kotlin 2.2.x Compatibility Workaround for React Native

Mobile Payments SDK 2.4.0 requires **Kotlin 2.2.21**, which introduces a breaking change with React Native's Gradle plugin (versions 0.75.x and earlier). The `KotlinTopLevelExtension` class was removed in Kotlin 2.2.x, causing the Android build to fail during Gradle configuration.
Mobile Payments SDK 2.5.0 requires **Kotlin 2.2.21**, which introduces a breaking change with React Native's Gradle plugin (versions 0.75.x and earlier). The `KotlinTopLevelExtension` class was removed in Kotlin 2.2.x, causing the Android build to fail during Gradle configuration.

This guide explains how to apply a patch to your project so you can use Mobile Payments SDK 2.4.0 with React Native until React Native itself adds support for Kotlin 2.2.x.
This guide explains how to apply a patch to your project so you can use Mobile Payments SDK 2.5.0 with React Native until React Native itself adds support for Kotlin 2.2.x.

> **Note:** This workaround is temporary. Once React Native releases a version with Kotlin 2.2.x support, you can remove the patch and `patch-package` dependency.

Expand Down Expand Up @@ -111,7 +111,7 @@ Applying patches...

### 5. Build your project

Your Android build should now succeed with Kotlin 2.2.21 and Mobile Payments SDK 2.4.0.
Your Android build should now succeed with Kotlin 2.2.21 and Mobile Payments SDK 2.5.0.

## Removing the Workaround

Expand Down
5 changes: 4 additions & 1 deletion example/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,15 @@ GEM
concurrent-ruby (~> 1.0)
json (2.8.2)
logger (1.6.1)
minitest (5.25.1)
minitest (6.0.5)
drb (~> 2.0)
prism (~> 1.5)
molinillo (0.8.0)
nanaimo (0.4.0)
nap (1.1.0)
netrc (0.11.0)
nkf (0.2.0)
prism (1.9.0)
public_suffix (4.0.7)
rexml (3.3.9)
ruby-macho (2.5.1)
Expand Down
3 changes: 2 additions & 1 deletion example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,15 @@ android {
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
pickFirsts += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
}
}
}

dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
// Mobile Payments SDK 2.4.0
// Mobile Payments SDK 2.5.0
implementation("com.squareup.sdk:mobile-payments-sdk:$squareSdkVersion")
implementation("com.squareup.sdk:mockreader-ui:$squareSdkVersion")
if (hermesEnabled.toBoolean()) {
Expand Down
2 changes: 1 addition & 1 deletion example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
targetSdkVersion = 35
ndkVersion = "26.1.10909125"
kotlinVersion = "2.2.21"
squareSdkVersion = "2.4.0"
squareSdkVersion = "2.5.0"
}
repositories {
google()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,14 +338,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests-resources.sh\"\n";
Expand All @@ -359,14 +355,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample/Pods-MobilePaymentsSdkReactNativeExample-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample/Pods-MobilePaymentsSdkReactNativeExample-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample/Pods-MobilePaymentsSdkReactNativeExample-resources.sh\"\n";
Expand Down Expand Up @@ -419,14 +411,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests/Pods-MobilePaymentsSdkReactNativeExample-MobilePaymentsSdkReactNativeExampleTests-frameworks.sh\"\n";
Expand All @@ -440,14 +428,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample/Pods-MobilePaymentsSdkReactNativeExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample/Pods-MobilePaymentsSdkReactNativeExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MobilePaymentsSdkReactNativeExample/Pods-MobilePaymentsSdkReactNativeExample-frameworks.sh\"\n";
Expand Down
16 changes: 8 additions & 8 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ PODS:
- hermes-engine (0.75.3):
- hermes-engine/Pre-built (= 0.75.3)
- hermes-engine/Pre-built (0.75.3)
- mobile-payments-sdk-react-native (2026.2.1):
- mobile-payments-sdk-react-native (2026.4.1):
- DoubleConversion
- glog
- hermes-engine
- MockReaderUI (~> 2.4.0)
- MockReaderUI (~> 2.5.0)
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
Expand All @@ -28,9 +28,9 @@ PODS:
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- SquareMobilePaymentsSDK (~> 2.4.0)
- SquareMobilePaymentsSDK (~> 2.5.0)
- Yoga
- MockReaderUI (2.4.0)
- MockReaderUI (2.5.0)
- Permission-BluetoothPeripheral (3.10.1):
- RNPermissions
- Permission-LocationAccuracy (3.10.1):
Expand Down Expand Up @@ -1581,7 +1581,7 @@ PODS:
- ReactCommon/turbomodule/core
- Yoga
- SocketRocket (0.7.0)
- SquareMobilePaymentsSDK (2.4.0)
- SquareMobilePaymentsSDK (2.5.0)
- Yoga (0.0.0)

DEPENDENCIES:
Expand Down Expand Up @@ -1823,8 +1823,8 @@ SPEC CHECKSUMS:
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
glog: 69ef571f3de08433d766d614c73a9838a06bf7eb
hermes-engine: 8d2103d6c0176779aea4e25df6bb1410f9946680
mobile-payments-sdk-react-native: 161fbdf5a7a5cd788224a78d361c08c5d2a3fb8c
MockReaderUI: e527a5bc446b95e8cd5ddb4c565fc7d614d38a0f
mobile-payments-sdk-react-native: 648e9e228798472f028ed9fd02ae172581ac1692
MockReaderUI: 651252bf60bffc2699866448a6fb7250c06be785
Permission-BluetoothPeripheral: 34ab829f159c6cf400c57bac05f5ba1b0af7a86e
Permission-LocationAccuracy: 30c5421911024b28d8916db5cbd728097da54434
Permission-LocationAlways: af165dee8a5a5888df6764f9f6ba98b112893709
Expand Down Expand Up @@ -1891,7 +1891,7 @@ SPEC CHECKSUMS:
RNScreens: 35bb8e81aeccf111baa0ea01a54231390dbbcfd9
RNVectorIcons: 182892e7d1a2f27b52d3c627eca5d2665a22ee28
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
SquareMobilePaymentsSDK: 53cd315a537037377cd364edc874bf75782239eb
Copy link
Copy Markdown

@rbeiter-block rbeiter-block Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validated these hashes - they are the sha1sum of the podspec:

  $ # For local/path pods, CocoaPods uses Specification#checksum which does:
    # Digest::SHA1.hexdigest(File.read(defined_in_file))
    echo "=== Trunk pod verification ==="
    echo "SquareMobilePaymentsSDK 2.5.0:"
    echo "  Podfile.lock says: 61d783cb2ef4b238731f4433a42028d95c77893c"
    echo "  pod spec cat hash: $(pod spec cat SquareMobilePaymentsSDK --version=2.5.0 2>/dev/null | shasum -a 1 | awk '{print
  $1}')"
    echo ""
    echo "MockReaderUI 2.5.0:"
    echo "  Podfile.lock says: 651252bf60bffc2699866448a6fb7250c06be785"
    echo "  pod spec cat hash: $(pod spec cat MockReaderUI --version=2.5.0 2>/dev/null | shasum -a 1 | awk '{print $1}')"
  === Trunk pod verification ===
  SquareMobilePaymentsSDK 2.5.0:
    Podfile.lock says: 61d783cb2ef4b238731f4433a42028d95c77893c
    pod spec cat hash: 61d783cb2ef4b238731f4433a42028d95c77893c

  MockReaderUI 2.5.0:
    Podfile.lock says: 651252bf60bffc2699866448a6fb7250c06be785
    pod spec cat hash: 651252bf60bffc2699866448a6fb7250c06be785

SquareMobilePaymentsSDK: 61d783cb2ef4b238731f4433a42028d95c77893c
Yoga: 4ef80d96a5534f0e01b3055f17d1e19a9fc61b63

PODFILE CHECKSUM: 81d2f9e3393262e2bc7a99478a8e3a6741f0482e
Expand Down
18 changes: 18 additions & 0 deletions ios/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,21 @@ extension ReaderChange {
}
}
}

extension ReaderSettings {
func toMap() -> NSDictionary {
return [
"isReducedChargingModeEnabled" : reducedChargingModeEnabled,
"preferredFirmwareUpdateTime" : preferredFirmwareUpdateTime?.toMap() ?? NSNull()
]
}
}

extension TimeOfDay {
func toMap() -> NSDictionary {
return [
"hour" : hour,
"minute" : minute
]
}
}
Loading
Loading