Flutter-плагин с нативной функциональностью: iOS и Android

Создание Flutter-плагина для нативной функциональности Вы интегрируете проприетарный SDK партнёра — C++ библиотеку с нативными вызовами. Готовых плагинов на pub.dev нет, а обёртка через `ffi` не подходит из-за сложного lifecycle — например, необходимо правильно управлять памятью и синхронизацией

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

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

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Flutter-плагин с нативной функциональностью: iOS и Android
Сложный
~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

Создание Flutter-плагина для нативной функциональности

Вы интегрируете проприетарный SDK партнёра — C++ библиотеку с нативными вызовами. Готовых плагинов на pub.dev нет, а обёртка через ffi не подходит из-за сложного lifecycle — например, необходимо правильно управлять памятью и синхронизацией с Dart-изолятом. Знакомая ситуация? Тогда пишем собственный плагин через Platform Channels. Мы, команда мобильных разработчиков с 5+ летним стажем, берём такие задачи под ключ: от проектирования API до публикации на pub.dev и интеграции в ваш проект. У нас за плечами реализация более 30 кастомных плагинов для заказчиков из финтеха, медицины и IoT. Снижаем бюджет на интеграцию до 40% за счёт использования Pigeon и оптимизации платформенных каналов.

Как выбрать тип Platform Channel?

Определение правильного канала — основа стабильной работы плагина. Сравним три варианта:

Канал Назначение Типичный сценарий
MethodChannel Вызов метода и получение результата (request/response) Получение версии ОС, чтение файла
EventChannel Поток событий из нативного кода в Dart Стрим показаний сенсора, подписка на BLE-уведомления
BasicMessageChannel Двунаправленная передача произвольных данных с кастомным кодеком Обмен сложными структурами, не влезающими в StandardMessageCodec

Типичный пример: плагин для работы с BLE-устройством. Сканирование устройств — EventChannel (непрерывный поток найденных устройств). Подключение/отключение — MethodChannel. Получение уведомлений от характеристики — снова EventChannel.

Почему Pigeon лучше ручной сериализации?

StandardMessageCodec (дефолтный) поддерживает примитивы, List, Map. Для кастомных объектов — сериализуем в Map<String, dynamic> на Dart-стороне и получаем HashMap на Kotlin / [String: Any] на Swift. Но это чревато опечатками в именах ключей. Альтернатива — Pigeon: инструмент от Flutter team для генерации type-safe API по .dart-спецификации. Pigeon генерирует Kotlin/Swift код с типизированными классами — исключает runtime-ошибки от опечаток в именах методов. Применение Pigeon сокращает время разработки на 30–40% и упрощает поддержку. Согласно официальной документации Flutter, использование Pigeon рекомендовано для плагинов со сложной сериализацией. Подробнее см. Platform Channels.

Сравните две стратегии:

Подход Типобезопасность Время разработки Поддержка
Ручная сериализация Нет (runtime-ошибки) Больше (нужны тесты) Сложнее (согласование ключей)
Pigeon Да (compile-time) На 30–40% быстрее Проще (автогенерация)

Как мы разрабатываем плагин: этапы

  1. Анализ требований: какие нативные функции нужны, какие разрешения, lifecycle. Оцениваем объём: 1–2 метода под одну платформу или 10+ с EventChannel для обеих.
  2. Проектирование Dart API: контракт через Pigeon или ручные MethodChannel/EventChannel. Определяем типы данных.
  3. Реализация на iOS (Swift) и Android (Kotlin): используем FlutterPlugin, ActivityAware, MethodCallHandler. Обработка всех edge cases и ошибок.
  4. Тестирование: модульные тесты на Dart, интеграционные тесты на обеих платформах, тестирование на реальных устройствах.
  5. Интеграция в ваш проект: подключаем через git dependency или публикуем на pub.dev.
  6. Документация: README с API, примерами, CHANGELOG.
Типичные ошибки при работе с Platform Channels
  • Двойной вызов result.success() на Android — IllegalStateException: Reply already submitted. Гарантируем, что каждый вызов завершается ровно один раз.
  • Утечка EventSink при повороте экрана на Android. Решение: обнуляем sink в onCancel() и проверяем перед каждым вызовом.
  • Несовпадение имён методов между Dart и нативным кодом. Pigeon исключает эту проблему.

Структура плагина

Создаём через flutter create --template=plugin my_plugin. Структура:

my_plugin/ lib/my_plugin.dart — Dart API android/src/.../MyPlugin.kt — Android реализация ios/Classes/MyPlugin.swift — iOS реализация example/ — пример приложения для тестирования 

Dart-сторона объявляет контракт:

class MyPlugin { static const MethodChannel _channel = MethodChannel('my_plugin'); static Future<String?> getPlatformVersion() async { return await _channel.invokeMethod<String>('getPlatformVersion'); } static Stream<ScanResult> get scanResults { return const EventChannel('my_plugin/scan_results') .receiveBroadcastStream() .map((data) => ScanResult.fromMap(Map<String, dynamic>.from(data))); } } 

Android-реализация: FlutterPlugin + ActivityAware

На Android плагин реализует FlutterPlugin для lifecycle, MethodCallHandler для обработки вызовов. Если нужен Activity (например для permission request), дополнительно ActivityAware:

class MyPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { private lateinit var channel: MethodChannel private var activity: Activity? = null override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { channel = MethodChannel(binding.binaryMessenger, "my_plugin") channel.setMethodCallHandler(this) } override fun onMethodCall(call: MethodCall, result: Result) { when (call.method) { "getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}") else -> result.notImplemented() } } override fun onAttachedToActivity(binding: ActivityPluginBinding) { activity = binding.activity } } 

Критичная деталь: result.success(), result.error() и result.notImplemented() должны вызываться ровно один раз. Вызов result.success() дважды — краш IllegalStateException: Reply already submitted. Мы гарантируем отсутствие таких ошибок в нашем коде.

iOS-реализация на Swift

public class MyPlugin: NSObject, FlutterPlugin { public static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel( name: "my_plugin", binaryMessenger: registrar.messenger() ) let instance = MyPlugin() registrar.addMethodCallDelegate(instance, channel: channel) } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "getPlatformVersion": result("iOS " + UIDevice.current.systemVersion) default: result(FlutterMethodNotImplemented) } } } 

EventChannel и memory leaks

При использовании EventChannel на Android нативный сайд получает EventSink. Типичная утечка: держим EventSink в поле класса, Activity пересоздаётся при повороте экрана, старый EventSink не валидируется — и вызов sink.success() после уничтожения бросает исключение. Решение: обнулять sink в onCancel() и проверять перед каждым вызовом.

Публикация и версионирование

Для внутреннего использования плагин живёт в git-репозитории и подключается через path или git dependency в pubspec.yaml. Для публикации на pub.dev — flutter pub publish с обязательным pubspec.yaml с homepage, repository, полным CHANGELOG.md.

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

  • Разработка Dart API и нативной реализации для iOS и Android
  • Интеграция с вашим проектом (пример использования)
  • Документация по API и сборке
  • Публикация на pub.dev или предоставление доступа к git-репозиторию
  • Гарантия стабильности платформенных каналов и обработка ошибок

Разработка плагина: простой (1–2 метода, одна платформа) — 2–4 дня. Полноценный cross-platform плагин с EventChannel, permissions и edge-case handling — 2–4 недели. Стоимость рассчитывается индивидуально. Получите консультацию: свяжитесь с нами для оценки вашего проекта. Мы уже реализовали более 30 кастомных плагинов для заказчиков из финтеха, медицины и IoT — присоединяйтесь. Закажите разработку плагина прямо сейчас.