Реализация встроенного DApp-браузера в мобильном криптокошельке

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Реализация встроенного DApp-браузера в мобильном криптокошельке
Сложная
от 1 недели до 3 месяцев
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1054
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

Реализация встроенного DApp-браузера в мобильном криптокошельке

Встроенный DApp-браузер — один из сложнейших компонентов криптокошелька. Он должен загружать произвольные веб-приложения, инжектировать провайдер window.ethereum, обрабатывать подписи транзакций и при этом не стать вектором атаки на активы пользователя.

Архитектура: WebView + провайдер

Основа браузера — нативный WebView с инжекцией JavaScript-провайдера. На iOS это WKWebView, на Android — WebView с addJavascriptInterface. Метавселенная MetaMask, Trust Wallet и Coinbase Wallet реализуют это одинаковым паттерном.

Провайдер window.ethereum — это объект который DApp ожидает увидеть в браузере. Он должен реализовывать EIP-1193 интерфейс: метод request(method, params) для всех RPC-запросов.

Схема работы:

DApp (JS) → window.ethereum.request({method: 'eth_sendTransaction'})
  → постMessage в нативный слой
  → нативный код показывает пользователю диалог подтверждения
  → пользователь одобряет/отклоняет
  → ответ возвращается в JS через postMessage
  → Promise разрешается в DApp

Инжекция провайдера на iOS (WKWebView)

Скрипт провайдера инжектируем через WKUserScript с injectionTime: .atDocumentStart. Критично — именно atDocumentStart, иначе DApp может проверить window.ethereum до инжекции и решить что кошелька нет.

let providerScript = loadProviderJS() // Читаем из бандла
let userScript = WKUserScript(
    source: providerScript,
    injectionTime: .atDocumentStart,
    forMainFrameOnly: false
)
webView.configuration.userContentController.addUserScript(userScript)
webView.configuration.userContentController.add(self, name: "ethereum")

JS-провайдер отправляет сообщения через webkit.messageHandlers.ethereum.postMessage({...}). Нативный код получает в userContentController(_:didReceive:).

Ответы передаём обратно через webView.evaluateJavaScript("window.ethereum._resolveResponse(\(id), \(result))").

Android: addJavascriptInterface

webView.addJavascriptInterface(EthereumProvider(this), "AndroidEthereum")
webView.settings.javaScriptEnabled = true

На Android JS-интерфейс работает синхронно, что создаёт проблему: методы @JavascriptInterface не могут возвращать Promise. Обходим через callback-паттерн: JS вызывает AndroidEthereum.request(id, method, paramsJson), нативный код в итоге вызывает webView.evaluateJavascript("resolveCallback($id, $result)", null).

Важно: addJavascriptInterface потенциально опасен. Методы аннотированные @JavascriptInterface видны для ВСЕГО JavaScript на странице, включая вредоносные iframe. Только аннотируйте методы которые необходимы. Никогда не добавляйте интерфейс с широким API.

Реализация window.ethereum провайдера

Минимальная реализация поддерживает методы EIP-1193:

// Инжектируемый провайдер (упрощённо)
window.ethereum = {
  isMetaMask: true, // многие DApp проверяют этот флаг
  chainId: '0x1',
  selectedAddress: null,

  request: async function({ method, params }) {
    return new Promise((resolve, reject) => {
      const id = generateId();
      pendingRequests[id] = { resolve, reject };
      webkit.messageHandlers.ethereum.postMessage({ id, method, params });
    });
  },

  on: function(event, handler) {
    // chainChanged, accountsChanged, connect, disconnect
    eventHandlers[event] = eventHandlers[event] || [];
    eventHandlers[event].push(handler);
  }
};

Методы которые нужно поддержать обязательно:

  • eth_requestAccounts — запрос доступа к адресу, показываем диалог
  • eth_accounts — список подключённых адресов
  • eth_chainId — текущая сеть
  • eth_sendTransaction — отправка транзакции, требует подтверждения
  • personal_sign — подписание сообщения
  • eth_signTypedData_v4 — подписание структурированных данных (EIP-712)
  • wallet_switchEthereumChain — запрос смены сети

Безопасность: это главное

Изоляция сессии. Каждая DApp должна иметь отдельный cookie-jar и localStorage. Не позволяйте DApp A читать данные DApp B. На iOS — отдельные WKWebViewConfiguration и WKWebsiteDataStore для каждой вкладки.

Проверка URL перед инжекцией. Не инжектируйте провайдер на произвольные страницы — только на HTTPS, только на DApp домены из вашего белого списка, или с явным подтверждением пользователя.

Диалог подтверждения транзакции. Пользователь должен видеть: адрес контракта, сумму ETH (если есть), данные транзакции в читаемом виде (декодированные через ABI), оценку газа и итоговую стоимость в фиате. Не показывайте сырой hex.

eth_signTypedData_v4 (EIP-712). Это структурированные данные — DApp просит подписать типизированный объект. Нужно распарсить JSON schema и показать пользователю что именно подписывается в человекочитаемом виде. MetaMask делает это через парсинг types и message полей. Подписание вслепую — риск для пользователя.

Фишинг-защита. Проверяем SSL-сертификат, показываем URL в адресной строке которую пользователь не может скрыть, блокируем alert() и prompt() из JS (DApp не должна перехватывать нативные диалоги). На iOS обрабатываем webView(_:runJavaScriptAlertPanelWithMessage:) и заменяем нативным UIAlertController.

Multi-tab и история

Браузер с одной вкладкой — минимум. Реализуем:

  • Вкладки с изолированными данными
  • Историю просмотров (опционально, многие пользователи кошельков предпочитают конфиденциальность)
  • Закладки для часто используемых DApp
  • Список популярных DApp (curated) для onboarding

На iOS несколько WKWebView можно держать в памяти — они ленивые пока не видимы. На Android WebView тяжёлый, для экономии памяти уничтожаем WebView неактивной вкладки и восстанавливаем URL при возврате.

React Native и Flutter

В React Native используем react-native-webview с инжекцией через injectedJavaScriptBeforeContentLoaded и onMessage. Ограничение: injectedJavaScriptBeforeContentLoaded на Android инжектируется не синхронно — есть гонка условий. Решение: дублируем инжекцию через evaluateJavaScript в onLoadStart.

В Flutter — webview_flutter с addJavaScriptChannel и runJavaScript. Аналогичные ограничения на Android.

Производительность

WebView рендерит полноценный веб-контент — это ресурсоёмко. На устаревших Android-устройствах (WebView на базе Chromium 80) сложные DeFi DApp могут тормозить. Мониторим через WebViewClient.onPageStarted / onPageFinished, показываем прогресс-бар загрузки.

Предзагрузка WebView при старте приложения (создаём инстанс в фоне) сокращает cold-start время браузера с ~800ms до ~200ms.

Процесс разработки

  1. Базовый WebView с навигацией, адресной строкой, прогресс-баром
  2. Инжекция провайдера и поддержка eth_requestAccounts, eth_accounts, eth_chainId
  3. Диалог транзакции — отображение, подписание, отправка через RPC
  4. Расширенные методыpersonal_sign, eth_signTypedData_v4, wallet_switchEthereumChain
  5. Безопасность — изоляция, фишинг-защита, аудит
  6. Multi-tab и UX-полировка

Сроки: базовый браузер с eth_sendTransaction — 3-4 недели. Полноценный браузер с multi-tab, EIP-712 отображением, security-аудитом — 2-3 месяца.