Перейти к содержимому

21. Native Modules

Native Modules позволяют вызывать нативный код (Swift/Kotlin) из JavaScript. Когда Expo SDK не покрывает нужную функциональность.

  • Интеграция с нативными SDK (Bluetooth, NFC)
  • Кастомные нативные UI компоненты
  • Высокопроизводительные операции (ML, обработка видео)
  • Уникальные платформенные API

Современный способ через 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');
Окно терминала
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)
}
}
}
}
// JavaScript
import { 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
# Bluetooth
npm install react-native-ble-plx
# NFC
npm install react-native-nfc-manager
# Calendar
npx expo install expo-calendar
# Contacts
npx expo install expo-contacts
# Battery
npx expo install expo-battery
# Barcode Scanner
npx expo install expo-barcode-scanner

Автонастройка нативного проекта:

{
"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>
);
}