DropFi Mobile Injection Script

Understand how the DropFi mobile app injects the window.xrpl provider into web views. This script enables DApps to communicate with the DropFi mobile wallet through React Native WebView.

Overview

DropFi Mobile Injection Script

How window.xrpl is injected into mobile web views

The DropFi mobile injection script is injected into web views within the DropFi mobile app. This script creates the `window.xrpl` object that DApps use to interact with the DropFi mobile wallet. The script uses React Native WebView's postMessage API to communicate with the native mobile app.

React Native WebView

Uses ReactNativeWebView.postMessage for native communication

Duplicate Prevention

Checks for existing provider to prevent multiple injections

Event-Driven Architecture

Implements event listeners for wallet state changes

Promise-Based API

All methods return promises for async operations

Complete Injection Script

Here is the complete mobile injection script that gets injected into web views:

DropFi Mobile Injection Script

(function () {
    if (!window.ReactNativeWebView) return;
    if (window.xrpl && window.xrpl.isDropFi) { true; return; }
  
    console.log('[DropFi] Injected XRPL provider');
    const XRPLProvider = {
      isDropFi: true,
      selectedAddress: null,
      selectedNetwork: null,
      connectedAccounts: [],
      network: null,
      endpoint: null,
      listeners: {},
      resolvers: {},
  
      _emit(event, payload) {
        (this.listeners[event] || []).forEach((fn) => fn(payload));
      },
  
      on(event, cb) {
        this.listeners[event] = this.listeners[event] || [];
        this.listeners[event].push(cb);
      },
  
      off(event, cb) {
        if (!this.listeners[event]) return;
        this.listeners[event] = this.listeners[event].filter((fn) => fn !== cb);
      },
  
      createXRPLPromise(method, data = {}) {
        return new Promise((resolve) => {
          this.resolvers[method] = (result) => {
            if (method === 'xrpl_stateRequest' && result) {
              this.selectedAddress = result.selectedAddress;
              this.connectedAccounts = result.connectedAccounts;
              this.network = result.network;
              this.endpoint = result.endpoint;
              this._emit('xrpl_selectedAddress', result.selectedAddress);
              this._emit('xrpl_connectedAccounts', result.connectedAccounts);
              this._emit('xrpl_selectedNetwork', result.network);
            } else if (method === 'xrpl_connect' && result) {
              this.selectedAddress = result;
              this.connectedAccounts = [result];
              this._emit('xrpl_selectedAddress', result);
              this._emit('xrpl_connectedAccounts', [result]);
            } else if (method === 'xrpl_disconnect') {
              const old = this.selectedAddress;
              this.selectedAddress = null;
              this.connectedAccounts = [];
              this._emit('xrpl_selectedAddress', null);
              this._emit('xrpl_connectedAccounts', []);
              this._emit('xrpl_disconnect', old);
            } else if (method === 'xrpl_switchNetwork' && result) {
              this.network = result.network;
              this.endpoint = result.endpoint;
              this._emit('xrpl_selectedNetwork', result.network);
            }
  
            resolve(result);
          };
  
          window.ReactNativeWebView.postMessage(
            JSON.stringify({ method, params: data })
          );
        });
      },
  
      handleHostResponse(message) {
        try {
          const { method, payload } = JSON.parse(message?.data || '{}');
          if (this.resolvers[method]) {
            this.resolvers[method](payload);
          }
        } catch (err) {
          console.warn('[DropFi] Failed to handle host response', err);
        }
      },
  
      connect: (data) => XRPLProvider.createXRPLPromise('xrpl_connect', { data }),
      disconnect: () => XRPLProvider.createXRPLPromise('xrpl_disconnect'),
      signMessage: (message) => XRPLProvider.createXRPLPromise('xrpl_signMessage', { message }),
      sendTransaction: (tx) => XRPLProvider.createXRPLPromise('xrpl_sendTransaction', { tx }),
      switchNetwork: (networkId) => XRPLProvider.createXRPLPromise('xrpl_switchNetwork', { networkId }),
      changeAccount: (account) => XRPLProvider.createXRPLPromise('xrpl_changeAccount', { account }),
      initialize: () => XRPLProvider.createXRPLPromise('xrpl_stateRequest'),
  
      isConnected: () => !!XRPLProvider.selectedAddress,
    };
  
    window.addEventListener('message', (event) => {
      XRPLProvider.handleHostResponse(event);
    });
  
    window.xrpl = XRPLProvider;
  })();

Key Differences from Web Version

The mobile injection script has several key differences from the web version:

React Native WebView Check

First checks if window.ReactNativeWebView exists before injecting

Duplicate Prevention

Checks if window.xrpl already exists and is a DropFi provider to prevent double injection

Message Format

Uses JSON.stringify for postMessage instead of direct object passing

Response Parsing

Parses message.data as JSON in handleHostResponse, with error handling

Key Components

The mobile injection script consists of several key components:
1

Environment Check

Verifies ReactNativeWebView exists and prevents duplicate injection

Only injects if running in a React Native WebView and no existing DropFi provider is found

2

XRPLProvider Object

The main provider object that implements the window.xrpl API

Contains state properties (selectedAddress, network, etc.) and methods for wallet interaction

3

Event System

Implements on/off/_emit for event-driven communication

Allows DApps to listen for wallet state changes like address changes or network switches

4

Promise-Based Methods

createXRPLPromise creates promises that resolve when the app responds

Each method (connect, disconnect, etc.) uses this pattern to handle async communication

5

Native Communication

Uses ReactNativeWebView.postMessage to communicate with the native app

Messages are JSON stringified and sent to the native layer for processing

6

State Synchronization

Automatically updates internal state when responses are received

Updates selectedAddress, connectedAccounts, network, and endpoint based on app responses

Communication Flow

Understanding how the script communicates with the DropFi mobile app:

Request Flow

DApp calls window.xrpl.connect() → createXRPLPromise → ReactNativeWebView.postMessage → Native app receives message

Response Flow

Native app sends response → window.addEventListener receives → handleHostResponse → JSON.parse → resolver called → Promise resolves

Error Handling

handleHostResponse includes try-catch to gracefully handle JSON parsing errors

Public API Methods

The window.xrpl object exposes the following public methods (same as web version):
POST
connect(data)

Initiates connection to DropFi wallet

Parameters: data: object (optional) - returns Promise<string>

POST
disconnect()

Disconnects from the wallet

Parameters: None - returns Promise<void>

POST
signMessage(message)

Signs a message using the connected wallet

Parameters: message: string - returns Promise<string>

POST
sendTransaction(tx)

Sends a transaction to the XRP Ledger

Parameters: tx: object - returns Promise<string>

POST
switchNetwork(networkId)

Switches the active network

Parameters: networkId: string - returns Promise<object>

POST
changeAccount(account)

Changes the active account

Parameters: account: string - returns Promise<void>

GET
initialize()

Initializes and requests current wallet state

Parameters: None - returns Promise<object>

GET
isConnected()

Checks if wallet is currently connected

Parameters: None - returns boolean

Event System

The injection script supports an event system for listening to wallet state changes (same as web version):

Event Usage Example

// Listen for address changes
window.xrpl.on('xrpl_selectedAddress', (address) => {
  console.log('Address changed:', address);
});

// Listen for network changes
window.xrpl.on('xrpl_selectedNetwork', (network) => {
  console.log('Network changed:', network);
});

// Listen for disconnect events
window.xrpl.on('xrpl_disconnect', (oldAddress) => {
  console.log('Disconnected from:', oldAddress);
});

// Remove event listener
const handler = (address) => console.log(address);
window.xrpl.on('xrpl_selectedAddress', handler);
window.xrpl.off('xrpl_selectedAddress', handler);
Available events: xrpl_selectedAddress, xrpl_connectedAccounts, xrpl_selectedNetwork, xrpl_disconnect

On This Page

Select a documentation page to see its table of contents