21. Native Modules
Native Modules позволяют вызывать нативный код (Swift/Kotlin) из JavaScript. Когда Expo SDK не покрывает нужную функциональность.
Когда нужны
Заголовок раздела «Когда нужны»- Интеграция с нативными SDK (Bluetooth, NFC)
- Кастомные нативные UI компоненты
- Высокопроизводительные операции (ML, обработка видео)
- Уникальные платформенные API
Turbo Modules (New Architecture)
Заголовок раздела «Turbo Modules (New Architecture)»Современный способ через JSI — прямой вызов без Bridge:
// Spec файл (TypeScript)import type { TurboModule } from 'react-native';import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule { readonly getDeviceInfo: () => Promise<{ model: string; os: string }>; readonly vibrate: (duration: number) => void;}
export default TurboModuleRegistry.getEnforcing<Spec>('DeviceInfoModule');Expo Modules API (рекомендуется)
Заголовок раздела «Expo Modules API (рекомендуется)»npx create-expo-module my-module// iOS (Swift)import ExpoModulesCore
public class MyModule: Module { public func definition() -> ModuleDefinition { Name("MyModule")
Function("greet") { (name: String) in return "Hello, \(name)!" }
AsyncFunction("heavyTask") { (data: String, promise: Promise) in DispatchQueue.global().async { let result = processData(data) promise.resolve(result) } } }}// JavaScriptimport { requireNativeModule } from 'expo-modules-core';
const MyModule = requireNativeModule('MyModule');const greeting = MyModule.greet('Яша');const result = await MyModule.heavyTask(data);Готовые библиотеки (сначала ищи здесь!)
Заголовок раздела «Готовые библиотеки (сначала ищи здесь!)»# Биометрия (Face ID / Touch ID)npx expo install expo-local-authentication
# Bluetoothnpm install react-native-ble-plx
# NFCnpm install react-native-nfc-manager
# Calendarnpx expo install expo-calendar
# Contactsnpx expo install expo-contacts
# Batterynpx expo install expo-battery
# Barcode Scannernpx expo install expo-barcode-scannerExpo Config Plugins
Заголовок раздела «Expo Config Plugins»Автонастройка нативного проекта:
{ "expo": { "plugins": [ ["expo-camera", { "cameraPermission": "Для сканирования QR" }], ["expo-location", { "locationAlwaysUsageDescription": "Трекинг маршрута" }], "expo-secure-store" ] }}Пример: биометрия
Заголовок раздела «Пример: биометрия»import * as LocalAuthentication from 'expo-local-authentication';
async function authenticateWithBiometrics() { const hasHardware = await LocalAuthentication.hasHardwareAsync(); const isEnrolled = await LocalAuthentication.isEnrolledAsync();
if (!hasHardware || !isEnrolled) { Alert.alert('Биометрия недоступна'); return; }
const result = await LocalAuthentication.authenticateAsync({ promptMessage: 'Войти с помощью Face ID', fallbackLabel: 'Ввести пароль', });
if (result.success) console.log('Аутентификация успешна');}- Turbo Modules (JSI) — современный подход без Bridge
- Expo Modules API — самый простой способ создать модуль
- Config Plugins — автонастройка ios/android при
expo prebuild - Сначала ищи готовую библиотеку — обычно она уже есть
// React Web-эквивалент React Native кода// Паттерн Native Module: кастомный JS-модуль (хук)import { useState, useCallback } from 'react';
// "Native Module" — инкапсулированная логикаfunction useDeviceInfo() { const getInfo = useCallback(() => ({ platform: navigator.platform, language: navigator.language, online: navigator.onLine, cores: navigator.hardwareConcurrency, userAgent: navigator.userAgent.slice(0, 50), }), []); return { getInfo };}
export default function App() { const { getInfo } = useDeviceInfo(); const [info, setInfo] = useState(null);
return ( <div style={{ padding: 24, fontFamily: 'system-ui' }}> <h3>Native Module Pattern</h3> <p>Кастомный хук — аналог Native Module</p> <button onClick={() => setInfo(getInfo())} style={{ padding: '10px 20px', fontSize: 16, cursor: 'pointer' }}> DeviceInfo.getInfo() </button> {info && ( <pre style={{ background: '#f0f0f0', padding: 12, borderRadius: 8, marginTop: 12 }}> {JSON.stringify(info, null, 2)} </pre> )} </div> );}