Розробка мобільного додатку криптобіржи
Мобільний додаток біржи — це не адаптована веб-версія. Це окремий продукт з іншим UX, іншими вимогами до безпеки та іншими технічними обмеженнями. Користувач з телефону торгує інакше: швидкі дії, менше екрана, біометрія замість пароля.
Вибір технології
React Native проти Flutter проти 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).
Архітектура додатку
Управління станом
Складність стану біржевого додатка висока: реалтайм тикери, 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 з реалтайм оновленнями — потребує оптимізації рендеринга
- Форма ордера з калькулятором, процентним вводом, валідацією
Оптимізація рендеринга 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 верифікації прямо в додатку.
Безпека
Біометрія та безпечне сховище
Біометрична аутентифікація — обов'язковий елемент для біржі:
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 сертифікат.
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.
Оптимізації продуктивності
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 без релізу в сторах. Виправлення помилок — за хвилини. Нові функції — все одно через store-review.
CI/CD: GitHub Actions → EAS Build → TestFlight (iOS) / Internal Testing (Android) → Production.
| Аспект | Технологія | Примітка |
|---|---|---|
| Framework | React Native + Expo | Bare workflow для кастомних модулів |
| Charts | TradingView Lightweight Charts via WebView | Галузевий стандарт |
| 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 тижнів
- Повний набір функцій з біометрією, push-сповіщеннями, алертами, KYC: 5–7 місяців
- Подача в App Store + Google Play: +2–3 тижні на review та виправлення







