Create a Custom Flutter Plugin with Android Support (Full Integration Guide)

Flutter allows you to write cross-platform mobile apps using Dart, but sometimes you need to access native Android features—like camera, Bluetooth, or platform-specific APIs—that Flutter doesn’t support out of the box.

This is where Flutter plugins come in. A plugin is a Dart package that uses platform-specific code (like Java/Kotlin on Android) through platform channels to bridge communication between Flutter and native code.

In this guide, you’ll learn:

  • How to create a Flutter plugin
  • Write Android-specific logic in Java/Kotlin
  • Use MethodChannel for communication
  • Use the plugin in a Flutter app

🧰 Step 1: Create the Plugin Project

Run this command in terminal:

flutter create --template=plugin --platforms=android flutter_custom_plugin

Explanation:
This creates a new Flutter plugin project named flutter_custom_plugin. The plugin will include platform code for Android. You’ll see:

  • /lib/flutter_custom_plugin.dart – Dart interface
  • /android/src/main/java/... – Native Android code

📦 Step 2: Understand Project Structure

  • flutter_custom_plugin/lib/flutter_custom_plugin.dart: Contains plugin API exposed to Flutter apps.
  • flutter_custom_plugin/android/src/main/java/com/example/flutter_custom_plugin/FlutterCustomPlugin.java: Native Android implementation using Java (or Kotlin).
  • pubspec.yaml: Plugin metadata and supported platforms.

You can switch to Kotlin by adding --android-language kotlin to your create command.


📡 Step 3: Define MethodChannel in Dart

lib/flutter_custom_plugin.dart

import 'package:flutter/services.dart';

class FlutterCustomPlugin {
  static const MethodChannel _channel = MethodChannel('flutter_custom_plugin');

  static Future<String?> getPlatformVersion() async {
    final String? version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }
}

Explanation:
We define a static MethodChannel named 'flutter_custom_plugin'. The invokeMethod() call sends a message to the platform side and waits for a response. Here we’re requesting getPlatformVersion from the Android side.


📱 Step 4: Implement Android Platform Code

android/src/main/java/com/example/flutter_custom_plugin/FlutterCustomPlugin.java

package com.example.flutter_custom_plugin;

import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

public class FlutterCustomPlugin implements FlutterPlugin, MethodChannel.MethodCallHandler {
  private MethodChannel channel;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
    channel = new MethodChannel(binding.getBinaryMessenger(), "flutter_custom_plugin");
    channel.setMethodCallHandler(this);
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }
}

Explanation:
This Java class implements FlutterPlugin and MethodCallHandler. When getPlatformVersion is invoked from Dart, it returns the current Android OS version. If the method isn’t recognized, notImplemented() is called.


🧪 Step 5: Use the Plugin in a Flutter App

  1. Add the plugin to your pubspec.yaml:
dependencies:
  flutter_custom_plugin:
    path: ../flutter_custom_plugin
  1. Call it in your main app:
import 'package:flutter/material.dart';
import 'package:flutter_custom_plugin/flutter_custom_plugin.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: PluginHome(),
    );
  }
}

class PluginHome extends StatefulWidget {
  @override
  _PluginHomeState createState() => _PluginHomeState();
}

class _PluginHomeState extends State<PluginHome> {
  String _platformVersion = 'Unknown';

  @override
  void initState() {
    super.initState();
    getPlatformVersion();
  }

  Future<void> getPlatformVersion() async {
    final version = await FlutterCustomPlugin.getPlatformVersion();
    setState(() {
      _platformVersion = version ?? 'Failed to get version';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Flutter Plugin Example")),
      body: Center(child: Text('Running on: $_platformVersion')),
    );
  }
}

Explanation:
We call our plugin’s getPlatformVersion() function inside initState() and display the Android OS version using a Text widget.


🔄 Testing the Plugin

  • Run the example app using flutter run.
  • You should see the OS version returned from native Android code.
  • If using Kotlin, ensure your plugin class uses override fun in a similar structure.

🧠 Final Thoughts

Creating a custom Flutter plugin with Android support allows you to:

  • Extend Flutter apps with native functionality
  • Interact with Java/Kotlin APIs
  • Reuse platform-specific libraries in Dart apps

Key Concepts Recap:

  • Use MethodChannel to bridge Dart and native Android
  • Plugins let Flutter call Java/Kotlin functions
  • Platform plugins follow the structure defined by FlutterPlugin

Have you tried writing your own Flutter plugin yet?
Drop your ideas, doubts, or sample use cases in the comments—we’d love to help or feature your plugin!

Leave a Comment