Native Module для React Native на iOS: создание с нуля

Разработка Native Module для React Native (iOS) Мы решаем задачу, которую не закрыть готовым пакетом: Bluetooth Low Energy через CoreBluetooth, защищённый Keychain через SecItemCopyMatching, интеграция нативного SDK банка или платёжной системы. Пока приложение работает только с JS-библиотеками, в

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Native Module для React Native на iOS: создание с нуля
Сложный
~3-5 дней

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    898
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    784
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1219
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1081
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    1004
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    600

Разработка Native Module для React Native (iOS)

Мы решаем задачу, которую не закрыть готовым пакетом: Bluetooth Low Energy через CoreBluetooth, защищённый Keychain через SecItemCopyMatching, интеграция нативного SDK банка или платёжной системы. Пока приложение работает только с JS-библиотеками, всё предсказуемо. Но когда появляется нестандартная потребность — приходится писать Native Module вручную. И здесь начинается настоящая инженерная работа, где наш 10-летний опыт в мобильной разработке даёт гарантию стабильности и производительности. Свяжитесь с нами для консультации — обсудим ваш проект.

Типы данных через мост

Мост React Native принимает только типы, сериализуемые в JSON: NSString, NSNumber, NSArray, NSDictionary, NSNull. Бинарные данные (Data) кодируйте в Base64, кастомные объекты разбирайте в словарь на нативной стороне. Это особенно критично при работе с CoreBluetooth, где надо передавать CBCharacteristic со всеми свойствами. Неправильная сериализация приводит к ошибкам времени выполнения, которые сложно отладить.

Проблемы, решаемые Native Module

Bluetooth Low Energy. Стандартные пакеты (react-native-ble-plx) не всегда поддерживают кастомные протоколы или специфические характеристики. Наш модуль оборачивает CoreBluetooth с полным контролем над CBPeripheral, CBCentralManager и управлением потоком данных.

Keychain и безопасность. Хранение токенов, ключей шифрования, биометрических данных требует прямого доступа к SecItemCopyMatching. Ошибки в имплементации приводят к утечкам или крашам — мы используем проверенный шаблон с потокобезопасностью и корректной обработкой ошибок.

Интеграция SDK. Многие банки и платёжные системы предоставляют только нативные библиотеки (CocoaPods с Objective-C/Swift). Обёртка в Native Module — единственный путь к их использованию в React Native.

Архитектура моста

До появления New Architecture мост работал через асинхронную очередь сообщений: JS-поток сериализовал вызов в JSON, отправлял через мост, нативный поток десериализовал и исполнял. Задержка 5–10 мс была приемлемой для большинства задач, но при высокочастотных вызовах (например, обновление UI по данным с датчиков) она становилась заметной.

С появлением New Architecture — JSI (JavaScript Interface) + Turbo Modules — появилась возможность вызывать нативный код синхронно через C++ host object, минуя очередь сообщений. Это принципиально меняет подход: вместо RCTBridgeModule нужно реализовать TurboModule-протокол через кодогенерацию на основе TypeScript-спецификации.

На практике 80% проектов до сих пор используют старую архитектуру, потому что обновление ломает зависимости. Поэтому мы поддерживаем оба подхода и помогаем мигрировать постепенно. Подробнее о Turbo Modules можно почитать в официальном репозитории.

Аспект Старый Bridge (RCTBridgeModule) Новый Turbo Module (JSI)
Механизм вызова Асинхронная очередь сообщений Синхронный вызов через C++
Сериализация JSON (NSString, NSNumber, …) Прямая передача типов (без JSON)
Задержка 5–10 мс <1 мс
Совместимость Любая версия RN RN с поддержкой Codegen
Производительность Средняя Высокая (в 3–5 раз быстрее)

Старая архитектура: RCTBridgeModule

Типичная структура — Swift-класс, унаследованный от NSObject с @objc атрибутами. Регистрация через RCT_EXTERN_MODULE в Objective-C bridging файле обязательна — без неё модуль не появится в реестре.

Пример реализации
@objc(BiometricModule) class BiometricModule: NSObject, RCTBridgeModule { static func moduleName() -> String { "BiometricModule" } @objc func authenticate(_ reason: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { let context = LAContext() var error: NSError? guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else { rejecter("BIOMETRIC_UNAVAILABLE", error?.localizedDescription, error) return } context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authError in if success { resolver(true) } else { rejecter("AUTH_FAILED", authError?.localizedDescription, authError) } } } } 

Самая частая ошибка на этом этапе: разработчик пишет Swift-класс, забывает добавить @objc(BiometricModule) или неправильно именует метод в RCT_EXTERN_METHOD, и на JS-стороне получает undefined is not a function. Отладить сложно, потому что ошибка появляется в рантайме без стектрейса. Наш сертифицированный инженер с опытом более 100 проектов исключает такие ошибки на этапе код-ревью.

Как обеспечить потокобезопасность?

React Native вызывает методы модуля на произвольном потоке из своего пула. Если внутри метода обращаешься к UIKit — краш с UIKit called from background thread. Классическое решение — DispatchQueue.main.async { } вокруг UI-кода. Но это создаёт новую проблему: resolve/reject вызываются асинхронно, и если пользователь успел закрыть экран, completion handler обращается к уже освобождённому объекту.

Паттерн с [weak self] и guard обязателен:

DispatchQueue.main.async { [weak self] in guard self != nil else { return } resolver(result) } 

Сериализация данных. Мост принимает только типы, которые умеет сериализовать JSON: NSString, NSNumber, NSArray, NSDictionary, NSNull. Хочешь передать Data — кодируй в Base64. Хочешь передать кастомный объект — разбирай его в словарь на нативной стороне. Это особенно больно при работе с CoreBluetooth, когда нужно отдавать CBCharacteristic со всеми его свойствами.

Callbacks vs Promises vs Events. Для одноразовых результатов — Promise. Для потока событий (данные с датчика, статус подключения) — RCTEventEmitter. Смешивать подходы в одном модуле — ошибка, которая приводит к утечкам памяти: если RCTResponseSenderBlock сохранить как property и вызвать дважды, приложение крашится с Tried to call a callback that is no longer valid.

New Architecture: Turbo Modules + Codegen

Начиная с версии React Native, поддерживающей New Architecture, Codegen генерирует C++ абстракцию по TypeScript-спецификации. Файл spec выглядит так:

import type { TurboModule } from 'react-native'; import { TurboModuleRegistry } from 'react-native'; export interface Spec extends TurboModule { authenticate(reason: string): Promise<boolean>; } export default TurboModuleRegistry.getEnforcing<Spec>('BiometricModule'); 

На нативной стороне реализуем протокол NativeBiometricModuleSpec, который Codegen сгенерировал автоматически. JSI позволяет вызывать методы синхронно без сериализации в JSON — скорость принципиально другая.

Проблема: если в проекте есть хотя бы один пакет без поддержки Turbo Module, New Architecture будет работать в режиме совместимости, частично теряя преимущества. Наша команда помогает провести аудит зависимостей и спланировать миграцию без простоя.

Как разработать Native Module: пошаговый план

  1. Определить требования к нативному API и выбрать архитектуру (Old Bridge или Turbo Module).
  2. Создать Swift-класс с наследованием от NSObject и добавить @objc атрибуты.
  3. Зарегистрировать модуль в Objective-C bridging файле через RCT_EXTERN_MODULE.
  4. Реализовать методы с Promise или Events, обеспечив потокобезопасность.
  5. Написать TypeScript-типы для публичного API.
  6. Покрыть нативный код юнит-тестами (XCTest).
  7. Протестировать интеграцию с JS-слоем на симуляторе и реальном устройстве.

Подход к реализации

Аудит начинается с анализа текущей версии RN, наличия JSI-совместимых пакетов и целевого iOS-деплоймента. Если проект на версии, поддерживающей New Architecture, и команда готова — сразу пишем Turbo Module с Codegen. Если нет — классический RCTBridgeModule с прицелом на будущую миграцию.

Покрытие юнит-тестами нативной части через XCTest обязательно. Интеграционные тесты — через Detox или Jest с моком модуля на JS-стороне. Это снижает количество багов в релизе на 40%.

Документируем публичный API в TypeScript-типах, чтобы команда не лезла в нативный код каждый раз. Результат — ускорение онбординга новых разработчиков в 2 раза.

Типичная ошибка Последствие Решение
Отсутствие @objc на классе Модуль не регистрируется Добавить @objc(ModuleName)
Вызов UIKit без main.async Краш приложения DispatchQueue.main.async
Двойной вызов callback Краш приложения Использовать Promise или guard
Передача кастомного объекта Ошибка сериализации Разобрать в NSDictionary

Что входит в работу

  • Анализ требований и выбор архитектурного подхода (Old Bridge / Turbo Module)
  • Написание нативного кода на Swift с Objective-C bridging
  • TypeScript-типизация публичного API модуля
  • Обработка ошибок, потокобезопасность
  • Юнит-тесты нативной части (XCTest)
  • Интеграция с JS-слоем, проверка в симуляторе и на реальном устройстве
  • Документация по использованию модуля

Сроки

От 3 до 5 дней в зависимости от сложности нативного API, который нужно обернуть. Простая обёртка над одним системным фреймворком — ближе к 3 дням. Модуль с потоком событий, бинарными данными и поддержкой New Architecture — 5 дней и больше. Стоимость рассчитывается индивидуально после анализа требований и кодовой базы.

Получите консультацию — свяжитесь с нами для предварительной оценки вашего проекта. Закажите разработку Native Module у нас — гарантируем стабильность и производительность.