Custom Flutter Plugin for Native iOS and Android Functionality

Creating a Flutter Plugin for Native Functionality You're integrating a proprietary partner SDK—a C++ library with native calls. There are no ready-made plugins on pub.dev, and wrapping via `ffi` isn't viable due to complex lifecycle management—for example, proper memory handling and synchronizat

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
Custom Flutter Plugin for Native iOS and Android Functionality
Complex
~5 days

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    898
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    784
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1219
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1081
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1004
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    600

Creating a Flutter Plugin for Native Functionality

You're integrating a proprietary partner SDK—a C++ library with native calls. There are no ready-made plugins on pub.dev, and wrapping via ffi isn't viable due to complex lifecycle management—for example, proper memory handling and synchronization with the Dart isolate. Sound familiar? Then we build a custom plugin using Platform Channels. Our mobile development team, with 5+ years of experience, handles such projects end-to-end: from API design to publishing on pub.dev and integration into your project. We have implemented over 30 custom plugins for clients in fintech, healthcare, and IoT. We cut integration costs by up to 40% by leveraging Pigeon and optimizing platform channels.

How to Choose the Right Platform Channel?

Choosing the correct channel is the foundation of a stable plugin. Let's compare three options:

Channel Purpose Typical Scenario
MethodChannel Call a method and get a result (request/response) Getting OS version, reading a file
EventChannel Stream events from native code to Dart Sensor data stream, subscribing to BLE notifications
BasicMessageChannel Bidirectional arbitrary data transfer with custom codec Exchanging complex structures not fitting StandardMessageCodec

A typical example: a plugin for BLE devices. Device scanning—EventChannel (continuous stream of found devices). Connection/disconnection—MethodChannel. Receiving characteristic notifications—again EventChannel.

Why Pigeon Is Better Than Manual Serialization?

StandardMessageCodec (default) supports primitives, List, Map. For custom objects, we serialize to Map<String, dynamic> on the Dart side and get HashMap on Kotlin / [String: Any] on Swift. But this is prone to key name typos. The alternative—Pigeon: a tool from the Flutter team that generates type-safe APIs from a .dart specification. Pigeon generates Kotlin/Swift code with typed classes, eliminating runtime errors from method name typos. Using Pigeon reduces development time by 30–40% and simplifies maintenance. According to official Flutter documentation, Pigeon is recommended for plugins with complex serialization. More details at Platform Channels.

Compare the two strategies:

Approach Type Safety Development Time Maintenance
Manual serialization No (runtime errors) Longer (tests needed) Harder (key agreement)
Pigeon Yes (compile-time) 30–40% faster Easier (autogeneration)

How We Develop the Plugin: Steps

  1. Requirements analysis: which native functions, permissions, lifecycle. We estimate scope: 1–2 methods for one platform, or 10+ with EventChannel for both.
  2. Dart API design: contract via Pigeon or manual MethodChannel/EventChannel. Determine data types.
  3. iOS (Swift) and Android (Kotlin) implementation: use FlutterPlugin, ActivityAware, MethodCallHandler. Handle all edge cases and errors.
  4. Testing: unit tests on Dart, integration tests on both platforms, testing on real devices.
  5. Integration into your project: connect via git dependency or publish on pub.dev.
  6. Documentation: README with API, examples, CHANGELOG.
Common Platform Channel Mistakes
  • Double call to result.success() on Android—IllegalStateException: Reply already submitted. We ensure every call completes exactly once.
  • EventSink leak on screen rotation on Android. Solution: nullify sink in onCancel() and check before every call.
  • Method name mismatch between Dart and native code. Pigeon eliminates this.

Plugin Structure

Created via flutter create --template=plugin my_plugin. Structure:

my_plugin/ lib/my_plugin.dart — Dart API android/src/.../MyPlugin.kt — Android implementation ios/Classes/MyPlugin.swift — iOS implementation example/ — example app for testing 

Dart side declares the contract:

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 Implementation: FlutterPlugin + ActivityAware

On Android, the plugin implements FlutterPlugin for lifecycle, MethodCallHandler for handling calls. If an Activity is needed (e.g., for permission requests), additionally 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 } } 

Critical point: result.success(), result.error(), and result.notImplemented() must be called exactly once. Calling result.success() twice crashes with IllegalStateException: Reply already submitted. We guarantee no such errors in our code.

iOS Implementation in 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 and Memory Leaks

When using EventChannel on Android, the native side receives an EventSink. A typical leak: holding EventSink in a field, Activity recreates on screen rotation, old EventSink is not validated—calling sink.success() after destruction throws an exception. Solution: nullify sink in onCancel() and check before every call.

Publishing and Versioning

For internal use, the plugin lives in a git repository and is connected via path or git dependency in pubspec.yaml. For pub.dev publication, run flutter pub publish with mandatory pubspec.yaml fields (homepage, repository) and a complete CHANGELOG.md.

What's Included in the Work

  • Dart API and native implementation for iOS and Android
  • Integration with your project (usage example)
  • API and build documentation
  • Publication on pub.dev or git repository access
  • Guarantee of stable platform channels and error handling

Timelines

Development timeline: simple (1–2 methods, one platform)—2–4 days. Full cross-platform plugin with EventChannel, permissions, and edge-case handling—2–4 weeks. Pricing is determined after analysis. Get a consultation: contact us for an assessment of your project. We have already implemented over 30 custom plugins for clients in fintech, healthcare, and IoT—join them. Order plugin development now.