Разработка мобильного приложения криптобиржи
Мобильное приложение биржи — это не адаптированная веб-версия. Это отдельный продукт с другим UX, другими требованиями к безопасности и другими техническими ограничениями. Пользователь с телефона торгует иначе: быстрые действия, меньше экрана, биометрия вместо пароля.
Выбор технологии
React Native vs Flutter vs Native
React Native (Meta) — наш основной выбор для бирж, где уже есть веб-фронтенд на React. Переиспользование бизнес-логики, единая команда. Expo — для быстрого старта. Bare React Native — для production с кастомными нативными модулями.
Flutter (Google) — лучший выбор при нуле существующего JS кода. Dart, Skia-рендеринг (выглядит одинаково на iOS и Android), хорошая производительность. Минус: меньше крипто-специфичных библиотек.
Native (Swift/Kotlin) — максимальная производительность и доступ к API, но две отдельные кодовые базы. Оправдано только при очень высоких требованиях к производительности (HFT-уровень).
Для большинства бирж: React Native + Expo для старта, миграция на bare workflow при необходимости кастомных нативных модулей (secure enclave, биометрия, push notifications).
Архитектура приложения
State management
Сложность стейта биржевого приложения высокая: реалтайм тикеры, order book, торговая история, балансы, активные ордера. Всё это обновляется через WebSocket.
// Zustand для локального стейта + React Query для серверного
import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
interface MarketStore {
tickers: Record<string, Ticker>;
orderBook: OrderBook | null;
lastPrice: Record<string, string>;
updateTicker: (pair: string, ticker: Ticker) => void;
updateOrderBook: (book: OrderBook) => void;
}
const useMarketStore = create<MarketStore>()(
subscribeWithSelector((set) => ({
tickers: {},
orderBook: null,
lastPrice: {},
updateTicker: (pair, ticker) =>
set((state) => ({ tickers: { ...state.tickers, [pair]: ticker } })),
updateOrderBook: (book) => set({ orderBook: book }),
}))
);
WebSocket менеджер переподключается автоматически при разрыве, дедуплицирует подписки, восстанавливает состояние:
class WSManager {
private ws: WebSocket | null = null;
private subscriptions = new Set<string>();
private reconnectTimer: NodeJS.Timeout | null = null;
connect(url: string) {
this.ws = new WebSocket(url);
this.ws.onopen = () => {
// Восстанавливаем все подписки после переподключения
this.subscriptions.forEach(sub => this.ws!.send(sub));
};
this.ws.onclose = () => {
this.reconnectTimer = setTimeout(() => this.connect(url), 3000);
};
this.ws.onmessage = (e) => this.handleMessage(JSON.parse(e.data));
}
}
Навигация
React Navigation v6 — стандарт для React Native. Структура для биржи:
Root Navigator (Stack)
├── Auth Stack
│ ├── Login
│ ├── Register
│ └── 2FA Setup
└── Main Tabs
├── Home (Markets / Watchlist)
├── Trade
│ ├── Chart Screen
│ ├── Order Book
│ └── Place Order
├── Wallets
│ ├── Balance Overview
│ ├── Deposit
│ └── Withdraw
├── Orders (History + Active)
└── Profile
Deep linking для push notifications: exchange://trade/BTC-USDT открывает торговый экран напрямую.
Ключевые экраны и компоненты
Торговый экран
Самый сложный экран. Включает:
-
TradingView chart через
react-native-webviewс TradingView Lightweight Charts внутри — это стандарт в индустрии для мобильных бирж - Order book с real-time обновлениями — нужна оптимизация рендеринга
- Форма ордера с калькулятором, процентным вводом, валидацией
Оптимизация order book рендеринга:
// FlashList вместо FlatList — в 5-10x быстрее для длинных списков
import { FlashList } from "@shopify/flash-list";
const OrderBookRow = React.memo(({ price, size, total, side }: OrderBookRowProps) => {
// Фоновая полоса depth visualizer через абсолютное позиционирование
const depthWidth = `${(total / maxTotal) * 100}%`;
return (
<View style={styles.row}>
<View style={[styles.depthBar, { width: depthWidth,
backgroundColor: side === 'bid' ? '#0d2d1c' : '#2d0d0d' }]} />
<Text style={[styles.price, { color: side === 'bid' ? '#00b15e' : '#e84242' }]}>
{formatPrice(price)}
</Text>
<Text style={styles.size}>{formatSize(size)}</Text>
</View>
);
});
Экран депозита/вывода
QR-код для депозита через react-native-qrcode-svg. Сканирование QR при выводе — expo-camera или react-native-vision-camera (более производительный).
Добавление нового адреса вывода требует 2FA верификации прямо в приложении.
Безопасность
Biometrics и Secure Storage
Биометрическая аутентификация — обязательный элемент для биржи:
import * as LocalAuthentication from 'expo-local-authentication';
import * as SecureStore from 'expo-secure-store';
async function authenticateWithBiometrics(): Promise<boolean> {
const hasHardware = await LocalAuthentication.hasHardwareAsync();
const isEnrolled = await LocalAuthentication.isEnrolledAsync();
if (!hasHardware || !isEnrolled) {
return fallbackToPIN();
}
const result = await LocalAuthentication.authenticateAsync({
promptMessage: 'Подтвердите личность для выхода',
disableDeviceFallback: false,
cancelLabel: 'Отмена',
});
return result.success;
}
// JWT токен хранится в SecureStore (iOS Keychain / Android Keystore)
async function saveToken(token: string) {
await SecureStore.setItemAsync('auth_token', token, {
keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
});
}
SecureStore использует iOS Keychain и Android Keystore — аппаратное шифрование. Никогда не хранить токены в AsyncStorage — он не зашифрован.
Certificate Pinning
Предотвращает MITM-атаки. Для React Native через react-native-ssl-pinning:
fetch('https://api.exchange.com/v1/orders', {
sslPinning: {
certs: ['sha256/AAAA...'], // SHA-256 fingerprint сертификата
},
});
При ротации сертификата нужно обновить приложение — поэтому лучше пинить промежуточный CA, а не leaf certificate.
Jailbreak/Root Detection
Скомпрометированное устройство — повышенный риск. Базовая проверка:
import JailMonkey from 'jail-monkey';
if (JailMonkey.isJailBroken()) {
Alert.alert(
'Предупреждение безопасности',
'Устройство модифицировано. Рекомендуем использовать приложение только на стандартных устройствах.',
);
}
Решение: предупреждать, но не блокировать полностью — иначе легитимные пользователи-разработчики будут заблокированы.
Push Notifications
Firebase Cloud Messaging (FCM) — стандарт для Android. APNs — для iOS. Expo Notifications абстрагирует оба.
Типы уведомлений для биржи:
- Ордер исполнен / частично исполнен
- Цена достигла watchlist алерта
- Вывод подтверждён
- Новый вход с устройства
- Подозрительная активность
// Регистрация и получение push token
const { status } = await Notifications.requestPermissionsAsync();
if (status === 'granted') {
const token = await Notifications.getExpoPushTokenAsync({
projectId: Constants.expoConfig.extra.eas.projectId,
});
await api.registerPushToken(token.data);
}
Серверная часть: при каждом событии (fill, withdrawal) — enqueue в очередь (Redis + Bull), worker отправляет через FCM/APNs API.
Performance оптимизации
Hermes engine — включён по умолчанию в React Native 0.70+. Быстрый старт, меньше памяти.
Реимейджинг изображений: иконки монет — expo-image с кэшированием вместо стандартного <Image>. Lazy loading для длинных списков.
Worklets через Reanimated: анимации цены (flash зелёным/красным при обновлении) — на UI thread через react-native-reanimated, без блокировки JS thread:
const priceColor = useDerivedValue(() => {
return withTiming(
priceChange.value > 0 ? '#00b15e' : '#e84242',
{ duration: 300 }
);
});
Bundle splitting: Expo Router поддерживает lazy loading экранов. Торговый экран загружается только при открытии вкладки Trade.
Сборка и дистрибуция
EAS Build (Expo Application Services) — облачная сборка без настройки локальных Xcode/Android Studio:
# iOS production build
eas build --platform ios --profile production
# Android AAB для Google Play
eas build --platform android --profile production
OTA Updates (Expo Updates) — обновление JS bundle без релиза в сторах. Исправление багов — за минуты. Новые фичи — всё равно через стор-ревью.
CI/CD: GitHub Actions → EAS Build → TestFlight (iOS) / Internal Testing (Android) → Production.
| Аспект | Технология | Примечание |
|---|---|---|
| Framework | React Native + Expo | Bare workflow для кастомных модулей |
| Charts | TradingView Lightweight Charts via WebView | Industry standard |
| State | Zustand + React Query | Простота + server state |
| Auth storage | expo-secure-store | Keychain/Keystore |
| Push | Expo Notifications + FCM/APNs | Кроссплатформенно |
| Build | EAS Build | Облачная CI/CD |
Сроки разработки
- MVP (Markets, Trade, Wallet): 10–14 недель
- Полный feature set с биометрией, пуш-нотификациями, алертами, KYC: 5–7 месяцев
- Подача в App Store + Google Play: +2–3 недели на ревью и устранение замечаний







