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

Интеграция проприетарного SDK в Flutter-приложение часто упирается в отсутствие готовых плагинов и сложности с нативным кодом. Мы разрабатываем кастомные Flutter-плагины, используя Platform Channel, MethodChannel, EventChannel и Pigeon для надёжной связи с iOS и Android. Наша команда реализует проект под ключ — от проектирования API до публикации и последующей поддержки.

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

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

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

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

Создание 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 — присоединяйтесь. Закажите разработку плагина прямо сейчас.

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

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

  • Разработка мобильного приложения для компании FEEDME
    Разработка мобильного приложения для компании FEEDME
    1009
  • Разработка мобильного приложения для компании XOOMER
    Разработка мобильного приложения для компании XOOMER
    902
  • Разработка мобильного приложения для компании RHL
    Разработка мобильного приложения для компании RHL
    1331
  • Разработка мобильного приложения для компании ZIPPY
    Разработка мобильного приложения для компании ZIPPY
    1179
  • Разработка мобильного приложения для компании Affhome
    Разработка мобильного приложения для компании Affhome
    1106
  • Разработка мобильного приложения для компании FLAVORS
    Разработка мобильного приложения для компании FLAVORS
    713