Skip to main content
On this page

Use a custom WebView only when your application must host an existing merchant-owned web checkout. For a new mobile integration, prefer the maintained iOS, Android, or React Native SDK; those SDKs already implement the DEUNA WebView bridge and external-action lifecycle.

Architecture#

Sequence diagram
1Native app2Merchant checkoutWebView3DEUNA Web SDK43DS / APM surfaceLoad allow-listed HTTPScheckout URLInitialize and open widgetCallback oropenExternalPopupValidated JSON bridgemessageOpen approved external URLClose or returnResume and reconcile
Merchant or customerDEUNAProvider or processor
01 · load
Open trusted checkout
Use HTTPS and an allow-listed merchant origin.
02 · bridge
Validate messages
Accept a versioned, minimal schema from the expected page only.
03 · redirect
Handle external actions
Present 3DS and APM URLs in an approved browser or secondary WebView.
04 · reconcile
Confirm order state
Treat return and closure as ambiguous until the backend verifies them.

See the WebView wrapper pattern#

This walkthrough shows a merchant web checkout loaded inside an iOS WebView. The native wrapper exchanges messages with the checkout page while DEUNA Web SDK renders the payment experience:

WebView wrapper example using a merchant checkout page and native message bridge.

The video demonstrates the presentation pattern. UI details can change; use the architecture, security boundaries, and platform requirements below as the implementation contract.

Required WebView capabilities#

CapabilityWhy it is required
JavaScript and DOM storageThe hosted checkout and SDK require browser execution and session storage.
New-window interception3DS and APM flows can use window.open.
Navigation allow-listPrevent the checkout WebView from becoming a general-purpose browser.
Bidirectional message bridgeForward safe completion, error, close, and lifecycle messages.
App lifecycle handlingPreserve state across backgrounding and external authentication.
Downloads or sharing, if usedVoucher flows can produce a file or downloadable reference.

Define a minimal bridge#

Code running in the merchant checkout pageJavaScript
type NativeMessage = {
  version: 1;
  type: 'success' | 'error' | 'closed' | 'event';
  widget: 'payment' | 'elements' | 'voucher' | 'nextAction';
  data?: unknown;
};

function postToNative(message: NativeMessage) {
  const body = JSON.stringify(message);
  window.webkit?.messageHandlers.deunaPayment?.postMessage(body); // iOS
  window.deunaPayment?.postMessage(body);                         // Android
  window.ReactNativeWebView?.postMessage(body);                   // React Native
}

At the native boundary, parse JSON with a strict schema, reject unknown message versions and types, cap message size, and ignore messages from an unexpected top-level page. Never expose a generic native method dispatcher to JavaScript.

Forward SDK outcomes#

JavaScript
await DeunaSDK.initPaymentWidget({
  orderToken,
  callbacks: {
    onSuccess: (data) => postToNative({version: 1, type: 'success', widget: 'payment', data}),
    onError: (data) => postToNative({version: 1, type: 'error', widget: 'payment', data}),
    onClosed: (action) => postToNative({version: 1, type: 'closed', widget: 'payment', data: {action}}),
    onEventDispatch: (event) => postToNative({
      version: 1,
      type: 'event',
      widget: 'payment',
      data: {event},
    }),
  },
});

Forward only the fields the native application needs. Do not bridge order tokens, wallet tokens, card data, complete customer objects, or arbitrary raw event payloads.

External windows and redirects#

The Web SDK emits lifecycle events for supported external popups. Your WebView must intercept window.open or new-window requests and present the target without falsely reporting it as immediately closed.

  • Allow only https URLs whose host matches your approved authentication or payment destinations.
  • Prefer an isolated browser surface for third-party content; do not inject the merchant bridge into an issuer or provider page.
  • Track the external surface independently from the checkout WebView.
  • On close or return, resume the checkout and retrieve the order state.
  • Do not suppress timeout errors globally. A timeout can represent a real incomplete action; reconcile, then show an appropriate recovery path.

The SDK repositories include maintained reference wrappers in Examples/checkout-web-wrapper for iOS and examples/checkout-web-wrapper for Android.

Platform checklist#

iOS · WKWebViewNavigation and script messages

Enable JavaScript for the trusted checkout configuration, register a narrowly named WKScriptMessageHandler, validate top-level navigation in WKNavigationDelegate, and implement WKUIDelegate new-window handling. Remove script handlers when the controller is disposed to avoid retaining the bridge.

Android · WebViewNavigation and window creation

Enable JavaScript and DOM storage only for the checkout WebView, use a constrained JavaScript interface, validate URLs in WebViewClient, and handle new windows through the WebChromeClient or a controlled secondary surface. Disable file and content access unless your application explicitly needs them.

React Native · react-native-webviewMessage and open-window lifecycle

Use onMessage, onShouldStartLoadWithRequest, and the supported new-window callback. Keep the main checkout component mounted while the external surface is visible. The maintained DEUNA React Native SDK already implements this controller and is preferred for new integrations.

Responsive and accessible presentation#

  • Respect safe-area insets and the on-screen keyboard.
  • Use the full available width and dynamic viewport height; avoid a fixed desktop-sized WebView.
  • Keep native close controls outside payment content but reachable by assistive technology.
  • Announce navigation and errors, and restore focus after an external surface closes.
  • Test rotation, split-screen, large text, screen readers, slow networks, and app backgrounding.

Test matrix#

  • Card success, decline, and customer closure.
  • Frictionless and challenged 3DS.
  • APM redirect success, cancellation, and provider timeout.
  • External window closed by the customer.
  • App backgrounded and later resumed.
  • Network loss before and after submission.
  • Untrusted navigation and malformed bridge messages are rejected.
  • Backend state is correct after every ambiguous client outcome.