Flutter is Google’s free and open-source toolkit for developing UI applications. Using a single codebase, it builds high-quality native interfaces for Android and iOS. Flutter works with existing code and is used by developers and organizations worldwide. This post will show you how to create a custom Flutter plugin.
At HashStudioz, we wanted to complement our existing SDK set with a Flutter SDK. For Android and iOS, we developed SDKs that store event details and persist user details. We wanted to develop a solution that leveraged our existing Android and iOS SDKs to create the Flutter SDK. The app is designed to run on Android or iOS devices.
After much brainstorming, we developed a custom Flutter plugin. Based on Flutter’s flexible system, the custom plugin follows a basic mechanism. Using this method, you can call APIs available in Kotlin or Java on Android or Swift or Objective-C on iOS.
Table of Contents
Creating a Custom Plugin Using Flutter
Getting Started
This example illustrates the process of invoking a platform-specific API to retrieve and display the current battery level in Flutter. It involves utilizing the Android BatteryManager API and the iOS device.batteryLevel API via a unified platform message named getBatteryLevel().
Step 1: Creating the Package
To initiate a plugin package:
- Use the –template=plugin flag with the Flutter create command.
- Use the –platforms= option followed by a comma-separated list to specify the platforms supported by the plugin (e.g., Android, iOS, web, Linux, macOS, and Windows).
- Use the –org option to specify your organization using reverse domain name notation, utilized in various package and bundle identifiers in the generated plugin code.
- Use the -a option to specify the language for Android or the -i option to specify the language for iOS.
Below is an example command to create a plugin package for Android and iOS platforms while using Java for Android and Objective-C for iOS:
flutter create –org com.hashstudioz –template=plugin –platforms=android,ios -a java -i objc batteryLevel
This command generates a plugin project in the batteryLevel folder with specialized content, including:
- lib/batteryLevel.dart: The Dart API for the plugin.
- android/src/main/java/com/hashstudioz/batteryLevel/BatteryLevelPlugin.java: The Android platform-specific implementation of the plugin API in Java.
- ios/Classes/BatteryLevelPlugin.m: The iOS-platform specific implementation of the plugin API in Objective-C.
- example/: A Flutter app that depends on the plugin and illustrates how to use it.

Step 2: Creating the Flutter Platform Client
The app’s State class holds the current app state. Extend it to hold the current battery state.
- Construct the channel using MethodChannel with a single platform method that returns the battery level.
- Ensure unique channel names by prefixing them with a unique domain prefix (e.g., org.hashstudioz.dev/battery).
In the batteryLevel.dart file located in the lib folder:
import 'dart:async';
import 'package:flutter/services.dart';
class BatteryLevel {
static const MethodChannel _channel = MethodChannel('org.hashstudioz.dev/battery');
// Get battery level.
static Future getBatteryLevel() async {
String batteryLevel;
try {
final int result = await _channel.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level: $result%.';
} on PlatformException {
batteryLevel = 'Failed to get battery level.';
}
return batteryLevel;
}
}
Replace the example/lib/main.dart file with a user interface that displays the battery state and a button for refreshing the value.
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:batteryLevel/batteryLevel.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _batteryLevel = 'Unknown';
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
batteryLevel = await BatteryLevel.getBatteryLevel();
} on PlatformException {
batteryLevel = 'Failed to get platform version.';
}
if (!mounted) return;
setState(() {
_batteryLevel = batteryLevel;
});
}
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
child: Text('Get Battery Level'),
onPressed: _getBatteryLevel,
),
Text(_batteryLevel),
],
),
),
);
}
}
Step 3: Adding Android Platform-Specific Implementation
Open BatteryLevelPlugin.java within android/src/main/java/com/hashstudioz/batteryLevel/ and make the changes as follows:
- Change the channel name in the initialization of MethodChannel object to org.hashstudioz.dev/battery.
- Replace onMethodCall to handle the getBatteryLevel call and respond with a predefined battery level.
Step 4: Adding iOS Platform-Specific Implementation
Open BatteryLevelPlugin.m under ios/Classes/ and make the following changes:
- Change the channel name in the initialization of FlutterMethodChannel object to org.hashstudioz.dev/battery.
- Replace the handleMethodCall method to handle the getBatteryLevel call and respond with a predefined battery level.
With these steps, you have successfully developed a custom plugin. Run the plugin across Android and iOS platforms to observe its functionality.
Publishing the Custom Plugin
Now, let’s briefly go over a set of guidelines to keep in mind after creating the custom plugin:
Once you’ve finished developing the custom plugin, you’ll want to make it available for other developers to use. You can do this by publishing the custom plugin on pub.dev. However, prior to publishing, carefully review the pubspec.yaml, README.md, CHANGELOG.md, and LICENSE files to confirm that the content is comprehensive and accurate.
Next, execute the publish command in dry-run mode to conduct a preliminary analysis:
$ flutter pub publish –dry-run
The subsequent step involves publishing on pub.dev. However, ensure that you’re fully prepared because publishing is a permanent action and cannot be undone:
$ flutter pub publish
Conclusion
This blog has guided you through creating a custom Flutter plugin to enhance your app’s functionality by tapping into platform-specific features. By following the provided steps, you’ve learned to integrate native APIs seamlessly.

Frequently Asked Questions
1. How do I initiate a Flutter plugin package for my project?
To start a Flutter plugin package, you can use the Flutter create command with the appropriate options like –template=plugin, –platforms=, –org, -a, and -i. These options help customize the plugin package according to your project’s needs.
2. How do I integrate platform-specific APIs using a Flutter plugin?
Integrating platform-specific APIs involves creating a MethodChannel and invoking platform-specific methods to interact with the native APIs, allowing seamless communication between Flutter and the respective platform.
3. How do I publish my custom Flutter plugin for others to use?
To publish your custom Flutter plugin, you need to review and update necessary files like pubspec.yaml, README.md, CHANGELOG.md, and LICENSE. After ensuring readiness, you can use the flutter pub publish command to make your plugin available on pub.dev.
4. What factors should I consider when choosing a Flutter app development company?
Key factors to consider when selecting a Flutter app development company include experience with Flutter, a strong portfolio showcasing diverse projects, expertise in UI/UX design, adherence to project timelines, transparent communication, and a client-centric approach.