Changelog
All notable changes to this project will be documented in this file.
[2.2.0] - 2026-09-29
Added
- Added unified anti-fraud providers support with native
DeunaFraudModuleon both Android and iOS. - Added native support for Mercado Pago device fingerprinting with early background initialization (
initializeFraudProviders). - Added native support for Accertify, Riskified, Cybersource, and Signifyd fraud detection providers.
- Added Expo Config Plugin (
withFraudProviders) to automatically configure native anti-fraud dependencies and CocoaPods subspecs. - Added automatic fraud provider prewarming in example app on mount and configuration updates.
Changed
- Updated native DEUNA SDK dependencies: Android SDK to
2.12.7and iOS SDK to~> 2.12.6.
[2.1.10] - 2026-09-11
Added
- Enabled third-party cookies on Android
DeunaWebView(thirdPartyCookiesEnabled) to support redirect and authentication flows requiring session cookies.
Fixed
- Implemented state-based process-wide mutex in
ExternalUrlHelperto strictly prevent duplicate external URL openings (3DS, modal, or in-app browser) while an external view is actively open. - Preserved asynchronous
AppStateclose detection forIN_APP_BROWSER(Chrome Custom Tabs) on Android while enforcing process-wide mutex. - Routed
WebViewEventType.openExternalUrlandWebViewEventType.redirectinBaseWebViewControllerthroughnotifyOpenExternalUrlto ensure debounce and mutex checks are applied consistently. - Fixed
ExternalUrlControllerto handlecloseExternalUrlevents sent from external WebViews. - Added
resetReopenGuardcleanup inDeunaSDK.setWidgetControllerto prevent orphaned static mutex states across new widget initializations. - Moved
Opening external URLlog inDeunaSDKto execute only aftercanOpenUrlguard passes.
[2.1.9] - 2026-09-07
Removed
- Removed
deuna-web-sdkgit submodule andcopy-types.shscript to prevent CI build desyncs. - Embedded and directly versioned
src/types/within the repository.
[2.1.8] - 2026-09-07
Added
- Added
onOpenWindowprop forwarding toDeunaWidget. - Added
warnmethod toDeunaLogsand exportedDeunaLogs.
Fixed
- Fixed window popups blocking in iOS WebView by enabling
javaScriptCanOpenWindowsAutomatically. - Fixed trailing slashes in widget URLs when constructing controllers.
- Fixed duplicate URL openings and redirection loops across both WebView and In-App Browser via unified reopen guard in
ExternalUrlHelper.
Changed
- Centralized SDK logging into
DeunaLogsand removed redundant console logs across SDK and example apps.
[2.1.7] - 2026-08-11
Fixed
- Fixed
ELEMENTS_URLSimport path invaultApi.tsto referenceconstantsinstead ofbuildElementsLink.
[2.1.6] - 2026-08-06
Added
- Added
errorApmMissingReferencetoCheckoutEventTypeenum. PaymentWidgetControllernow fires theonErrorcallback withPaymentErrorType.paymentErrorwhen an APM reference fails to generate or display (generation_failed/display_failed).
[2.1.4] - 2026-06-10
Added
- Added
paymentMethodsEnteredandpaymentMethodsStartedto theElementsEventenum.
Fixed
initPaymentwidget (explore):userInfois now always forwarded to the widget regardless of whetheruserTokenis present, allowing testers to use both fields simultaneously.
[2.1.x] - 2026-05-12
🚨 BREAKING CHANGE — Native Wallet Support (Google Pay & Apple Pay)
Version 2.1.0 introduces native Google Pay and Apple Pay support via a new native module (DeunaWalletsModule). This requires additional setup steps that did not exist in previous versions.
What's new
sdk.getWalletsAvailable()— queries the vault API and filters by what the device actually supports natively.sdk.initElements()— launches the native Google Pay or Apple Pay payment sheet directly, without a WebView.
⚠️ Breaking: installation steps changed
Previous versions only required installing the npm package. Version 2.1.0 ships a native iOS/Android module that must be linked.
React Native CLI — run pod install after upgrading:
npm install @deuna/[email protected]
cd ios && pod installExpo (managed workflow) — re-run prebuild after upgrading:
npm install @deuna/[email protected]
npx expo prebuildIf you skip these steps, calling getWalletsAvailable() will always return [] and initElements() will throw.
⚠️ iOS (React Native CLI only): Xcode 16+ / Clang 16+ build fix required
Clang 16+ (shipped with Xcode 16+) rejects consteval calls inside the fmt pod that React Native includes. Add the following to the post_install block in your ios/Podfile:
post_install do |installer|
react_native_post_install(installer, config[:reactNativePath], :mac_catalyst_enabled => false)
# Fix: fmt consteval incompatibility with Xcode 16+ / Clang 16+
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if target.name == 'fmt'
config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++17'
end
end
end
endRe-run pod install after editing the Podfile.
Expo users do not need this step — the SDK's config plugin (withDeunaWallets) applies it automatically during expo prebuild.
⚠️ Breaking: Apple Pay requires entitlement + merchant ID
Apple Pay will never be available unless the app's provisioning profile includes the com.apple.developer.in-app-payments entitlement with your merchant ID.
Expo — add to app.json:
{
"expo": {
"ios": {
"entitlements": {
"com.apple.developer.in-app-payments": ["merchant.io.your-domain.com"]
}
}
}
}React Native CLI — add to ios/<AppName>/<AppName>.entitlements:
<key>com.apple.developer.in-app-payments</key>
<array>
<string>merchant.io.your-domain.com</string>
</array>⚠️ Breaking: Google Pay requires merchant enrollment
getWalletsAvailable() will not return google_pay unless the merchant account has Google Pay enabled in the DEUNA dashboard. Calling with an API key from a merchant without Google Pay returns [].
⚠️ Android (React Native CLI only): dependency compatibility patch required
deuna-sdk-android transitively pulls androidx.browser:1.10.0, kotlin-stdlib:2.1.x, and androidx.annotation:1.10.0, which are incompatible with the AGP 8.6.0 / Kotlin 1.9.x build environment shipped with React Native 0.76.x.
Add the following block to your android/app/build.gradle:
configurations.all {
resolutionStrategy {
force 'androidx.browser:browser:1.8.0'
force 'org.jetbrains.kotlin:kotlin-stdlib:1.9.25'
force 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.25'
force 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.25'
force 'androidx.annotation:annotation:1.8.2'
force 'androidx.annotation:annotation-jvm:1.8.2'
}
}Expo users do not need this step — the SDK's config plugin (withDeunaWallets) applies it automatically during expo prebuild.
Added
getWalletsAvailable(params)— returns the list of native wallet providers available on the current device for the given order.initElements(params)— launches the native wallet payment sheet (Google Pay or Apple Pay) and handles tokenization.- Native iOS module (
DeunaWalletsModule) implemented asRCTEventEmitter— zero Podfile changes required, linked automatically via React Native autolinking. - Native Android module (
DeunaWalletsModule) implemented asReactContextBaseJavaModule— zero Podfile/Gradle changes required, linked automatically via React Native autolinking. - Expo config plugin (
withAndroidDepsCompat) automatically patchesapp/build.gradlewith the dependency compatibility block duringexpo prebuild.
Fixed
- Android:
allowedCardNetworks(and other array/object credential fields) were incorrectly cast toString, causing a crash when launching Google Pay. Credentials are now recursively converted preserving arrays, nested objects, booleans, and numbers. - Android:
ObjectAlreadyConsumedException: Map already consumedcrash on Google Pay success —WritableMapwas passed to bothsendEventandpromise.resolve, consuming it twice. Each call now gets its own independent conversion. - iOS: Removed redundant conditional cast warning (
conditional cast from '[String: Any]' to '[String: Any]' always succeeds) in success callback logging.
[2.0.5] - 2026-04-28
Fixed
- Fixed a race condition for InAppBrowser close listener that was causing the WebView to be closed before the external url was closed.
[2.0.4] - 2026-03-26
Fixed
- Improved iOS in-app browser close handling by marking the browser as closed after returning from
openUrl.
Changed
- Updated external URL opening logic to detect user-initiated actions and bypass the 5-second reopen guard for explicit manual clicks.
[2.0.3] - 2026-03-26
Fixed
- Fixed a Mercado Pago redirect regression where reopening the widget could block opening the same in-app browser URL again.
- Added a reset of the in-app browser reopen guard on each new widget initialization (
payment,elements,nextAction,voucher) to allow valid retry flows. - Kept a 5-second in-app browser reopen guard to prevent immediate redirect loops while preserving reopening behavior across widget sessions.
- Fixed iOS
WKWebViewwarnings (Error evaluating injectedJavaScript ... unsupported return type) by making injected JavaScript snippets return a supported value (true).
[2.0.2] - 2026-03-25
Added
- Updated the web sdk types.
[2.0.1] - 2026-02-19
Added
- Added fraud_id & user_agent to the order object in the onSuccess callback
[2.0.0] - 2026-01-02
🚨 BREAKING CHANGES
This is a major version release with breaking changes. Please read the migration guide carefully.
What's Breaking:
- Removed
expo-web-browserdependency - No longer included as a dependency. Some merchants uses webpack to bundle their apps andexpo-web-browseris not compatible with webpack and we need to support it. - New adapter pattern required - Browser functionality now requires explicit adapter configuration
- API changes - SDK initialization for merchants that uses Mercado Pago wallet require an adapter configuration to open the redirect url in a custom tab or safari view controller.
Impact:
- External redirects still work and open in WebView by default
- Payments requiring Custom Tabs/Safari View Controller (like Mercado Pago wallet) now need custom adapter configuration
- In-app browser experience with native Custom Tabs (Android) or Safari View Controller (iOS) now requires manual setup via adapters
Added
- New Adapter Pattern: Introduced
InAppBrowserAdapterinterface for customizable browser behavior - DefaultInAppBrowserAdapter: Default implementation using React Native's
Linking.openURL() - Exported adapter types and implementations from
src/adapters/index.ts
📋 Migration Guide from 1.x to 2.0.0
Scenario 1: Basic Usage (No Changes Needed)
If you don't use any payment method that cannot be rendered in a tradicional webView like Mercado Pago Wallet, no changes are required. Otherwise, you need to configure a custom adapter using the InAppBrowserAdapter interface.
Scenario 2: Custom Tabs/Safari View Controller for Specific Payments
External redirects work by default and open in WebView. However, some payments (like Mercado Pago wallet) require opening in Custom Tabs (Android) or Safari View Controller (iOS) to function properly. For these cases, you need to configure a custom adapter.
Expo projects: Using expo-web-browser
1. Install the dependency:
npm install expo-web-browser
# or
yarn add expo-web-browser2. Create and use the adapter:
import { WebBrowser } from 'expo-web-browser';
import { InAppBrowserAdapter, DeunaSDK } from '@deuna/react-native-sdk';
class ExpoWebBrowserAdapter implements InAppBrowserAdapter {
private initialized = false;
private async initialize() {
if (this.initialized) return;
await WebBrowser.maybeCompleteAuthSession();
this.initialized = true;
}
async openUrl(url: string): Promise<void> {
try {
await this.initialize();
await WebBrowser.openBrowserAsync(url);
} catch (error) {
console.error('Error opening browser:', error);
throw error;
}
}
}
// Initialize SDK with custom adapter
const deunaSDK = DeunaSDK.initialize({
publicApiKey: 'your-public-api-key',
environment: 'production',
inAppBrowserAdapter: new ExpoWebBrowserAdapter(),
});React Native CLI projects: Using react-native-inappbrowser-reborn
1. Install the dependency:
npm install react-native-inappbrowser-reborn
# or
yarn add react-native-inappbrowser-reborn2. Create and use the adapter:
import InAppBrowser from 'react-native-inappbrowser-reborn';
import { InAppBrowserAdapter, DeunaSDK } from '@deuna/react-native-sdk';
class InAppBrowserRebornAdapter implements InAppBrowserAdapter {
async openUrl(url: string): Promise<void> {
try {
if (await InAppBrowser.isAvailable()) {
await InAppBrowser.open(url, {
dismissButtonStyle: 'cancel',
preferredBarTintColor: '#453AA4',
preferredControlTintColor: 'white',
readerMode: false,
animated: true,
});
} else {
// Fallback to system browser
await Linking.openURL(url);
}
} catch (error) {
console.error('Error opening in-app browser:', error);
throw error;
}
}
}
const deunaSDK = DeunaSDK.initialize({
publicApiKey: 'your-public-api-key',
environment: 'production',
inAppBrowserAdapter: new InAppBrowserRebornAdapter(),
});Warning: Currently
react-native-inappbrowser-rebornis not compatible with "Support 16 KB page sizes" feature of Android 15+ Recommendation. For more information, see Android 15+ Recommendation. And check react-native-inappbrowser-reborn for more information.
Option C: Using a custom adapter (If you don't want to use expo-web-browser or react-native-inappbrowser-reborn)
You can also create your own adapter by implementing the InAppBrowserAdapter interface:
import { InAppBrowserAdapter, DeunaSDK } from '@deuna/react-native-sdk';
import { Linking } from 'react-native';
class CustomBrowserAdapter implements InAppBrowserAdapter {
async openUrl(url: string): Promise<void> {
try {
// Your custom logic here
// Example: Add logging, analytics, or custom URL handling
console.log('Opening URL:', url);
// You could integrate with any browser library or custom WebView
// Or implement your own WebView modal, etc.
} catch (error) {
console.error('Error opening URL:', error);
}
}
}
const deunaSDK = DeunaSDK.initialize({
publicApiKey: 'your-public-api-key',
environment: 'production',
inAppBrowserAdapter: new CustomBrowserAdapter(),
});Before vs After Comparison
Before (v1.x):
// SDK handled browser opening automatically with expo-web-browser
const deunaSDK = DeunaSDK.initialize({
publicApiKey: 'your-public-api-key',
environment: 'production',
});In v1.x, the SDK automatically used
expo-web-browserinternally to open external URLs in Custom Tabs (Android) or Safari View Controller (iOS) when needed.
After (v2.0.0):
// You control how external URLs are opened
const deunaSDK = DeunaSDK.initialize({
publicApiKey: 'your-public-api-key',
environment: 'production',
inAppBrowserAdapter: new ExpoWebBrowserAdapter(), // Optional, uses default if not provided
});Why This Change?
- Metro and Webpack compatibility: Removed
expo-web-browserdependency to ensure the SDK works seamlessly with both Metro (React Native) and Webpack bundlers. - Better flexibility: Choose the browser implementation that works best for your app
- Reduced bundle size: Only include browser dependencies you actually need
- Platform compatibility: Works better with different React Native setups (Expo, bare React Native, etc.)
- Build system compatibility: Eliminates bundler conflicts that could occur with expo-web-browser in non-Expo environments
- Future-proof: Easier to adapt to new browser libraries or custom implementations